diff options
author | YimingWu <xp8110@outlook.com> | 2019-10-24 15:36:28 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2019-10-24 15:36:28 +0300 |
commit | e910924b37a3fdffeb38ac14c656c16f107a9c0d (patch) | |
tree | ab626478bbb650837fd54140cfbb30a04edb6a26 /source/blender | |
parent | f60406ff257c3309418413b5af76373010fb2a6f (diff) | |
parent | 42eef8f81a6aea27094985347ab802dc6bb91a61 (diff) |
Merge remote-tracking branch 'origin/master' into soc-2019-npr
Diffstat (limited to 'source/blender')
700 files changed, 20656 insertions, 10918 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index 696e0ff1810..7c5efaf309d 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -27,6 +27,7 @@ extern "C" { struct CacheReader; struct ListBase; +struct Main; struct Mesh; struct Object; struct Scene; @@ -103,7 +104,9 @@ bool ABC_import(struct bContext *C, bool validate_meshes, bool as_background_job); -AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths); +AbcArchiveHandle *ABC_create_handle(struct Main *bmain, + const char *filename, + struct ListBase *object_paths); void ABC_free_handle(AbcArchiveHandle *handle); diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc index c4252d20d48..bb527c23b20 100644 --- a/source/blender/alembic/intern/abc_archive.cc +++ b/source/blender/alembic/intern/abc_archive.cc @@ -24,6 +24,10 @@ #include "abc_archive.h" extern "C" { #include "BKE_blender_version.h" +#include "BKE_main.h" + +#include "BLI_path_util.h" +#include "BLI_string.h" } #ifdef WIN32 @@ -95,20 +99,24 @@ static IArchive open_archive(const std::string &filename, return IArchive(); } -ArchiveReader::ArchiveReader(const char *filename) +ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) { + char abs_filename[FILE_MAX]; + BLI_strncpy(abs_filename, filename, FILE_MAX); + BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain)); + #ifdef WIN32 - UTF16_ENCODE(filename); - std::wstring wstr(filename_16); + UTF16_ENCODE(abs_filename); + std::wstring wstr(abs_filename_16); m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); - UTF16_UN_ENCODE(filename); + UTF16_UN_ENCODE(abs_filename); #else - m_infile.open(filename, std::ios::in | std::ios::binary); + m_infile.open(abs_filename, std::ios::in | std::ios::binary); #endif m_streams.push_back(&m_infile); - m_archive = open_archive(filename, m_streams, m_is_hdf5); + m_archive = open_archive(abs_filename, m_streams, m_is_hdf5); /* We can't open an HDF5 file from a stream, so close it. */ if (m_is_hdf5) { diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h index 343a8112aa2..a64de742cdf 100644 --- a/source/blender/alembic/intern/abc_archive.h +++ b/source/blender/alembic/intern/abc_archive.h @@ -34,6 +34,8 @@ #include <fstream> +struct Main; + /* Wrappers around input and output archives. The goal is to be able to use * streams so that unicode paths work on Windows (T49112), and to make sure that * the stream objects remain valid as long as the archives are open. @@ -46,7 +48,7 @@ class ArchiveReader { bool m_is_hdf5; public: - explicit ArchiveReader(const char *filename); + ArchiveReader(struct Main *bmain, const char *filename); bool valid() const; diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index a7549cc1f47..a69178281ff 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -53,6 +53,7 @@ extern "C" { #include "BKE_anim.h" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_modifier.h" @@ -263,7 +264,7 @@ void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &fram } } -void AbcExporter::operator()(float &progress, bool &was_canceled) +void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled) { std::string scene_name; @@ -332,10 +333,11 @@ void AbcExporter::operator()(float &progress, bool &was_canceled) size_t i = 0; for (; begin != end; ++begin) { - progress = (++i / size); + *progress = (++i / size); + *do_update = 1; if (G.is_break) { - was_canceled = true; + *was_canceled = true; break; } diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index e6a7a3fc7f4..a73289fcf95 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -104,7 +104,7 @@ class AbcExporter { AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); ~AbcExporter(); - void operator()(float &progress, bool &was_canceled); + void operator()(short *do_update, float *progress, bool *was_canceled); protected: void getShutterSamples(unsigned int nr_of_samples, diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc index 38042bc7286..98387be2e61 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_hair.cc @@ -79,10 +79,14 @@ void AbcHairWriter::do_write() if (m_psys->pathcache) { ParticleSettings *part = m_psys->part; + bool export_children = m_settings.export_child_hairs && m_psys->childcache && + part->childtype != 0; - write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); + if (!export_children || part->draw & PART_DRAW_PARENT) { + write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); + } - if (m_settings.export_child_hairs && m_psys->childcache) { + if (export_children) { write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); } } diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 5de21075a23..651f32e6ab0 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -561,7 +561,7 @@ Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL); - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); if (r_needsfree) { @@ -885,7 +885,8 @@ static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data if (!mesh_data.loop_normals) { BKE_mesh_calc_normals(config.mesh); - config.mesh->flag &= ~ME_AUTOSMOOTH; + /* Don't touch the ME_AUTOSMOOTH flag in this case. It can be used by artists to toggle between + * flat/smooth shaded when the Alembic mesh doesn't contain loop normals. */ return; } @@ -1018,7 +1019,10 @@ static void read_mesh_sample(const std::string &iobject_full_name, abc_mesh_data.face_counts = sample.getFaceCounts(); abc_mesh_data.face_indices = sample.getFaceIndices(); abc_mesh_data.positions = sample.getPositions(); - abc_mesh_data.poly_flag_smooth = false; + + /* The auto-smoothing flag can be used by artists when the Alembic file does not contain custom + * loop normals. Auto-smoothing only works when polys are marked as smooth. */ + abc_mesh_data.poly_flag_smooth = (config.mesh->flag & ME_AUTOSMOOTH); read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); @@ -1192,8 +1196,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); settings.read_flag |= MOD_MESHSEQ_READ_ALL; - /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */ - new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH); } else { /* If the face count changed (e.g. by triangulation), only read points. @@ -1416,11 +1418,24 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); - MEdge *edges = mesh->medge; - if (indices && sharpnesses) { + MEdge *edges = mesh->medge; + int totedge = mesh->totedge; + for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) { - MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]); + int v1 = (*indices)[i]; + int v2 = (*indices)[i + 1]; + + if (v2 < v1) { + /* It appears to be common to store edges with the smallest index first, in which case this + * prevents us from doing the second search below. */ + std::swap(v1, v2); + } + + MEdge *edge = find_edge(edges, totedge, v1, v2); + if (edge == NULL) { + edge = find_edge(edges, totedge, v2, v1); + } if (edge) { edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 9ace0a8faa9..1034c5b319f 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -173,9 +173,11 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) return parent_is_part_of_this_object; } -AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths) +AbcArchiveHandle *ABC_create_handle(struct Main *bmain, + const char *filename, + ListBase *object_paths) { - ArchiveReader *archive = new ArchiveReader(filename); + ArchiveReader *archive = new ArchiveReader(bmain, filename); if (!archive->valid()) { delete archive; @@ -222,6 +224,7 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string struct ExportJobData { ViewLayer *view_layer; Main *bmain; + wmWindowManager *wm; char filename[1024]; ExportSettings settings; @@ -246,8 +249,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo * scene frame in separate threads */ G.is_rendering = true; - BKE_spacedata_draw_locks(true); - + WM_set_locked_interface(data->wm, true); G.is_break = false; DEG_graph_build_from_view_layer( @@ -261,7 +263,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo const int orig_frame = CFRA; data->was_canceled = false; - exporter(*data->progress, data->was_canceled); + exporter(do_update, progress, &data->was_canceled); if (CFRA != orig_frame) { CFRA = orig_frame; @@ -296,7 +298,7 @@ static void export_endjob(void *customdata) } G.is_rendering = false; - BKE_spacedata_draw_locks(false); + WM_set_locked_interface(data->wm, false); } bool ABC_export(Scene *scene, @@ -310,6 +312,7 @@ bool ABC_export(Scene *scene, job->view_layer = CTX_data_view_layer(C); job->bmain = CTX_data_main(C); + job->wm = CTX_wm_manager(C); job->export_ok = false; BLI_strncpy(job->filename, filepath, 1024); @@ -649,7 +652,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa WM_set_locked_interface(data->wm, true); - ArchiveReader *archive = new ArchiveReader(data->filename); + ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename); if (!archive->valid()) { #ifndef WITH_ALEMBIC_HDF5 diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 0294a6219b9..45086de0f61 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -80,9 +80,8 @@ typedef struct GlyphCacheBLF { /* and the last texture, aka. the current texture. */ unsigned int texture_current; - /* like bftgl, we draw every glyph in a big texture, so this is the - * current position inside the texture. - */ + /* We draw every glyph in a big texture, so this is the + * current position inside the texture. */ int offset_x; int offset_y; diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 868c5a69593..b7139d5bbf6 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -212,8 +212,8 @@ void what_does_obaction(struct Object *ob, float cframe); /* for proxy */ -void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, - const struct bPoseChannel *pchanfrom); +void BKE_pose_copy_pchan_result(struct bPoseChannel *pchanto, + const struct bPoseChannel *pchanfrom); bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index a2a14011595..4e4528ff92b 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -25,7 +25,6 @@ */ struct AnimData; -struct ChannelDriver; struct Depsgraph; struct FCurve; struct ID; @@ -289,7 +288,7 @@ void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id); void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, int driver_index, - struct ChannelDriver *driver_orig); + struct FCurve *fcu_orig); void BKE_animsys_update_driver_array(struct ID *id); diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index e55cb69a5c6..b35abb1ecef 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -91,5 +91,6 @@ enum { #define BLENDER_QUIT_FILE "quit.blend" #define BLENDER_BOOKMARK_FILE "bookmarks.txt" #define BLENDER_HISTORY_FILE "recent-files.txt" +#define BLENDER_PLATFORM_SUPPORT_FILE "platform_support.txt" #endif /* __BKE_APPDIR_H__ */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 89f83c44c11..dfa1b311eb0 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -26,8 +26,8 @@ * * \note Use #STRINGIFY() rather than defining with quotes. */ -#define BLENDER_VERSION 281 -#define BLENDER_SUBVERSION 11 +#define BLENDER_VERSION 282 +#define BLENDER_SUBVERSION 1 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 26ab7f8ba0c..70741831727 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -31,7 +31,6 @@ struct Main; struct Scene; struct ToolSettings; struct UnifiedPaintSettings; -struct bContext; // enum eCurveMappingPreset; @@ -56,7 +55,7 @@ void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool li void BKE_brush_free(struct Brush *brush); void BKE_brush_sculpt_reset(struct Brush *brush); -void BKE_brush_gpencil_presets(struct bContext *C); +void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts); /* image icon function */ struct ImBuf *get_brush_icon(struct Brush *brush); @@ -90,7 +89,9 @@ float BKE_brush_sample_masktex(const struct Scene *scene, unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary); /* radial control */ -struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary); +struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, + bool secondary, + bool display_gradient); /* unified strength size and color */ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index aeff6007292..630c5fa1856 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -86,11 +86,10 @@ void BKE_curve_curve_dimension_update(struct Curve *cu); void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]); struct BoundBox *BKE_curve_boundbox_get(struct Object *ob); + void BKE_curve_texspace_calc(struct Curve *cu); -struct BoundBox *BKE_curve_texspace_get(struct Curve *cu, - float r_loc[3], - float r_rot[3], - float r_size[3]); +void BKE_curve_texspace_ensure(struct Curve *cu); +void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_size[3]); bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 062968eddfc..47c8f31ead3 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -30,6 +30,7 @@ struct BMLoop; struct BMesh; +struct BoundBox; struct Depsgraph; struct EditMeshData; struct Mesh; @@ -59,6 +60,9 @@ typedef struct BMEditMesh { struct Mesh *mesh_eval_final, *mesh_eval_cage; + /** Cached cage bounding box for selection. */ + struct BoundBox *bb_cage; + /*derivedmesh stuff*/ CustomData_MeshMasks lastDataMask; unsigned char (*derivedVertColor)[4]; @@ -90,6 +94,7 @@ void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]; void BKE_editmesh_lnorspace_update(BMEditMesh *em); void BKE_editmesh_ensure_autosmooth(BMEditMesh *em); +struct BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em); /* editderivedmesh.c */ /* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index e86408076cd..7c8a9452023 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -72,8 +72,8 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree, float *r_dist, float r_hitout[3], float r_cagehit[3], - BMBVHTree_FaceFilter filter, - void *filter_cb); + BMBVHTree_FaceFilter filter_cb, + void *filter_userdata); /* find a vert closest to co in a sphere of radius dist_max */ struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree, diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 369cffedb9d..7f227650f61 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -32,6 +32,7 @@ struct ListBase; struct Main; struct Material; struct Object; +struct Scene; struct ToolSettings; struct bDeformGroup; struct bGPDframe; diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index ba2e1e85d23..9cbc7d05ac2 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -31,7 +31,7 @@ struct ModifierUpdateDepsgraphContext; struct Object; struct Scene; /* NOTE: bakeModifier() called from UI: - * needs to create new databloc-ks, hence the need for this. */ + * needs to create new data-blocks, hence the need for this. */ struct bGPDframe; struct bGPDlayer; struct bGPDstroke; @@ -261,12 +261,6 @@ typedef struct GpencilModifierTypeInfo { struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); - - /** - * Get the number of times the strokes are duplicated in this modifier. - * This is used to calculate the size of the GPU VBOs - */ - int (*getDuplicationFactor)(struct GpencilModifierData *md); } GpencilModifierTypeInfo; /* Initialize modifier's global data (type info and some common global storages). */ @@ -297,6 +291,7 @@ void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, bool BKE_gpencil_has_geometry_modifiers(struct Object *ob); bool BKE_gpencil_has_time_modifiers(struct Object *ob); +bool BKE_gpencil_has_transform_modifiers(struct Object *ob); void BKE_gpencil_stroke_modifiers(struct Depsgraph *depsgraph, struct Object *ob, diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 234b74eece3..82c831ae8e0 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -309,11 +309,11 @@ void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy); /* image_gen.c */ void BKE_image_buf_fill_color( unsigned char *rect, float *rect_float, int width, int height, const float color[4]); -void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int height, int width); +void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height); void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, - int height, - int width); + int width, + int height); /* Cycles hookup */ unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 535980840c1..19eb40debe6 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -114,11 +114,13 @@ void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend); -void BKE_layer_collection_isolate(struct Scene *scene, - struct ViewLayer *view_layer, - struct LayerCollection *lc, - bool extend); -void BKE_layer_collection_local_isolate(struct ViewLayer *view_layer, +bool BKE_base_is_visible(const struct View3D *v3d, const struct Base *base); +bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob); +void BKE_layer_collection_isolate_global(struct Scene *scene, + struct ViewLayer *view_layer, + struct LayerCollection *lc, + bool extend); +void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer, struct View3D *v3d, struct LayerCollection *lc, bool extend); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 261416dc025..71799bf74f6 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -114,7 +114,10 @@ enum { LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_CACHES, }; -void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, int flag); +void BKE_libblock_copy_ex(struct Main *bmain, + const struct ID *id, + struct ID **r_newid, + const int orig_flag); void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* Special version. sued by datablock localization. */ @@ -172,6 +175,7 @@ void BKE_libblock_management_usercounts_clear(struct Main *bmain, void *idv); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); +void id_lib_indirect_weak_link(struct ID *id); void BKE_library_filepath_set(struct Main *bmain, struct Library *lib, const char *filepath); void id_us_ensure_real(struct ID *id); void id_us_clear_real(struct ID *id); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index af40eef6ab5..90afec54561 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -78,12 +78,18 @@ struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, const bool add_key_index, const struct BMeshCreateParams *params); -struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params); +struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, + const struct BMeshToMeshParams *params, + const struct Mesh *me_settings); struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, - const struct CustomData_MeshMasks *cd_mask_extra); + const struct CustomData_MeshMasks *cd_mask_extra, + const struct Mesh *me_settings); struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap( - struct BMEditMesh *em, const struct CustomData_MeshMasks *data_mask, float (*vertexCos)[3]); + struct BMEditMesh *em, + const struct CustomData_MeshMasks *data_mask, + float (*vertexCos)[3], + const struct Mesh *me_settings); int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, @@ -107,6 +113,7 @@ void BKE_mesh_copy_data(struct Main *bmain, const struct Mesh *me_src, const int flag); struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me); +void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); @@ -141,8 +148,6 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me); bool BKE_mesh_clear_facemap_customdata(struct Mesh *me); void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local); -void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]); -void BKE_mesh_texspace_calc(struct Mesh *me); float (*BKE_mesh_orco_verts_get(struct Object *ob))[3]; void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert); int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr); @@ -192,12 +197,14 @@ void BKE_mesh_smooth_flag_set(struct Mesh *me, const bool use_smooth); const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh); struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob); -struct BoundBox *BKE_mesh_texspace_get(struct Mesh *me, - float r_loc[3], - float r_rot[3], - float r_size[3]); -void BKE_mesh_texspace_get_reference( - struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size); + +void BKE_mesh_texspace_calc(struct Mesh *me); +void BKE_mesh_texspace_ensure(struct Mesh *me); +void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_size[3]); +void BKE_mesh_texspace_get_reference(struct Mesh *me, + short **r_texflag, + float **r_loc, + float **r_size); void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob); void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index a1bcd515c17..86c094b8a6d 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -39,7 +39,12 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve double adaptivity, bool relax_disoriented_triangles); #endif -struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size); + +struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh); +struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, + float voxel_size, + float adaptivity, + float isovalue); struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh, int target_faces, int seed, diff --git a/source/blender/blenkernel/BKE_mirror.h b/source/blender/blenkernel/BKE_mirror.h new file mode 100644 index 00000000000..20eb8a920fc --- /dev/null +++ b/source/blender/blenkernel/BKE_mirror.h @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +#ifndef __BKE_MIRROR_H__ +#define __BKE_MIRROR_H__ + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +struct MirrorModifierData; +struct ModifierEvalContext; +struct Object; + +struct Mesh *BKE_mirror_bisect_on_mirror_plane(struct MirrorModifierData *mmd, + const struct Mesh *mesh, + int axis, + const float plane_co[3], + float plane_no[3]); + +struct Mesh *BKE_mirror_apply_mirror_on_axis(struct MirrorModifierData *mmd, + const struct ModifierEvalContext *UNUSED(ctx), + struct Object *ob, + const struct Mesh *mesh, + int axis); + +#endif /* __BKE_MIRROR_H__ */ diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index b2bc30c107c..0977a406aa0 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -48,7 +48,9 @@ typedef enum { */ eModifierTypeType_OnlyDeform, + /* Modifier adds geometry. */ eModifierTypeType_Constructive, + /* Modifier can add and remove geometry. */ eModifierTypeType_Nonconstructive, /* both deformVerts & applyModifier are valid calls @@ -380,6 +382,7 @@ struct Object *modifiers_isDeformedByArmature(struct Object *ob); struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); struct Object *modifiers_isDeformedByCurve(struct Object *ob); +bool modifiers_usesMultires(struct Object *ob); bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm); bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob); bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index c5955a9af8d..7513717df41 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -53,8 +53,8 @@ void multires_mark_as_modified(struct Depsgraph *depsgraph, struct Object *object, enum MultiresModifiedFlags flags); -void multires_force_update(struct Object *ob); -void multires_force_render_update(struct Object *ob); +void multires_flush_sculpt_updates(struct Object *ob); +void multires_force_sculpt_rebuild(struct Object *ob); void multires_force_external_reload(struct Object *ob); /* internal, only called in subsurf_ccg.c */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f88aebd312c..a5b9b1e5148 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -591,6 +591,11 @@ void nodeChainIter(const bNodeTree *ntree, bool (*callback)(bNode *, bNode *, void *, const bool), void *userdata, const bool reversed); +void nodeChainIterBackwards(const bNodeTree *ntree, + const bNode *node_start, + bool (*callback)(bNode *, bNode *, void *), + void *userdata, + int recursion_lvl); void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata); struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index dcd926e9e19..ffdcb9cd2c0 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -321,8 +321,10 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph, void BKE_object_sculpt_data_create(struct Object *ob); -int BKE_object_obdata_texspace_get( - struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot); +int BKE_object_obdata_texspace_get(struct Object *ob, + short **r_texflag, + float **r_loc, + float **r_size); struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob); struct Mesh *BKE_object_get_final_mesh(struct Object *object); diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h index ef0cbaa2ae6..83780d8fad5 100644 --- a/source/blender/blenkernel/BKE_object_facemap.h +++ b/source/blender/blenkernel/BKE_object_facemap.h @@ -40,6 +40,11 @@ void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap); struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name); void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase); +int *BKE_object_facemap_index_map_create(struct Object *ob_src, + struct Object *ob_dst, + int *r_map_len); +void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 5ce16e8b906..4413ad2a70f 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -220,7 +220,7 @@ typedef struct SculptSession { struct MPoly *mpoly; struct MLoop *mloop; int totvert, totpoly; - struct KeyBlock *kb; + struct KeyBlock *shapekey_active; float *vmask; /* Mesh connectivity */ @@ -243,10 +243,10 @@ typedef struct SculptSession { bool show_mask; /* Painting on deformed mesh */ - bool modifiers_active; /* object is deformed with some modifiers */ - float (*orig_cos)[3]; /* coords of undeformed mesh */ - float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ - float (*deform_imats)[3][3]; /* crazyspace deformation matrices */ + bool deform_modifiers_active; /* object is deformed with some modifiers */ + float (*orig_cos)[3]; /* coords of undeformed mesh */ + float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ + float (*deform_imats)[3][3]; /* crazyspace deformation matrices */ /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; @@ -270,6 +270,7 @@ typedef struct SculptSession { /* Dynamic mesh preview */ int *preview_vert_index_list; int preview_vert_index_count; + float pose_origin[3]; /* Transform operator */ float pivot_pos[3]; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 899dddf31e8..13adb868c01 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -25,6 +25,13 @@ #include "BLI_bitmap.h" #include "BLI_ghash.h" +/* For embedding CCGKey in iterator. */ +#include "BKE_ccg.h" + +#ifdef __cplusplus +extern "C" { +#endif + struct BMLog; struct BMesh; struct CCGElem; @@ -33,6 +40,7 @@ struct CustomData; struct DMFlagMat; struct GPU_PBVH_Buffers; struct IsectRayPrecalc; +struct Mesh; struct MLoop; struct MLoopTri; struct MPoly; @@ -40,6 +48,8 @@ struct MVert; struct PBVH; struct PBVHNode; struct SubdivCCG; +struct TaskParallelSettings; +struct TaskParallelTLS; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; @@ -49,20 +59,28 @@ typedef struct { } PBVHProxyNode; typedef enum { - PBVH_Leaf = 1, + PBVH_Leaf = 1 << 0, - PBVH_UpdateNormals = 2, - PBVH_UpdateBB = 4, - PBVH_UpdateOriginalBB = 8, - PBVH_UpdateDrawBuffers = 16, - PBVH_UpdateRedraw = 32, + PBVH_UpdateNormals = 1 << 1, + PBVH_UpdateBB = 1 << 2, + PBVH_UpdateOriginalBB = 1 << 3, + PBVH_UpdateDrawBuffers = 1 << 4, + PBVH_UpdateRedraw = 1 << 5, + PBVH_UpdateMask = 1 << 6, - PBVH_RebuildDrawBuffers = 64, - PBVH_FullyHidden = 128, + PBVH_RebuildDrawBuffers = 1 << 7, + PBVH_FullyHidden = 1 << 8, + PBVH_FullyMasked = 1 << 9, + PBVH_FullyUnmasked = 1 << 10, - PBVH_UpdateTopology = 256, + PBVH_UpdateTopology = 1 << 11, } PBVHNodeFlags; +typedef struct PBVHFrustumPlanes { + float (*planes)[4]; + int num_planes; +} PBVHFrustumPlanes; + /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ @@ -77,6 +95,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float PBVH *BKE_pbvh_new(void); void BKE_pbvh_build_mesh(PBVH *bvh, + const struct Mesh *mesh, const struct MPoly *mpoly, const struct MLoop *mloop, struct MVert *verts, @@ -167,7 +186,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh, /* Drawing */ void BKE_pbvh_draw_cb(PBVH *bvh, - float (*planes)[4], + bool show_vcol, + bool update_only_visible, + PBVHFrustumPlanes *frustum, void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), void *user_data); @@ -198,9 +219,10 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, int gridsize); /* multires level, only valid for type == PBVH_GRIDS */ -void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh); -struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids); +struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh); +int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh); /* Only valid for type == PBVH_BMESH */ struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); @@ -221,11 +243,16 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, /* Node Access */ void BKE_pbvh_node_mark_update(PBVHNode *node); +void BKE_pbvh_node_mark_update_mask(PBVHNode *node); void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); void BKE_pbvh_node_mark_redraw(PBVHNode *node); void BKE_pbvh_node_mark_normals_update(PBVHNode *node); void BKE_pbvh_node_mark_topology_update(PBVHNode *node); void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); +void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked); +bool BKE_pbvh_node_fully_masked_get(PBVHNode *node); +void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked); +bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node); void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, @@ -245,10 +272,10 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max float BKE_pbvh_node_get_tmin(PBVHNode *node); -/* test if AABB is at least partially inside the planes' volume */ -bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); -/* test if AABB is at least partially outside the planes' volume */ -bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); +/* test if AABB is at least partially inside the PBVHFrustumPlanes volume */ +bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum); +/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */ +bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum); struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node); struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node); @@ -259,8 +286,8 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); /* Update Bounding Box/Redraw and clear flags */ void BKE_pbvh_update_bounds(PBVH *bvh, int flags); +void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags); void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg); -void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol); void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface); void BKE_pbvh_grids_update(PBVH *bvh, @@ -304,9 +331,9 @@ typedef struct PBVHVertexIter { int index; /* grid */ + struct CCGKey key; struct CCGElem **grids; struct CCGElem *grid; - struct CCGKey *key; BLI_bitmap **grid_hidden, *gh; int *grid_indices; int totgrid; @@ -343,6 +370,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo if (vi.grids) { \ vi.width = vi.gridsize; \ vi.height = vi.gridsize; \ + vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ vi.grid = vi.grids[vi.grid_indices[vi.g]]; \ if (mode == PBVH_ITER_UNIQUE) \ vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \ @@ -355,10 +383,11 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo for (vi.gy = 0; vi.gy < vi.height; vi.gy++) { \ for (vi.gx = 0; vi.gx < vi.width; vi.gx++, vi.i++) { \ if (vi.grid) { \ - vi.co = CCG_elem_co(vi.key, vi.grid); \ - vi.fno = CCG_elem_no(vi.key, vi.grid); \ - vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \ - vi.grid = CCG_elem_next(vi.key, vi.grid); \ + vi.co = CCG_elem_co(&vi.key, vi.grid); \ + vi.fno = CCG_elem_no(&vi.key, vi.grid); \ + vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \ + vi.grid = CCG_elem_next(&vi.key, vi.grid); \ + vi.index++; \ if (vi.gh) { \ if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) \ continue; \ @@ -414,4 +443,33 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node); bool pbvh_has_mask(PBVH *bvh); void pbvh_show_mask_set(PBVH *bvh, bool show_mask); +/* Parallelization */ +typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata, + const int iter, + const struct TaskParallelTLS *__restrict tls); +typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata, + void *__restrict chunk_join, + void *__restrict chunk); + +typedef struct PBVHParallelSettings { + bool use_threading; + void *userdata_chunk; + size_t userdata_chunk_size; + PBVHParallelReduceFunc func_reduce; +} PBVHParallelSettings; + +void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings, + bool use_threading, + int totnode); + +void BKE_pbvh_parallel_range(const int start, + const int stop, + void *userdata, + PBVHParallelRangeFunc func, + const struct PBVHParallelSettings *settings); + +#ifdef __cplusplus +} +#endif + #endif /* __BKE_PBVH_H__ */ diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 4c023f54e04..b4c440d54a6 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -103,8 +103,14 @@ bool BKE_rigidbody_add_object(struct Main *bmain, int type, struct ReportList *reports); void BKE_rigidbody_ensure_local_object(struct Main *bmain, struct Object *ob); -void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob); -void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob); +void BKE_rigidbody_remove_object(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); +void BKE_rigidbody_remove_constraint(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); /* -------------- */ /* Utility Macros */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 2986d19edfb..006915d6c45 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -75,7 +75,10 @@ void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); struct Scene *BKE_scene_add(struct Main *bmain, const char *name); -void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob); +void BKE_scene_remove_rigidbody_object(struct Main *bmain, + struct Scene *scene, + struct Object *ob, + const bool free_us); bool BKE_scene_object_find(struct Scene *scene, struct Object *ob); struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name); @@ -122,7 +125,7 @@ struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, #ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH #endif -int BKE_scene_camera_switch_update(struct Scene *scene); +bool BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 16f766ae8bb..a5b223a73f2 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -351,6 +351,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa void BKE_sequencer_prefetch_stop(struct Scene *scene); void BKE_sequencer_prefetch_free(struct Scene *scene); bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene); +bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene); void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end); SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context); struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq, diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index e3d19a3d807..e90b1429c9d 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -115,6 +115,11 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, struct Object *ob_source, struct Object *ob_target); +/* Used in object_remesh.c to preserve the details and volume in the voxel remesher */ +void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me, + struct Mesh *target_me, + struct Object *ob_target); + /* * This function casts a ray in the given BVHTree. * but it takes into consideration the space_transform, that is: diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 700bf5139e0..267a03da25c 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -140,7 +140,7 @@ typedef struct SubdivDisplacement { /* This structure contains everything needed to construct subdivided surface. * It does not specify storage, memory layout or anything else. - * It is possible to create different storages (like, grid based CPU side + * It is possible to create different storage's (like, grid based CPU side * buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same * Subdiv structure. */ typedef struct Subdiv { diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 2e9ccb8b39d..409a0d1232b 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -92,6 +92,14 @@ typedef struct SubdivToCCGSettings { bool need_mask; } SubdivToCCGSettings; +typedef struct SubdivCCGCoord { + /* Index of the grid within SubdivCCG::grids array. */ + int grid_index; + + /* Coordinate within the grid. */ + short x, y; +} SubdivCCGCoord; + /* This is actually a coarse face, which consists of multiple CCG grids. */ typedef struct SubdivCCGFace { /* Total number of grids in this face. @@ -106,20 +114,16 @@ typedef struct SubdivCCGFace { /* Definition of an edge which is adjacent to at least one of the faces. */ typedef struct SubdivCCGAdjacentEdge { int num_adjacent_faces; - /* Indexed by adjacent face index. */ - SubdivCCGFace **faces; /* Indexed by adjacent face index, then by point index on the edge. - * points to a grid element. */ - struct CCGElem ***boundary_elements; + * points to a coordinate into the grids. */ + struct SubdivCCGCoord **boundary_coords; } SubdivCCGAdjacentEdge; /* Definition of a vertex which is adjacent to at least one of the faces. */ typedef struct SubdivCCGAdjacentVertex { int num_adjacent_faces; - /* Indexed by adjacent face index. */ - SubdivCCGFace **faces; - /* Indexed by adjacent face index, points to a grid element. */ - struct CCGElem **corner_elements; + /* Indexed by adjacent face index, points to a coordinate in the grids. */ + struct SubdivCCGCoord *corner_coords; } SubdivCCGAdjacentVertex; /* Representation of subdivision surface which uses CCG grids. */ @@ -135,6 +139,9 @@ typedef struct SubdivCCG { /* Resolution of grid. All grids have matching resolution, and resolution * is same as ptex created for non-quad polygons. */ int grid_size; + /* Size of a single element of a grid (including coordinate and all the other layers). + * Measured in bytes. */ + int grid_element_size; /* Grids represent limit surface, with displacement applied. Grids are * corresponding to face-corners of coarse mesh, each grid has * grid_size^2 elements. @@ -150,7 +157,7 @@ typedef struct SubdivCCG { struct CCGElem **edges; int num_edges; /* Loose vertices. Every element corresponds to a loose vertex from a coarse - * mesh, every coarse loose vertex corresponds to a single sundivided + * mesh, every coarse loose vertex corresponds to a single subdivided * element. */ struct CCGElem *vertices; int num_vertices; @@ -255,4 +262,40 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, int *r_num_faces, int *r_num_loops); +typedef struct SubdivCCGNeighbors { + SubdivCCGCoord *coords; + int size; + int num_duplicates; + + SubdivCCGCoord coords_fixed[256]; +} SubdivCCGNeighbors; + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord); +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord); + +/* CCG element neighbors. + * + * Neighbors are considered: + * + * - For an inner elements of a grid other elements which are sharing same row or column (4 + * neighbor elements in total). + * + * - For the corner element a single neighboring element on every adjacent edge, single from + * every gird. + * + * - For the boundary element two neighbor elements on the boundary (from same grid) and one + * element inside of every neighboring grid. */ + +/* Get actual neighbors of the given coordinate. + * + * SubdivCCGNeighbors.neighbors must be freed if it is not equal to + * SubdivCCGNeighbors.fixed_neighbors. + * + * If include_duplicates is true, vertices in other grids that match + * the current vertex are added at the end of the coords array. */ +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors); + #endif /* __BKE_SUBDIV_CCG_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h new file mode 100644 index 00000000000..f1a56aa9cde --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_deform.h @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifndef __BKE_SUBDIV_DEFORM_H__ +#define __BKE_SUBDIV_DEFORM_H__ + +#include "BLI_sys_types.h" + +struct Mesh; +struct Subdiv; + +/* Special version of subdivision surface which calculates final positions for coarse vertices. + * + * vertex_cos are supposed to hold coordinates of the coarse mesh. */ +void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, + const struct Mesh *coarse_mesh, + float (*vertex_cos)[3], + int num_verts); + +#endif /* __BKE_SUBDIV_DEFORM_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 1d794e4d61a..c8d672c2524 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -31,7 +31,12 @@ struct Subdiv; /* Returns true if evaluator is ready for use. */ bool BKE_subdiv_eval_begin(struct Subdiv *subdiv); -bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh); + +/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse + * mesh. */ +bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, + const struct Mesh *mesh, + const float (*coarse_vertex_cos)[3]); /* Makes sure displacement evaluator is initialized. * diff --git a/source/blender/blenkernel/BKE_subdiv_topology.h b/source/blender/blenkernel/BKE_subdiv_topology.h new file mode 100644 index 00000000000..dd057d88fb6 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_topology.h @@ -0,0 +1,31 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifndef __BKE_SUBDIV_TOPOLOGY_H__ +#define __BKE_SUBDIV_TOPOLOGY_H__ + +struct Subdiv; + +int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv); + +#endif /* __BKE_SUBDIV_TOPOLOGY_H__ */ diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 65aa43ced7c..98a94c5f689 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -78,6 +78,7 @@ void txt_delete_selected(struct Text *text); void txt_sel_all(struct Text *text); void txt_sel_clear(struct Text *text); void txt_sel_line(struct Text *text); +void txt_sel_set(struct Text *text, int startl, int startc, int endl, int endc); char *txt_sel_to_buf(struct Text *text, int *r_buf_strlen); void txt_insert_buf(struct Text *text, const char *in_buffer); void txt_split_curline(struct Text *text); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 16074cd3e37..ec4246f5dba 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -159,6 +159,7 @@ set(SRC intern/mesh_runtime.c intern/mesh_tangent.c intern/mesh_validate.c + intern/mirror.c intern/modifier.c intern/movieclip.c intern/multires.c @@ -182,15 +183,16 @@ set(SRC intern/particle_system.c intern/pbvh.c intern/pbvh_bmesh.c + intern/pbvh_parallel.cc intern/pointcache.c intern/report.c intern/rigidbody.c intern/scene.c intern/screen.c intern/seqcache.c - intern/seqprefetch.c intern/seqeffects.c intern/seqmodifier.c + intern/seqprefetch.c intern/sequencer.c intern/shader_fx.c intern/shrinkwrap.c @@ -205,12 +207,14 @@ set(SRC intern/subdiv_ccg_material.c intern/subdiv_converter.c intern/subdiv_converter_mesh.c + intern/subdiv_deform.c intern/subdiv_displacement.c intern/subdiv_displacement_multires.c intern/subdiv_eval.c intern/subdiv_foreach.c intern/subdiv_mesh.c intern/subdiv_stats.c + intern/subdiv_topology.c intern/subsurf_ccg.c intern/suggestions.c intern/text.c @@ -310,6 +314,7 @@ set(SRC BKE_mesh_remesh_voxel.h BKE_mesh_runtime.h BKE_mesh_tangent.h + BKE_mirror.h BKE_modifier.h BKE_movieclip.h BKE_multires.h @@ -339,9 +344,11 @@ set(SRC BKE_studiolight.h BKE_subdiv.h BKE_subdiv_ccg.h + BKE_subdiv_deform.h BKE_subdiv_eval.h BKE_subdiv_foreach.h BKE_subdiv_mesh.h + BKE_subdiv_topology.h BKE_subsurf.h BKE_suggestions.h BKE_text.h @@ -631,6 +638,14 @@ if(WITH_QUADRIFLOW) add_definitions(-DWITH_QUADRIFLOW) endif() +if(WITH_TBB) + add_definitions(-DWITH_TBB) + + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 010e162f49d..2f61cfcbc15 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -729,7 +729,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) int free; if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); + mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me); } else { mesh = BKE_mesh_copy_for_eval(me, true); @@ -797,14 +797,6 @@ static void editmesh_update_statvis_color(const Scene *scene, Object *ob) BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis); } -static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig) -{ - if (me_orig->flag & ME_AUTOSMOOTH) { - me->flag |= ME_AUTOSMOOTH; - me->smoothresh = me_orig->smoothresh; - } -} - static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, const CustomData_MeshMasks *final_datamask, const bool sculpt_dyntopo, @@ -881,18 +873,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval) /* Make sure the name is the same. This is because mesh allocation from template does not * take care of naming. */ BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name)); - /* Make sure materials are preserved from the input. */ - if (mesh_eval->mat != NULL) { - MEM_freeN(mesh_eval->mat); - } - mesh_eval->mat = MEM_dupallocN(mesh_input->mat); - mesh_eval->totcol = mesh_input->totcol; /* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */ mesh_eval->edit_mesh = mesh_input->edit_mesh; - /* Copy auth-smooth settings which are also not taken care about by mesh allocation from a - * template. */ - mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH); - mesh_eval->smoothresh = mesh_input->smoothresh; } static void mesh_calc_modifiers(struct Depsgraph *depsgraph, @@ -1220,8 +1202,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, MEM_freeN(deformed_verts); deformed_verts = NULL; } - - mesh_copy_autosmooth(mesh_final, mesh_input); } /* create an orco mesh in parallel */ @@ -1533,8 +1513,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Evaluate modifiers up to certain index to get the mesh cage. */ int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); if (r_cage && cageIndex == -1) { - mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, &final_datamask, NULL); - mesh_copy_autosmooth(mesh_cage, mesh_input); + mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( + em_input, &final_datamask, NULL, mesh_input); } /* Clear errors before evaluation. */ @@ -1574,9 +1554,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { if (mesh_final == NULL) { - mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL); + mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input); ASSERT_IS_VALID_MESH(mesh_final); - mesh_copy_autosmooth(mesh_final, mesh_input); } BLI_assert(deformed_verts != NULL); BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); @@ -1607,11 +1586,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } } else { - mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL); + mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input); ASSERT_IS_VALID_MESH(mesh_final); - mesh_copy_autosmooth(mesh_final, mesh_input); - if (deformed_verts) { BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } @@ -1674,8 +1651,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, MEM_freeN(deformed_verts); deformed_verts = NULL; } - - mesh_copy_autosmooth(mesh_final, mesh_input); } mesh_final->runtime.deformed_only = false; } @@ -1695,8 +1670,10 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts); } mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( - em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL); - mesh_copy_autosmooth(mesh_cage, mesh_input); + em_input, + &final_datamask, + deformed_verts ? MEM_dupallocN(deformed_verts) : NULL, + mesh_input); } } @@ -1730,11 +1707,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, else { /* this is just a copy of the editmesh, no need to calc normals */ mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap( - em_input, &final_datamask, deformed_verts); + em_input, &final_datamask, deformed_verts, mesh_input); deformed_verts = NULL; - mesh_copy_autosmooth(mesh_final, mesh_input); - /* In this case, we should never have weight-modifying modifiers in stack... */ if (do_init_statvis) { editmesh_update_statvis_color(scene, ob); @@ -1854,11 +1829,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph, &ob->runtime.mesh_eval); BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval); - /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492) - * did not re-enable that flag (which always get disabled for eval mesh as a start). */ - if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) { - BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob); - } assign_object_mesh_eval(ob); @@ -1982,7 +1952,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask) { /* This function isn't thread-safe and can't be used during evaluation. */ - BLI_assert(DEG_debug_is_evaluating(depsgraph) == false); + BLI_assert(DEG_is_evaluating(depsgraph) == false); /* Evaluated meshes aren't supposed to be created on original instances. If you do, * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */ @@ -2015,7 +1985,7 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask) { /* This function isn't thread-safe and can't be used during evaluation. */ - BLI_assert(DEG_debug_is_evaluating(depsgraph) == false); + BLI_assert(DEG_is_evaluating(depsgraph) == false); /* Evaluated meshes aren't supposed to be created on original instances. If you do, * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d072a0aa599..de1cbd236fb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1472,7 +1472,7 @@ void BKE_pose_rest(bPose *pose) } } -void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) +void BKE_pose_copy_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) { copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); @@ -1523,7 +1523,7 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) { pchanto = BKE_pose_channel_find_name(to, pchanfrom->name); if (pchanto != NULL) { - BKE_pose_copyesult_pchan_result(pchanto, pchanfrom); + BKE_pose_copy_pchan_result(pchanto, pchanfrom); } } return true; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index ab8ea37377d..2e655452a21 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -305,8 +305,9 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag) /* make a copy of action - at worst, user has to delete copies... */ if (do_action) { BLI_assert(bmain != NULL); - BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action); - BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact); + BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact); + BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag); + BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag); } else if (do_id_user) { id_us_plus((ID *)dadt->action); @@ -4081,11 +4082,10 @@ void BKE_animsys_update_driver_array(ID *id) } } -void BKE_animsys_eval_driver(Depsgraph *depsgraph, - ID *id, - int driver_index, - ChannelDriver *driver_orig) +void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCurve *fcu_orig) { + BLI_assert(fcu_orig != NULL); + /* TODO(sergey): De-duplicate with BKE animsys. */ PointerRNA id_ptr; bool ok = false; @@ -4110,6 +4110,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { /* check if driver itself is tagged for recalculation */ /* XXX driver recalc flag is not set yet by depsgraph! */ + ChannelDriver *driver_orig = fcu_orig->driver; if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) { /* evaluate this using values set already in other places * NOTE: for 'layering' option later on, we should check if we should remove old value before @@ -4120,7 +4121,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { /* Evaluate driver, and write results to COW-domain destination */ const float ctime = DEG_get_ctime(depsgraph); - const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime); + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); ok = animsys_write_rna_setting(&anim_rna, curval); /* Flush results & status codes to original data for UI (T59984) */ @@ -4128,6 +4129,7 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); /* curval is displayed in the UI, and flag contains error-status codes */ + fcu_orig->curval = fcu->curval; driver_orig->curval = fcu->driver->curval; driver_orig->flag = fcu->driver->flag; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 3b64a9520ca..fbac9e6b773 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -110,7 +110,7 @@ const char *BKE_appdir_folder_default(void) // #define PATH_DEBUG -/* returns a formatted representation of the specified version number. Non-reentrant! */ +/* returns a formatted representation of the specified version number. Non-re-entrant! */ static char *blender_version_decimal(const int ver) { static char version_str[5]; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index d74c8e6d258..3215b3d7b40 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1257,9 +1257,9 @@ void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, float pre_blend = pos * (float)segments; int index = (int)floorf(pre_blend); - float blend = pre_blend - index; + CLAMP(index, 0, segments - 1); - CLAMP(index, 0, segments); + float blend = pre_blend - index; CLAMP(blend, 0.0f, 1.0f); *r_index = index; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 00975976130..e30accf6279 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -643,6 +643,10 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec } BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase)); + + if (object->proxy != NULL) { + object->proxy->proxy_from = object; + } } void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object) @@ -724,6 +728,26 @@ void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph, } } +static void pose_channel_flush_to_orig_if_needed(struct Depsgraph *depsgraph, + struct Object *object, + bPoseChannel *pchan) +{ + if (!DEG_is_active(depsgraph)) { + return; + } + const bArmature *armature = (bArmature *)object->data; + if (armature->edbo != NULL) { + return; + } + bPoseChannel *pchan_orig = pchan->orig_pchan; + /* TODO(sergey): Using BKE_pose_copy_pchan_result() introduces T70901, but why? */ + copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat); + copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat); + copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]); + copy_m4_m4(pchan_orig->constinv, pchan->constinv); + copy_v3_v3(pchan_orig->pose_tail, pchan->pose_tail); +} + void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int pchan_index) { const bArmature *armature = (bArmature *)object->data; @@ -741,13 +765,9 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int mat4_to_dquat(&pchan->runtime.deform_dual_quat, pchan->bone->arm_mat, pchan->chan_mat); } } - if (DEG_is_active(depsgraph) && armature->edbo == NULL) { + pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan); + if (DEG_is_active(depsgraph)) { bPoseChannel *pchan_orig = pchan->orig_pchan; - copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat); - copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat); - copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]); - copy_m4_m4(pchan_orig->constinv, pchan->constinv); - BKE_pose_where_is_bone_tail(pchan_orig); if (pchan->bone == NULL || pchan->bone->segments <= 1) { BKE_pose_channel_free_bbone_cache(&pchan_orig->runtime); } @@ -905,7 +925,9 @@ void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object, pchan->name); return; } - BKE_pose_copyesult_pchan_result(pchan, pchan_from); + BKE_pose_copy_pchan_result(pchan, pchan_from); copy_dq_dq(&pchan->runtime.deform_dual_quat, &pchan_from->runtime.deform_dual_quat); BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from); + + pose_channel_flush_to_orig_if_needed(depsgraph, object, pchan); } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 29c4ae624e9..fe740f4898e 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -26,6 +26,7 @@ #include "DNA_gpencil_types.h" #include "DNA_defaults.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rand.h" @@ -36,6 +37,7 @@ #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_paint.h" #include "BKE_texture.h" #include "BKE_icons.h" @@ -239,307 +241,390 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) } } -/* create a set of grease pencil presets */ -void BKE_brush_gpencil_presets(bContext *C) +/* create a set of grease pencil presets. */ +void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) { #define SMOOTH_STROKE_RADIUS 40 #define SMOOTH_STROKE_FACTOR 0.9f - ToolSettings *ts = CTX_data_tool_settings(C); Paint *paint = &ts->gp_paint->paint; - Main *bmain = CTX_data_main(C); Brush *brush, *deft; CurveMapping *custom_curve; - /* Pencil brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil"); - brush->size = 25.0f; + /* Airbrush brush. */ + brush = BLI_findstring(&bmain->brushes, "Airbrush", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Airbrush"); + } + + brush->size = 300.0f; brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.0f; - brush->gpencil_settings->draw_strength = 0.6f; + brush->gpencil_settings->draw_strength = 0.4f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_settings->draw_random_press = 0.0f; - - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.98f; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 0.211f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; + + brush->gpencil_settings->draw_sensitivity = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH; brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - /* Pen brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen"); - deft = brush; /* save default brush */ - brush->size = 30.0f; + /* Create and link Black Dots material to brush. + * This material is required because the brush uses the material to define how the stroke is + * drawn. */ + Material *ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2); + if (ma == NULL) { + ma = BKE_material_add_gpencil(bmain, "Black Dots"); + } + brush->gpencil_settings->material = ma; + /* Pin the matterial to the brush. */ + brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; + + /* Ink Pen brush. */ + brush = BLI_findstring(&bmain->brushes, "Ink Pen", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen"); + } + brush->size = 60.0f; brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.0f; brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.7f; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 0; brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - /* Ink brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink"); - brush->size = 60.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.6f; - - brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->simplify_f = 0.002f; brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK); - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->draw_random_sub = 0.0f; brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; brush->gpencil_tool = GPAINT_TOOL_DRAW; brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - /* Curve */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK); + /* Ink Pen Rough brush. */ + brush = BLI_findstring(&bmain->brushes, "Ink Pen Rough", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen Rough"); + } - /* Ink Noise brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise"); brush->size = 60.0f; brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.0f; brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.7f; - brush->gpencil_settings->draw_random_strength = 0.0f; - - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.5f; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; brush->gpencil_settings->draw_smoothlvl = 2; - brush->gpencil_settings->thick_smoothfac = 0.5f; + brush->gpencil_settings->thick_smoothfac = 0.0f; brush->gpencil_settings->thick_smoothlvl = 2; - brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_subdivide = 0; brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->gpencil_settings->simplify_f = 0.000f; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 1.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; - /* Curve */ + /* Curve. */ custom_curve = brush->gpencil_settings->curve_sensitivity; BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); BKE_curvemapping_initialize(custom_curve); brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE); - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - /* Block Basic brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block"); - brush->size = 150.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; + brush->gpencil_tool = GPAINT_TOOL_DRAW; - brush->gpencil_settings->draw_strength = 1.0f; + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - brush->gpencil_settings->draw_random_press = 0.0f; + /* Marker Bold brush. */ + brush = BLI_findstring(&bmain->brushes, "Marker Bold", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Marker Bold"); + } + brush->size = 150.0f; + brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.6f; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER); + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; brush->gpencil_tool = GPAINT_TOOL_DRAW; brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - /* Marker brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker"); + /* Marker Chisel brush. */ + brush = BLI_findstring(&bmain->brushes, "Marker Chisel", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Marker Chisel"); + } brush->size = 80.0f; brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); - brush->gpencil_settings->draw_sensitivity = 1.0f; brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.374f; - brush->gpencil_settings->draw_random_strength = 0.0f; - - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.5f; brush->gpencil_settings->draw_angle = DEG2RAD(20.0f); brush->gpencil_settings->draw_angle_factor = 1.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothfac = 0.0f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->draw_random_sub = 0; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; brush->gpencil_tool = GPAINT_TOOL_DRAW; brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - /* Curve */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER); + /* Pen brush. */ + brush = BLI_findstring(&bmain->brushes, "Pen", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Pen"); + } + brush->size = 30.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.3f; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; brush->gpencil_settings->gradient_f = 1.0f; brush->gpencil_settings->gradient_s[0] = 1.0f; brush->gpencil_settings->gradient_s[1] = 1.0f; - /* Soft brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Draw Soft"); - deft = brush; /* save default brush */ - brush->size = 300.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Pencil Soft brush. */ + brush = BLI_findstring(&bmain->brushes, "Pencil Soft", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Pencil Soft"); + } + + brush->size = 80.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_strength = 0.4f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.64f; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 0.8f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->simplify_f = 0.000f; + brush->gpencil_settings->draw_random_press = 0.0f; brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Pencil brush. */ + brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Pencil"); + } + deft = brush; /* save default brush. */ + brush->size = 25.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + + brush->gpencil_settings->draw_strength = 0.6f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.55f; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.98f; - brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 0; brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; brush->gpencil_tool = GPAINT_TOOL_DRAW; brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - brush->gpencil_settings->gradient_f = 0.211f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 0.91f; - - /* Fill brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + /* Fill brush. */ + brush = BLI_findstring(&bmain->brushes, "Fill Area", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + } brush->size = 20.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->fill_leak = 3; brush->gpencil_settings->fill_threshold = 0.1f; brush->gpencil_settings->fill_simplylvl = 1; brush->gpencil_settings->fill_factor = 1; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; - brush->gpencil_tool = GPAINT_TOOL_FILL; + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->gradient_f = 1.0f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 1.0f; brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; brush->gpencil_settings->draw_subdivide = 1; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_settings->draw_sensitivity = 1.0f; - brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; + brush->gpencil_tool = GPAINT_TOOL_FILL; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - /* Soft Eraser brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + /* Soft Eraser brush. */ + brush = BLI_findstring(&bmain->brushes, "Eraser Soft", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + } brush->size = 30.0f; brush->gpencil_settings->draw_strength = 0.5f; brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); @@ -551,34 +636,46 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->era_strength_f = 100.0f; brush->gpencil_settings->era_thickness_f = 10.0f; - /* Hard Eraser brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + /* Hard Eraser brush. */ + brush = BLI_findstring(&bmain->brushes, "Eraser Hard", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + } brush->size = 30.0f; brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - brush->gpencil_tool = GPAINT_TOOL_ERASE; brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; brush->gpencil_settings->era_strength_f = 100.0f; brush->gpencil_settings->era_thickness_f = 50.0f; - /* Point Eraser brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point"); + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + brush->gpencil_tool = GPAINT_TOOL_ERASE; + + /* Point Eraser brush. */ + brush = BLI_findstring(&bmain->brushes, "Eraser Point", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point"); + } brush->size = 30.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; brush->gpencil_tool = GPAINT_TOOL_ERASE; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; - /* Stroke Eraser brush */ - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + /* Stroke Eraser brush. */ + brush = BLI_findstring(&bmain->brushes, "Eraser Stroke", offsetof(ID, name) + 2); + if (brush == NULL) { + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + } brush->size = 30.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; brush->gpencil_tool = GPAINT_TOOL_ERASE; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; - /* set default brush */ + /* set default brush. */ BKE_paint_brush_set(paint, deft); } @@ -812,53 +909,36 @@ void BKE_brush_sculpt_reset(Brush *br) /* Use the curve presets by default */ br->curve_preset = BRUSH_CURVE_SMOOTH; - if (br->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { - br->curve_preset = BRUSH_CURVE_POW4; - } + /* Note that sculpt defaults where set when 0.5 was the default (now it's 1.0) + * assign this so logic below can remain the same. */ + br->alpha = 0.5f; + + /* Brush settings */ switch (br->sculpt_tool) { + case SCULPT_TOOL_DRAW_SHARP: + br->flag |= BRUSH_DIR_IN; + br->curve_preset = BRUSH_CURVE_POW4; + br->spacing = 5; + break; case SCULPT_TOOL_CLAY: br->flag |= BRUSH_FRONTFACE; break; + case SCULPT_TOOL_CLAY_STRIPS: + br->flag |= BRUSH_ACCUMULATE; + br->alpha = 0.7f; + br->normal_radius_factor = 1.7f; + br->curve_preset = BRUSH_CURVE_SPHERE; + br->spacing = 6; + break; case SCULPT_TOOL_CREASE: br->flag |= BRUSH_DIR_IN; br->alpha = 0.25; break; - case SCULPT_TOOL_FILL: - br->add_col[1] = 1; - br->sub_col[0] = 0.25; - br->sub_col[1] = 1; - break; - case SCULPT_TOOL_FLATTEN: - br->add_col[1] = 1; - br->sub_col[0] = 0.25; - br->sub_col[1] = 1; - break; - case SCULPT_TOOL_INFLATE: - br->add_col[0] = 0.750000; - br->add_col[1] = 0.750000; - br->add_col[2] = 0.750000; - br->sub_col[0] = 0.250000; - br->sub_col[1] = 0.250000; - br->sub_col[2] = 0.250000; - break; - case SCULPT_TOOL_NUDGE: - br->add_col[0] = 0.250000; - br->add_col[1] = 1.000000; - br->add_col[2] = 0.250000; - break; - case SCULPT_TOOL_PINCH: - br->add_col[0] = 0.750000; - br->add_col[1] = 0.750000; - br->add_col[2] = 0.750000; - br->sub_col[0] = 0.250000; - br->sub_col[1] = 0.250000; - br->sub_col[2] = 0.250000; - break; case SCULPT_TOOL_SCRAPE: - br->add_col[1] = 1.000000; - br->sub_col[0] = 0.250000; - br->sub_col[1] = 1.000000; + br->alpha = 1.0f; + br->spacing = 7; + br->flag |= BRUSH_ACCUMULATE; break; case SCULPT_TOOL_ROTATE: br->alpha = 1.0; @@ -866,22 +946,95 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_SMOOTH: br->flag &= ~BRUSH_SPACE_ATTEN; br->spacing = 5; - br->add_col[0] = 0.750000; - br->add_col[1] = 0.750000; - br->add_col[2] = 0.750000; + br->alpha = 0.7f; break; - case SCULPT_TOOL_GRAB: - case SCULPT_TOOL_ELASTIC_DEFORM: - case SCULPT_TOOL_POSE: case SCULPT_TOOL_SNAKE_HOOK: + br->alpha = 1.0f; + br->rake_factor = 1.0f; + break; case SCULPT_TOOL_THUMB: br->size = 75; br->flag &= ~BRUSH_ALPHA_PRESSURE; br->flag &= ~BRUSH_SPACE; br->flag &= ~BRUSH_SPACE_ATTEN; - br->add_col[0] = 0.250000; - br->add_col[1] = 1.000000; - br->add_col[2] = 0.250000; + break; + case SCULPT_TOOL_ELASTIC_DEFORM: + br->elastic_deform_volume_preservation = 0.4f; + br->elastic_deform_type = BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE; + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE; + br->flag &= ~BRUSH_SPACE_ATTEN; + break; + case SCULPT_TOOL_POSE: + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE; + br->flag &= ~BRUSH_SPACE_ATTEN; + break; + case SCULPT_TOOL_GRAB: + br->alpha = 0.4f; + br->size = 75; + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE; + br->flag &= ~BRUSH_SPACE_ATTEN; + break; + default: + break; + } + + /* Cursor colors */ + switch (br->sculpt_tool) { + case SCULPT_TOOL_DRAW: + case SCULPT_TOOL_DRAW_SHARP: + case SCULPT_TOOL_CLAY: + case SCULPT_TOOL_CLAY_STRIPS: + case SCULPT_TOOL_LAYER: + case SCULPT_TOOL_INFLATE: + case SCULPT_TOOL_BLOB: + case SCULPT_TOOL_CREASE: + br->add_col[0] = 0.5f; + br->add_col[1] = 0.7f; + br->add_col[2] = 0.875f; + br->sub_col[0] = 0.5f; + br->sub_col[1] = 0.7f; + br->sub_col[2] = 0.875f; + break; + + case SCULPT_TOOL_SMOOTH: + case SCULPT_TOOL_FLATTEN: + case SCULPT_TOOL_FILL: + case SCULPT_TOOL_SCRAPE: + br->add_col[0] = 1.0f; + br->add_col[1] = 0.39f; + br->add_col[2] = 0.39f; + br->sub_col[0] = 1.0f; + br->sub_col[1] = 0.39f; + br->sub_col[2] = 0.39f; + break; + + case SCULPT_TOOL_PINCH: + case SCULPT_TOOL_GRAB: + case SCULPT_TOOL_SNAKE_HOOK: + case SCULPT_TOOL_THUMB: + case SCULPT_TOOL_NUDGE: + case SCULPT_TOOL_ROTATE: + case SCULPT_TOOL_ELASTIC_DEFORM: + case SCULPT_TOOL_POSE: + br->add_col[0] = 1.0f; + br->add_col[1] = 1.0f; + br->add_col[2] = 0.39f; + br->sub_col[0] = 1.0f; + br->sub_col[1] = 1.0f; + br->sub_col[2] = 0.39f; + break; + + case SCULPT_TOOL_SIMPLIFY: + case SCULPT_TOOL_MASK: + br->add_col[0] = 0.750000; + br->add_col[1] = 0.750000; + br->add_col[2] = 0.750000; + br->sub_col[0] = 0.750000; + br->sub_col[1] = 0.750000; + br->sub_col[2] = 0.750000; break; default: break; @@ -1470,11 +1623,11 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec } /**** Radial Control ****/ -struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) +struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient) { ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture"); unsigned int *texcache; - int side = 128; + int side = 512; int half = side / 2; int i, j; @@ -1483,15 +1636,17 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect"); im->x = im->y = side; - for (i = 0; i < side; i++) { - for (j = 0; j < side; j++) { - float magn = sqrtf(pow2f(i - half) + pow2f(j - half)); - im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half); + if (display_gradient || texcache) { + for (i = 0; i < side; i++) { + for (j = 0; j < side; j++) { + float magn = sqrtf(pow2f(i - half) + pow2f(j - half)); + im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half); + } } } - /* Modulate curve with texture */ if (texcache) { + /* Modulate curve with texture */ for (i = 0; i < side; i++) { for (j = 0; j < side; j++) { const int col = texcache[i * side + j]; @@ -1500,7 +1655,6 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) 3.0f / 255.0f; } } - MEM_freeN(texcache); } diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 85a12027bf2..0a5952e1b47 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -1395,7 +1395,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, else { /* Setup BVHTreeFromMesh */ bvhtree_from_mesh_edges_setup_data( - data, tree, false, mesh->mvert, false, mesh->medge, false); + data, tree, true, mesh->mvert, false, mesh->medge, false); } break; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 2d6256f12e2..3b0f4d9c2aa 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -246,7 +246,7 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file BLI_freelistN(&cache_file->object_paths); #ifdef WITH_ALEMBIC - cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths); + cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths); BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX); #endif diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 63d58f7e32e..463cbd4f378 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -772,7 +772,7 @@ static int cloth_from_object( clmd->clothObject->old_solver_type = 255; clmd->clothObject->edgeset = NULL; } - else if (!clmd->clothObject) { + else { modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject"); return 0; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index f2098cc2430..68a38c94ff7 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -773,7 +773,7 @@ static bool scene_collections_object_remove( bool removed = false; if (collection_skip == NULL) { - BKE_scene_remove_rigidbody_object(bmain, scene, ob); + BKE_scene_remove_rigidbody_object(bmain, scene, ob, free_us); } FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { @@ -1305,6 +1305,9 @@ bool BKE_collection_move(Main *bmain, BLI_ghash_free(view_layer_hash, NULL, NULL); + /* We need to sync it again to pass the correct flags to the collections objects. */ + BKE_main_collection_sync(bmain); + return true; } diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index fcbebd24b4a..fe834658689 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -261,7 +261,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra float (**deformcos)[3]) { ModifierData *md; - Mesh *me; + Mesh *me_input = ob->data; + Mesh *me = NULL; int i, a, numleft = 0, numVerts = 0; int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; @@ -270,7 +271,6 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra modifiers_clearErrors(ob); - me = NULL; md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* compute the deformation matrices and coordinates for the first @@ -292,7 +292,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra data_mask = datamasks->mask; BLI_linklist_free((LinkNode *)datamasks, NULL); - me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL); + me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL, me_input); deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts); defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); @@ -342,6 +342,34 @@ static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph, } } +static void crazyspace_init_verts_and_matrices(const Mesh *mesh, + float (**deformmats)[3][3], + float (**deformcos)[3]) +{ + int num_verts; + *deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts); + *deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats"); + for (int a = 0; a < num_verts; a++) { + unit_m3((*deformmats)[a]); + } + BLI_assert(num_verts == mesh->totvert); +} + +static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md) +{ + if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) { + return true; + } + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + return (mti->type == eModifierTypeType_OnlyDeform); +} + +static bool crazyspace_modifier_supports_deform(ModifierData *md) +{ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + return (mti->type == eModifierTypeType_OnlyDeform); +} + int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, Scene *scene, Object *object, @@ -349,70 +377,63 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, float (**deformcos)[3]) { ModifierData *md; - Mesh *me_eval; - int a, numVerts = 0; + Mesh *me_eval = NULL; float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; int numleft = 0; VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); + const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; const bool has_multires = mmd != NULL && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, 0}; - if (has_multires) { + if (is_sculpt_mode && has_multires) { *deformmats = NULL; *deformcos = NULL; return numleft; } - me_eval = NULL; - md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData); for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { continue; } - if (mti->type == eModifierTypeType_OnlyDeform) { - if (!defmats) { + if (crazyspace_modifier_supports_deform_matrices(md)) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + if (defmats == NULL) { /* NOTE: Evaluated object si re-set to its original undeformed * state. */ Mesh *me = object_eval.data; me_eval = BKE_mesh_copy_for_eval(me, true); - deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts); - defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats"); - - for (a = 0; a < numVerts; a++) { - unit_m3(defmats[a]); - } + crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts); } if (mti->deformMatrices) { - mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts); + mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert); } else { break; } } + else { + break; + } } for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { continue; } - if (mti->type == eModifierTypeType_OnlyDeform) { + if (crazyspace_modifier_supports_deform(md)) { numleft++; } } - if (me_eval) { + if (me_eval != NULL) { BKE_id_free(NULL, me_eval); } @@ -435,6 +456,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, /* there are deformation modifier which doesn't support deformation matrices * calculation. Need additional crazyspace correction */ + Mesh *mesh = (Mesh *)object->data; + Mesh *mesh_eval = NULL; + + if (*deformcos == NULL) { + crazyspace_init_verts_and_matrices(mesh, deformmats, deformcos); + } + float(*deformedVerts)[3] = *deformcos; float(*origVerts)[3] = MEM_dupallocN(deformedVerts); float(*quats)[4]; @@ -444,23 +472,26 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, crazyspace_init_object_for_eval(depsgraph, object, &object_eval); ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData); const ModifierEvalContext mectx = {depsgraph, &object_eval, 0}; - Mesh *mesh = (Mesh *)object->data; for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { continue; } - if (mti->type == eModifierTypeType_OnlyDeform) { + if (crazyspace_modifier_supports_deform(md)) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + /* skip leading modifiers which have been already * handled in sculpt_get_first_deform_matrices */ if (mti->deformMatrices && !deformed) { continue; } - mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert); + if (mesh_eval == NULL) { + mesh_eval = BKE_mesh_copy_for_eval(mesh, true); + } + + mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert); deformed = 1; } } @@ -479,6 +510,10 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, MEM_freeN(origVerts); MEM_freeN(quats); + + if (mesh_eval != NULL) { + BKE_id_free(NULL, mesh_eval); + } } if (*deformmats == NULL) { diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 67b0aaffc4a..d81d250a305 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -142,7 +142,6 @@ void BKE_curve_free(Curve *cu) MEM_SAFE_FREE(cu->mat); MEM_SAFE_FREE(cu->str); MEM_SAFE_FREE(cu->strinfo); - MEM_SAFE_FREE(cu->bb); MEM_SAFE_FREE(cu->tb); } @@ -154,8 +153,6 @@ void BKE_curve_init(Curve *cu, const short curve_type) cu->type = curve_type; - cu->bb = BKE_boundbox_alloc_unit(); - if (cu->type == OB_FONT) { cu->flag |= CU_FRONT | CU_BACK; cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get(); @@ -204,7 +201,6 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const cu_dst->str = MEM_dupallocN(cu_src->str); cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); cu_dst->tb = MEM_dupallocN(cu_src->tb); - cu_dst->bb = MEM_dupallocN(cu_src->bb); cu_dst->batch_cache = NULL; if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { @@ -291,41 +287,6 @@ void BKE_curve_type_test(Object *ob) } } -void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3]) -{ - BoundBox *bb; - float min[3], max[3]; - float mloc[3], msize[3]; - - if (cu->bb == NULL) { - cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - } - bb = cu->bb; - - if (!r_loc) { - r_loc = mloc; - } - if (!r_size) { - r_size = msize; - } - - INIT_MINMAX(min, max); - if (!BKE_curve_minmax(cu, true, min, max)) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } - - mid_v3_v3v3(r_loc, min, max); - - r_size[0] = (max[0] - min[0]) / 2.0f; - r_size[1] = (max[1] - min[1]) / 2.0f; - r_size[2] = (max[2] - min[2]) / 2.0f; - - BKE_boundbox_init_from_minmax(bb, min, max); - - bb->flag &= ~BOUNDBOX_DIRTY; -} - BoundBox *BKE_curve_boundbox_get(Object *ob) { /* This is Object-level data access, @@ -349,13 +310,23 @@ BoundBox *BKE_curve_boundbox_get(Object *ob) void BKE_curve_texspace_calc(Curve *cu) { - float loc[3], size[3]; - int a; + if (cu->texflag & CU_AUTOSPACE) { + float min[3], max[3]; - BKE_curve_boundbox_calc(cu, loc, size); + INIT_MINMAX(min, max); + if (!BKE_curve_minmax(cu, true, min, max)) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } - if (cu->texflag & CU_AUTOSPACE) { - for (a = 0; a < 3; a++) { + float loc[3], size[3]; + mid_v3_v3v3(loc, min, max); + + size[0] = (max[0] - min[0]) / 2.0f; + size[1] = (max[1] - min[1]) / 2.0f; + size[2] = (max[2] - min[2]) / 2.0f; + + for (int a = 0; a < 3; a++) { if (size[a] == 0.0f) { size[a] = 1.0f; } @@ -369,27 +340,28 @@ void BKE_curve_texspace_calc(Curve *cu) copy_v3_v3(cu->loc, loc); copy_v3_v3(cu->size, size); - zero_v3(cu->rot); + + cu->texflag |= CU_AUTOSPACE_EVALUATED; } } -BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]) +void BKE_curve_texspace_ensure(Curve *cu) { - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + if ((cu->texflag & CU_AUTOSPACE) && !(cu->texflag & CU_AUTOSPACE_EVALUATED)) { BKE_curve_texspace_calc(cu); } +} + +void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_size[3]) +{ + BKE_curve_texspace_ensure(cu); if (r_loc) { copy_v3_v3(r_loc, cu->loc); } - if (r_rot) { - copy_v3_v3(r_rot, cu->rot); - } if (r_size) { copy_v3_v3(r_size, cu->size); } - - return cu->bb; } bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3]) @@ -5501,15 +5473,10 @@ void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve) BKE_curve_texspace_calc(curve); if (DEG_is_active(depsgraph)) { Curve *curve_orig = (Curve *)DEG_get_original_id(&curve->id); - BoundBox *bb = curve->bb; - if (bb != NULL) { - if (curve_orig->bb == NULL) { - curve_orig->bb = MEM_mallocN(sizeof(*curve_orig->bb), __func__); - } - *curve_orig->bb = *bb; + if (curve->texflag & CU_AUTOSPACE_EVALUATED) { + curve_orig->texflag |= CU_AUTOSPACE_EVALUATED; copy_v3_v3(curve_orig->loc, curve->loc); copy_v3_v3(curve_orig->size, curve->size); - copy_v3_v3(curve_orig->rot, curve->rot); } } } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index cbd3c91acc7..46f6a604eaa 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -624,7 +624,7 @@ void BKE_displist_fill(ListBase *dispbase, static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) { - const float z_up[3] = {0.0f, 0.0f, 1.0f}; + const float z_up[3] = {0.0f, 0.0f, -1.0f}; ListBase front, back; DispList *dl, *dlnew; float *fp, *fp1; @@ -703,7 +703,7 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis bevels_to_filledpoly(cu, dispbase); } else { - const float z_up[3] = {0.0f, 0.0f, 1.0f}; + const float z_up[3] = {0.0f, 0.0f, -1.0f}; BKE_displist_fill(dispbase, dispbase, z_up, false); } } @@ -1730,11 +1730,11 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) { if (a == 1) { fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase); - negate_v3_v3(bottom_no, bevp->dir); + copy_v3_v3(bottom_no, bevp->dir); } if (a == steps - 1) { fillBevelCap(nu, dlb, cur_data, &top_capbase); - copy_v3_v3(top_no, bevp->dir); + negate_v3_v3(top_no, bevp->dir); } } } diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c index 12e737bbaa8..2d71b847b5b 100644 --- a/source/blender/blenkernel/intern/editlattice.c +++ b/source/blender/blenkernel/intern/editlattice.c @@ -92,6 +92,21 @@ void BKE_editlattice_load(Object *obedit) lt = obedit->data; editlt = lt->editlatt->latt; + MEM_freeN(lt->def); + + lt->def = MEM_dupallocN(editlt->def); + + lt->flag = editlt->flag; + + lt->pntsu = editlt->pntsu; + lt->pntsv = editlt->pntsv; + lt->pntsw = editlt->pntsw; + + lt->typeu = editlt->typeu; + lt->typev = editlt->typev; + lt->typew = editlt->typew; + lt->actbp = editlt->actbp; + if (lt->editlatt->shapenr) { actkey = BLI_findlink(<->key->block, lt->editlatt->shapenr - 1); @@ -112,22 +127,6 @@ void BKE_editlattice_load(Object *obedit) bp++; } } - else { - MEM_freeN(lt->def); - - lt->def = MEM_dupallocN(editlt->def); - - lt->flag = editlt->flag; - - lt->pntsu = editlt->pntsu; - lt->pntsv = editlt->pntsv; - lt->pntsw = editlt->pntsw; - - lt->typeu = editlt->typeu; - lt->typev = editlt->typev; - lt->typew = editlt->typew; - lt->actbp = editlt->actbp; - } if (lt->dvert) { BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 866c494d354..d929c953b89 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -32,6 +32,8 @@ #include "BKE_editmesh.h" #include "BKE_cdderivedmesh.h" #include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate) { @@ -51,6 +53,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) *em_copy = *em; em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL; + em_copy->bb_cage = NULL; em_copy->derivedVertColor = NULL; em_copy->derivedVertColorLen = 0; @@ -151,6 +154,8 @@ void BKE_editmesh_free_derivedmesh(BMEditMesh *em) BKE_id_free(NULL, em->mesh_eval_final); } em->mesh_eval_cage = em->mesh_eval_final = NULL; + + MEM_SAFE_FREE(em->bb_cage); } /*does not free the BMEditMesh struct itself*/ @@ -257,3 +262,19 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em) BKE_editmesh_lnorspace_update(em); } } + +BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em) +{ + if (em->bb_cage == NULL) { + float min[3], max[3]; + INIT_MINMAX(min, max); + if (em->mesh_eval_cage) { + BKE_mesh_minmax(em->mesh_eval_cage, min, max); + } + + em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage"); + BKE_boundbox_init_from_minmax(em->bb_cage, min, max); + } + + return em->bb_cage; +} diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index 48c0258bf47..10499ae0b5c 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -821,7 +821,7 @@ static void fcm_noise_evaluate( FMod_Noise *data = (FMod_Noise *)fcm->data; float noise; - /* generate noise using good ol' Blender Noise + /* generate noise using good old Blender Noise * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1 * with evaltime being an integer (which happens when evaluating on frame by frame basis) */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index b55635560be..250e6ff6a7b 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -397,6 +397,9 @@ static void build_underline(Curve *cu, copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f); copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f); + /* Used by curve extrusion. */ + bp[0].radius = bp[1].radius = bp[2].radius = bp[3].radius = 1.0f; + nu2->bp = bp; BLI_addtail(nubase, nu2); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index bcac531a72b..9e1d6b6c428 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -427,9 +427,9 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; /* grid settings */ - ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */ - ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */ - gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */ + ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */ + ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */ + gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */ /* onion-skinning settings (datablock level) */ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); @@ -664,7 +664,7 @@ bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd) } /* make a copy of a given gpencil datablock */ -/* XXX: Should this be deprecated? */ +/* XXX: Should this be deprecated? */ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) { bGPdata *gpd_dst; @@ -1422,6 +1422,7 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) bGPdata *gpd = ob->data; MDeformVert *dvert = NULL; const int def_nr = BLI_findindex(&ob->defbase, defgroup); + const int totgrp = BLI_listbase_count(&ob->defbase); /* Remove points data */ if (gpd) { @@ -1436,9 +1437,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) defvert_remove_group(dvert, dw); } else { - /* reorganize weights in other strokes */ - for (int g = 0; g < gps->dvert->totweight; g++) { - dw = &dvert->dw[g]; + /* Reorganize weights for other groups after deleted one. */ + for (int g = 0; g < totgrp; g++) { + dw = defvert_find_index(dvert, g); if ((dw != NULL) && (dw->def_nr > def_nr)) { dw->def_nr--; } @@ -2020,7 +2021,10 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) { bGPDspoint *pt = &gps->points[i]; +<<<<<<< HEAD /* float pressure = 0.0f; */ +======= +>>>>>>> origin/master float sco[3] = {0.0f}; /* Do nothing if not enough points to smooth out */ diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 1750a389788..fe087256d25 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -340,6 +340,23 @@ bool BKE_gpencil_has_time_modifiers(Object *ob) return false; } +/* Check if exist transform stroke modifiers (to rotate sculpt or edit). */ +bool BKE_gpencil_has_transform_modifiers(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + /* Only if enabled in edit mode. */ + if (!GPENCIL_MODIFIER_EDIT(md, true) && GPENCIL_MODIFIER_ACTIVE(md, false)) { + if ((md->type == eGpencilModifierType_Armature) || (md->type == eGpencilModifierType_Hook) || + (md->type == eGpencilModifierType_Lattice) || + (md->type == eGpencilModifierType_Offset)) { + return true; + } + } + } + return false; +} + /* apply stroke modifiers */ void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 170cc230332..332549c6b47 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -569,7 +569,7 @@ Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exist char str[FILE_MAX], strtest[FILE_MAX]; STRNCPY(str, filepath); - BLI_path_abs(str, BKE_main_blendfile_path_from_global()); + BLI_path_abs(str, bmain->name); /* first search an identical filepath */ for (ima = bmain->images.first; ima; ima = ima->id.next) { @@ -1861,13 +1861,13 @@ static void stampdata( } } -/* Will always add prefix. */ static void stampdata_from_template(StampData *stamp_data, const Scene *scene, - const StampData *stamp_data_template) + const StampData *stamp_data_template, + bool do_prefix) { if (scene->r.stamp & R_STAMP_FILENAME) { - SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file); + SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", stamp_data_template->file); } else { stamp_data->file[0] = '\0'; @@ -1879,67 +1879,71 @@ static void stampdata_from_template(StampData *stamp_data, stamp_data->note[0] = '\0'; } if (scene->r.stamp & R_STAMP_DATE) { - SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date); + SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", stamp_data_template->date); } else { stamp_data->date[0] = '\0'; } if (scene->r.stamp & R_STAMP_MARKER) { - SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker); + SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", stamp_data_template->marker); } else { stamp_data->marker[0] = '\0'; } if (scene->r.stamp & R_STAMP_TIME) { - SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time); + SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", stamp_data_template->time); } else { stamp_data->time[0] = '\0'; } if (scene->r.stamp & R_STAMP_FRAME) { - SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame); + SNPRINTF(stamp_data->frame, do_prefix ? "Frame %s" : "%s", stamp_data_template->frame); } else { stamp_data->frame[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERA) { - SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera); + SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", stamp_data_template->camera); } else { stamp_data->camera[0] = '\0'; } if (scene->r.stamp & R_STAMP_CAMERALENS) { - SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens); + SNPRINTF( + stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", stamp_data_template->cameralens); } else { stamp_data->cameralens[0] = '\0'; } if (scene->r.stamp & R_STAMP_SCENE) { - SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene); + SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", stamp_data_template->scene); } else { stamp_data->scene[0] = '\0'; } if (scene->r.stamp & R_STAMP_SEQSTRIP) { - SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip); + SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", stamp_data_template->strip); } else { stamp_data->strip[0] = '\0'; } if (scene->r.stamp & R_STAMP_RENDERTIME) { - SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime); + SNPRINTF(stamp_data->rendertime, + do_prefix ? "RenderTime %s" : "%s", + stamp_data_template->rendertime); } else { stamp_data->rendertime[0] = '\0'; } if (scene->r.stamp & R_STAMP_MEMORY) { - SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory); + SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %s" : "%s", stamp_data_template->memory); } else { stamp_data->memory[0] = '\0'; } if (scene->r.stamp & R_STAMP_HOSTNAME) { - SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname); + SNPRINTF( + stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", stamp_data_template->hostname); } else { stamp_data->hostname[0] = '\0'; @@ -1991,11 +1995,12 @@ void BKE_image_stamp_buf(Scene *scene, display_device = scene->display_settings.display_device; display = IMB_colormanagement_display_get_named(display_device); + bool do_prefix = (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0; if (stamp_data_template == NULL) { - stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true); + stampdata(scene, camera, &stamp_data, do_prefix, true); } else { - stampdata_from_template(&stamp_data, scene, stamp_data_template); + stampdata_from_template(&stamp_data, scene, stamp_data_template, do_prefix); } /* TODO, do_versions */ @@ -5305,7 +5310,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) char str[FILE_MAX]; STRNCPY(str, iv->filepath); - BLI_path_abs(str, BKE_main_blendfile_path_from_global()); + BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index f3c0d5da6ee..f12999b033d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -32,6 +32,7 @@ #include "BKE_freestyle.h" #include "BKE_idprop.h" #include "BKE_layer.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_object.h" @@ -43,6 +44,7 @@ #include "DNA_object_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -55,9 +57,10 @@ #include "MEM_guardedalloc.h" /* Set of flags which are dependent on a collection settings. */ -static const short g_base_collection_flags = (BASE_VISIBLE | BASE_SELECTABLE | - BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER | - BASE_HOLDOUT | BASE_INDIRECT_ONLY); +static const short g_base_collection_flags = (BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER | + BASE_SELECTABLE | BASE_ENABLED_VIEWPORT | + BASE_ENABLED_RENDER | BASE_HOLDOUT | + BASE_INDIRECT_ONLY); /* prototype */ static void object_bases_iterator_next(BLI_Iterator *iter, const int flag); @@ -91,6 +94,7 @@ static Base *object_base_new(Object *ob) { Base *base = MEM_callocN(sizeof(Base), "Object Base"); base->object = ob; + base->local_view_bits = ~(0); if (ob->base_flag & BASE_SELECTED) { base->flag |= BASE_SELECTED; } @@ -652,7 +656,8 @@ static short layer_collection_sync(ViewLayer *view_layer, ListBase *new_object_bases, short parent_exclude, short parent_restrict, - short parent_layer_restrict) + short parent_layer_restrict, + unsigned short parent_local_collections_bits) { /* TODO: support recovery after removal of intermediate collections, reordering, .. * For local edits we can make editing operating do the appropriate thing, but for @@ -698,6 +703,13 @@ static short layer_collection_sync(ViewLayer *view_layer, lc->flag = parent_exclude; } + unsigned short local_collections_bits = parent_local_collections_bits & + lc->local_collections_bits; + + /* Tag linked collection as a weak reference so we keep the layer + * collection pointer on file load and remember exclude state. */ + id_lib_indirect_weak_link(&collection->id); + /* Collection restrict is inherited. */ short child_restrict = parent_restrict; short child_layer_restrict = parent_layer_restrict; @@ -713,7 +725,8 @@ static short layer_collection_sync(ViewLayer *view_layer, new_object_bases, lc->flag, child_restrict, - child_layer_restrict); + child_layer_restrict, + local_collections_bits); /* Layer collection exclude is not inherited. */ if (lc->flag & LAYER_COLLECTION_EXCLUDE) { @@ -724,9 +737,15 @@ static short layer_collection_sync(ViewLayer *view_layer, lc->runtime_flag = child_runtime_flag; } - if (((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) && + /* We separate restrict viewport and visible view layer because a layer collection can be + * hidden in the view layer yet (locally) visible in a viewport (if it is not restricted).*/ + if (child_restrict & COLLECTION_RESTRICT_VIEWPORT) { + lc->runtime_flag |= LAYER_COLLECTION_RESTRICT_VIEWPORT; + } + + if (((lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0) && ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0)) { - lc->runtime_flag |= LAYER_COLLECTION_VISIBLE; + lc->runtime_flag |= LAYER_COLLECTION_VISIBLE_VIEW_LAYER; } /* Sync objects, except if collection was excluded. */ @@ -735,6 +754,10 @@ static short layer_collection_sync(ViewLayer *view_layer, continue; } + /* Tag linked object as a weak reference so we keep the object + * base pointer on file load and remember hidden state. */ + id_lib_indirect_weak_link(&cob->ob->id); + void **base_p; Base *base; if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) { @@ -750,17 +773,18 @@ static short layer_collection_sync(ViewLayer *view_layer, else { /* Create new base. */ base = object_base_new(cob->ob); + base->local_collections_bits = local_collections_bits; *base_p = base; BLI_addtail(new_object_bases, base); } if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) { - base->flag_from_collection |= BASE_ENABLED_VIEWPORT; + base->flag_from_collection |= (BASE_ENABLED_VIEWPORT | BASE_VISIBLE_DEPSGRAPH); if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) { - base->flag_from_collection |= BASE_VISIBLE; - if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { - base->flag_from_collection |= BASE_SELECTABLE; - } + base->flag_from_collection |= BASE_VISIBLE_VIEWLAYER; + } + if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { + base->flag_from_collection |= BASE_SELECTABLE; } } @@ -827,7 +851,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) &new_object_bases, parent_exclude, parent_restrict, - parent_layer_restrict); + parent_layer_restrict, + ~(0)); /* Any remaining object bases are to be removed. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { @@ -957,7 +982,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { Base *base = BKE_view_layer_base_find(view_layer, cob->ob); - if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE)) { + if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { return true; } } @@ -1009,6 +1034,60 @@ void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool BKE_layer_collection_sync(scene, view_layer); } +bool BKE_base_is_visible(const View3D *v3d, const Base *base) +{ + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { + return false; + } + + if (v3d == NULL) { + return base->flag & BASE_VISIBLE_VIEWLAYER; + } + + if ((v3d->localvd) && ((v3d->local_view_uuid & base->local_view_bits) == 0)) { + return false; + } + + if (((1 << (base->object->type)) & v3d->object_type_exclude_viewport) != 0) { + return false; + } + + if (v3d->flag & V3D_LOCAL_COLLECTIONS) { + return (v3d->local_collections_uuid & base->local_collections_bits) != 0; + } + + return base->flag & BASE_VISIBLE_VIEWLAYER; +} + +bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Object *ob) +{ + BLI_assert(v3d != NULL); + + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + return false; + } + + if ((v3d->object_type_exclude_viewport & (1 << ob->type)) != 0) { + return false; + } + + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + return false; + } + + if ((v3d->flag & V3D_LOCAL_COLLECTIONS) && + ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) { + return false; + } + + /* If not using local view or local collection the object may still be in a hidden collection. */ + if (((v3d->localvd) == NULL) && ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) { + return (ob->base_flag & BASE_VISIBLE_VIEWLAYER) != 0; + } + + return true; +} + static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag) { lc->flag |= flag; @@ -1033,13 +1112,13 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int * If the collection or any of its parents is disabled, make it enabled. * Don't change the children disable state though. */ -void BKE_layer_collection_isolate(Scene *scene, - ViewLayer *view_layer, - LayerCollection *lc, - bool extend) +void BKE_layer_collection_isolate_global(Scene *scene, + ViewLayer *view_layer, + LayerCollection *lc, + bool extend) { LayerCollection *lc_master = view_layer->layer_collections.first; - bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE); + bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER); if (!extend) { /* Hide all collections . */ @@ -1123,7 +1202,9 @@ static void layer_collection_local_sync(ViewLayer *view_layer, } LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { - layer_collection_local_sync(view_layer, child, local_collections_uuid, visible); + if ((child->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + layer_collection_local_sync(view_layer, child, local_collections_uuid, visible); + } } } @@ -1144,9 +1225,9 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d) /** * Isolate the collection locally * - * Same as BKE_layer_collection_local_isolate but for a viewport + * Same as BKE_layer_collection_isolate_local but for a viewport */ -void BKE_layer_collection_local_isolate(ViewLayer *view_layer, +void BKE_layer_collection_isolate_local(ViewLayer *view_layer, View3D *v3d, LayerCollection *lc, bool extend) @@ -1417,12 +1498,12 @@ static void objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter) { - objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter) @@ -1459,7 +1540,7 @@ void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); if (iter->valid) { if (BKE_object_is_libdata((Object *)iter->current) == false) { // First object is valid (selectable and not libdata) -> all good. @@ -1476,7 +1557,7 @@ void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter) { // Search while there are objects and the one we have is not editable (editable = not libdata). do { - objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false); } @@ -1493,12 +1574,12 @@ void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter) void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in) { - objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED); + objects_iterator_begin(iter, data_in, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter) { - object_bases_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED); + object_bases_iterator_next(iter, BASE_VISIBLE_DEPSGRAPH | BASE_SELECTED); } void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter) @@ -1557,7 +1638,7 @@ void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_ data->object_type = base->object->type; } - if (!base_is_in_mode(data, base)) { + if (!(base_is_in_mode(data, base) && BKE_base_is_visible(data->v3d, base))) { BKE_view_layer_bases_in_mode_iterator_next(iter); } } @@ -1570,7 +1651,7 @@ void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter) if (base == data->base_active) { /* first step */ base = data->view_layer->object_bases.first; - if (base == data->base_active) { + if ((base == data->base_active) && BKE_base_is_visible(data->v3d, base)) { base = base->next; } } @@ -1579,7 +1660,8 @@ void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter) } while (base) { - if ((base != data->base_active) && base_is_in_mode(data, base)) { + if ((base != data->base_active) && base_is_in_mode(data, base) && + BKE_base_is_visible(data->v3d, base)) { iter->current = base; return; } @@ -1598,7 +1680,8 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter)) /* Evaluation */ /* Applies object's restrict flags on top of flags coming from the collection - * and stores those in base->flag. BASE_VISIBLE is based on viewport visibility. */ + * and stores those in base->flag. BASE_VISIBLE_DEPSGRAPH ignores viewport flags visibility + * (i.e., restriction and local collection). */ void BKE_base_eval_flags(Base *base) { /* Apply collection flags. */ @@ -1621,7 +1704,7 @@ void BKE_base_eval_flags(Base *base) * can change these again, but for tools we always want the viewport * visibility to be in sync regardless if depsgraph was evaluated. */ if (!(base->flag & BASE_ENABLED_VIEWPORT) || (base->flag & BASE_HIDDEN)) { - base->flag &= ~(BASE_VISIBLE | BASE_SELECTABLE); + base->flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_VISIBLE_VIEWLAYER | BASE_SELECTABLE); } /* Deselect unselectable objects. */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index bbee49e8150..909db9c7b52 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -165,12 +165,23 @@ void id_lib_extern(ID *id) BLI_assert(BKE_idcode_is_linkable(GS(id->name))); if (id->tag & LIB_TAG_INDIRECT) { id->tag &= ~LIB_TAG_INDIRECT; + id->flag &= ~LIB_INDIRECT_WEAK_LINK; id->tag |= LIB_TAG_EXTERN; id->lib->parent = NULL; } } } +void id_lib_indirect_weak_link(ID *id) +{ + if (id && ID_IS_LINKED(id)) { + BLI_assert(BKE_idcode_is_linkable(GS(id->name))); + if (id->tag & LIB_TAG_INDIRECT) { + id->flag |= LIB_INDIRECT_WEAK_LINK; + } + } +} + /** * Ensure we have a real user * @@ -1407,9 +1418,10 @@ void *BKE_id_new_nomain(const short type, const char *name) return id; } -void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag) +void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag) { ID *new_id = *r_newid; + int flag = orig_flag; const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0; @@ -1430,7 +1442,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag) } /* The id->flag bits to copy over. */ - const int copy_flag_mask = LIB_PRIVATE_DATA; + const int copy_idflag_mask = LIB_PRIVATE_DATA; if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { /* r_newid already contains pointer to allocated memory. */ @@ -1454,10 +1466,14 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag) memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset); } - new_id->flag = (new_id->flag & ~copy_flag_mask) | (id->flag & copy_flag_mask); + new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask); + + /* We do not want any handling of usercount in code duplicating the data here, we do that all + * at once in id_copy_libmanagement_cb() at the end. */ + const int copy_data_flag = orig_flag | LIB_ID_CREATE_NO_USER_REFCOUNT; if (id->properties) { - new_id->properties = IDP_CopyProperty_ex(id->properties, flag); + new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag); } /* XXX Again... We need a way to control what we copy in a much more refined way. @@ -1474,9 +1490,11 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag) /* the duplicate should get a copy of the animdata */ if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) { - BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0 || - is_private_id_data); - iat->adt = BKE_animdata_copy(bmain, iat->adt, flag); + /* Note that even though horrors like root nodetrees are not in bmain, the actions they use + * in their anim data *are* in bmain... super-mega-hooray. */ + BLI_assert((copy_data_flag & LIB_ID_COPY_ACTIONS) == 0 || + (copy_data_flag & LIB_ID_CREATE_NO_MAIN) == 0); + iat->adt = BKE_animdata_copy(bmain, iat->adt, copy_data_flag); } else { iat->adt = NULL; @@ -1764,6 +1782,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist) id->lib = NULL; id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN); + id->flag &= ~LIB_INDIRECT_WEAK_LINK; if (id_in_mainlist) { if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) { bmain->is_memfile_undo_written = false; @@ -1977,6 +1996,7 @@ void BKE_library_make_local(Main *bmain, if (id->lib == NULL) { id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); + id->flag &= ~LIB_INDIRECT_WEAK_LINK; } /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data * you don't want to be made local, used for appending data, diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 61f506a8a6c..45dbb4b6ec1 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -389,7 +389,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o if (ob->data == new_id) { switch (GS(new_id->name)) { case ID_ME: - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); break; case ID_CU: BKE_curve_type_test(ob); @@ -497,6 +497,7 @@ static void libblock_remap_data( if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { new_id->tag &= ~LIB_TAG_INDIRECT; + new_id->flag &= ~LIB_INDIRECT_WEAK_LINK; new_id->tag |= LIB_TAG_EXTERN; } diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index e03903c05e4..e6cfea6fb03 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -589,7 +589,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, (do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f, (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f}; - const float zvec[3] = {0.0f, 0.0f, 1.0f}; + const float zvec[3] = {0.0f, 0.0f, -1.0f}; MaskLayer *masklay; unsigned int masklay_index; MemArena *sf_arena; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index ae9c3400ace..ba139c654d3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -496,7 +496,6 @@ void BKE_mesh_clear_geometry(Mesh *mesh) CustomData_free(&mesh->ldata, mesh->totloop); CustomData_free(&mesh->pdata, mesh->totpoly); - MEM_SAFE_FREE(mesh->bb); MEM_SAFE_FREE(mesh->mselect); MEM_SAFE_FREE(mesh->edit_mesh); @@ -605,7 +604,6 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int me_dst->edit_mesh = NULL; me_dst->mselect = MEM_dupallocN(me_dst->mselect); - me_dst->bb = MEM_dupallocN(me_dst->bb); /* TODO Do we want to add flag to prevent this? */ if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { @@ -659,6 +657,31 @@ Mesh *BKE_mesh_new_nomain( return mesh; } +/* Copy user editable settings that we want to preserve through the modifier stack + * or operations where a mesh with new topology is created based on another mesh. */ +void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src) +{ + /* Copy general settings. */ + me_dst->editflag = me_src->editflag; + me_dst->flag = me_src->flag; + me_dst->smoothresh = me_src->smoothresh; + me_dst->remesh_voxel_size = me_src->remesh_voxel_size; + me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity; + me_dst->remesh_mode = me_src->remesh_mode; + + /* Copy texture space. */ + me_dst->texflag = me_src->texflag; + copy_v3_v3(me_dst->loc, me_src->loc); + copy_v3_v3(me_dst->size, me_src->size); + + /* Copy materials. */ + if (me_dst->mat != NULL) { + MEM_freeN(me_dst->mat); + } + me_dst->mat = MEM_dupallocN(me_src->mat); + me_dst->totcol = me_src->totcol; +} + Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, int verts_len, int edges_len, @@ -672,7 +695,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); - me_dst->mat = MEM_dupallocN(me_src->mat); me_dst->mselect = MEM_dupallocN(me_dst->mselect); me_dst->totvert = verts_len; @@ -682,8 +704,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->totpoly = polys_len; me_dst->cd_flag = me_src->cd_flag; - me_dst->editflag = me_src->editflag; - me_dst->texflag = me_src->texflag; + BKE_mesh_copy_settings(me_dst, me_src); CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); @@ -772,18 +793,24 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, }); } -Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params) +Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, + const struct BMeshToMeshParams *params, + const Mesh *me_settings) { BLI_assert(params->calc_object_remap == false); Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); BM_mesh_bm_to_me(NULL, bm, mesh, params); + BKE_mesh_copy_settings(mesh, me_settings); return mesh; } -Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra) +Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, + const CustomData_MeshMasks *cd_mask_extra, + const Mesh *me_settings) { Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); + BKE_mesh_copy_settings(mesh, me_settings); return mesh; } @@ -792,9 +819,10 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks */ Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em, const CustomData_MeshMasks *data_mask, - float (*vertexCos)[3]) + float (*vertexCos)[3], + const Mesh *me_settings) { - Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask); + Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask, me_settings); /* Use editmesh directly where possible. */ me->runtime.is_original = true; if (vertexCos) { @@ -811,50 +839,49 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local) BKE_id_make_local_generic(bmain, &me->id, true, lib_local); } -void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3]) +BoundBox *BKE_mesh_boundbox_get(Object *ob) { - BoundBox *bb; - float min[3], max[3]; - float mloc[3], msize[3]; - - if (me->bb == NULL) { - me->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - } - bb = me->bb; + /* This is Object-level data access, + * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ + if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { + Mesh *me = ob->data; + float min[3], max[3]; - if (!r_loc) { - r_loc = mloc; - } - if (!r_size) { - r_size = msize; - } + INIT_MINMAX(min, max); + if (!BKE_mesh_minmax(me, min, max)) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } - INIT_MINMAX(min, max); - if (!BKE_mesh_minmax(me, min, max)) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; + if (ob->runtime.bb == NULL) { + ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); + } + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); + ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; } - mid_v3_v3v3(r_loc, min, max); - - r_size[0] = (max[0] - min[0]) / 2.0f; - r_size[1] = (max[1] - min[1]) / 2.0f; - r_size[2] = (max[2] - min[2]) / 2.0f; - - BKE_boundbox_init_from_minmax(bb, min, max); - - bb->flag &= ~BOUNDBOX_DIRTY; + return ob->runtime.bb; } void BKE_mesh_texspace_calc(Mesh *me) { - float loc[3], size[3]; - int a; + if (me->texflag & ME_AUTOSPACE) { + float min[3], max[3]; - BKE_mesh_boundbox_calc(me, loc, size); + INIT_MINMAX(min, max); + if (!BKE_mesh_minmax(me, min, max)) { + min[0] = min[1] = min[2] = -1.0f; + max[0] = max[1] = max[2] = 1.0f; + } - if (me->texflag & ME_AUTOSPACE) { - for (a = 0; a < 3; a++) { + float loc[3], size[3]; + mid_v3_v3v3(loc, min, max); + + size[0] = (max[0] - min[0]) / 2.0f; + size[1] = (max[1] - min[1]) / 2.0f; + size[2] = (max[2] - min[2]) / 2.0f; + + for (int a = 0; a < 3; a++) { if (size[a] == 0.0f) { size[a] = 1.0f; } @@ -868,59 +895,33 @@ void BKE_mesh_texspace_calc(Mesh *me) copy_v3_v3(me->loc, loc); copy_v3_v3(me->size, size); - zero_v3(me->rot); + + me->texflag |= ME_AUTOSPACE_EVALUATED; } } -BoundBox *BKE_mesh_boundbox_get(Object *ob) +void BKE_mesh_texspace_ensure(Mesh *me) { - /* This is Object-level data access, - * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ - if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { - Mesh *me = ob->data; - float min[3], max[3]; - - INIT_MINMAX(min, max); - if (!BKE_mesh_minmax(me, min, max)) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } - - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); - } - BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); - ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; + if ((me->texflag & ME_AUTOSPACE) && !(me->texflag & ME_AUTOSPACE_EVALUATED)) { + BKE_mesh_texspace_calc(me); } - - return ob->runtime.bb; } -BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]) +void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3]) { - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } + BKE_mesh_texspace_ensure(me); if (r_loc) { copy_v3_v3(r_loc, me->loc); } - if (r_rot) { - copy_v3_v3(r_rot, me->rot); - } if (r_size) { copy_v3_v3(r_size, me->size); } - - return me->bb; } -void BKE_mesh_texspace_get_reference( - Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size) +void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size) { - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } + BKE_mesh_texspace_ensure(me); if (r_texflag != NULL) { *r_texflag = &me->texflag; @@ -928,9 +929,6 @@ void BKE_mesh_texspace_get_reference( if (r_loc != NULL) { *r_loc = me->loc; } - if (r_rot != NULL) { - *r_rot = me->rot; - } if (r_size != NULL) { *r_size = me->size; } @@ -938,14 +936,13 @@ void BKE_mesh_texspace_get_reference( void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) { - float *texloc, *texrot, *texsize; + float *texloc, *texsize; short *texflag; - if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) { + if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) { me->texflag = *texflag; copy_v3_v3(me->loc, texloc); copy_v3_v3(me->size, texsize); - copy_v3_v3(me->rot, texrot); } } @@ -974,7 +971,7 @@ void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int float loc[3], size[3]; int a; - BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size); + BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size); if (invert) { for (a = 0; a < totvert; a++) { @@ -1080,12 +1077,12 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) { Mesh *old = NULL; - multires_force_update(ob); - if (ob == NULL) { return; } + multires_force_sculpt_rebuild(ob); + if (ob->type == OB_MESH) { old = ob->data; if (old) { @@ -1949,9 +1946,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) { DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh); BKE_mesh_texspace_calc(mesh); - /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is - * (e.g. after modifiers, etc.) */ - mesh->texflag &= ~ME_AUTOSPACE; /* We are here because something did change in the mesh. This means we can not trust the existing * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the * evaluated mesh and let objects to re-create it with updated settings. */ @@ -1962,15 +1956,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) } if (DEG_is_active(depsgraph)) { Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); - BoundBox *bb = mesh->bb; - if (bb != NULL) { - if (mesh_orig->bb == NULL) { - mesh_orig->bb = MEM_mallocN(sizeof(*mesh_orig->bb), __func__); - } - *mesh_orig->bb = *bb; + if (mesh->texflag & ME_AUTOSPACE_EVALUATED) { + mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED; copy_v3_v3(mesh_orig->loc, mesh->loc); copy_v3_v3(mesh_orig->size, mesh->size); - copy_v3_v3(mesh_orig->rot, mesh->rot); } } } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 0a991ee36c8..2ade368284c 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -556,7 +556,7 @@ Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase) memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly)); if (alluv) { - const char *uvname = "Orco"; + const char *uvname = "UVMap"; CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname); } @@ -635,7 +635,7 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); if (alluv) { - const char *uvname = "Orco"; + const char *uvname = "UVMap"; me->mloopuv = CustomData_add_layer_named( &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); } @@ -667,7 +667,6 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, me->texflag = cu->texflag & ~CU_AUTOSPACE; copy_v3_v3(me->loc, cu->loc); copy_v3_v3(me->size, cu->size); - copy_v3_v3(me->rot, cu->rot); BKE_mesh_texspace_calc(me); cu->mat = NULL; @@ -1080,6 +1079,7 @@ static Mesh *mesh_new_from_mball_object(Object *object) Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); + BKE_mesh_texspace_copy_from_object(mesh_result, object); /* Copy materials. */ mesh_result->totcol = mball->totcol; @@ -1575,11 +1575,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, /* Clear selection history */ MEM_SAFE_FREE(tmp.mselect); tmp.totselect = 0; - BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb)); - if (mesh_dst->bb) { - MEM_freeN(mesh_dst->bb); - tmp.bb = NULL; - } + tmp.texflag &= ~ME_AUTOSPACE_EVALUATED; /* skip the listbase */ MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c index ff7ff947e1d..ba8ed5facad 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c @@ -38,6 +38,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_library.h" @@ -45,6 +46,8 @@ #include "BKE_bvhutils.h" #include "BKE_mesh_remesh_voxel.h" /* own include */ +#include "bmesh_tools.h" + #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif @@ -292,7 +295,10 @@ Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh, return new_mesh; } -Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size) +Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, + float voxel_size, + float adaptivity, + float isovalue) { Mesh *new_mesh = NULL; #ifdef WITH_OPENVDB @@ -300,11 +306,12 @@ Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size) struct OpenVDBTransform *xform = OpenVDBTransform_create(); OpenVDBTransform_create_linear_transform(xform, (double)voxel_size); level_set = BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(mesh, xform); - new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(level_set, 0.0, 0.0, false); + new_mesh = BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain( + level_set, (double)isovalue, (double)adaptivity, false); OpenVDBLevelSet_free(level_set); OpenVDBTransform_free(xform); #else - UNUSED_VARS(mesh, voxel_size); + UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue); #endif return new_mesh; } @@ -348,3 +355,112 @@ void BKE_remesh_reproject_paint_mask(Mesh *target, Mesh *source) } free_bvhtree_from_mesh(&bvhtree); } + +struct Mesh *BKE_mesh_remesh_voxel_fix_poles(struct Mesh *mesh) +{ + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); + BMesh *bm; + bm = BM_mesh_create(&allocsize, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + BM_mesh_bm_from_me(bm, + mesh, + (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, + })); + + BMVert *v; + BMEdge *ed, *ed_next; + BMFace *f, *f_next; + BMIter iter_a, iter_b; + + /* Merge 3 edge poles vertices that exist in the same face */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_ITER_MESH_MUTABLE (f, f_next, &iter_a, bm, BM_FACES_OF_MESH) { + BMVert *v1, *v2; + v1 = NULL; + v2 = NULL; + BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { + if (BM_vert_edge_count(v) == 3) { + if (v1) { + v2 = v; + } + else { + v1 = v; + } + } + } + if (v1 && v2 && (v1 != v2) && !BM_edge_exists(v1, v2)) { + BM_face_kill(bm, f); + BMEdge *e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NOP); + BM_elem_flag_set(e, BM_ELEM_TAG, true); + } + } + + BM_ITER_MESH_MUTABLE (ed, ed_next, &iter_a, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(ed, BM_ELEM_TAG)) { + float co[3]; + mid_v3_v3v3(co, ed->v1->co, ed->v2->co); + BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true); + copy_v3_v3(vc->co, co); + } + } + + /* Delete faces with a 3 edge pole in all their vertices */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) { + bool dissolve = true; + BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { + if (BM_vert_edge_count(v) != 3) { + dissolve = false; + } + } + if (dissolve) { + BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) { + BM_elem_flag_set(v, BM_ELEM_TAG, true); + } + } + } + BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS); + + BM_ITER_MESH (ed, &iter_a, bm, BM_EDGES_OF_MESH) { + if (BM_edge_face_count(ed) != 2) { + BM_elem_flag_set(ed, BM_ELEM_TAG, true); + } + } + BM_mesh_edgenet(bm, false, true); + + /* Smooth the result */ + for (int i = 0; i < 4; i++) { + BM_ITER_MESH (v, &iter_a, bm, BM_VERTS_OF_MESH) { + float co[3]; + zero_v3(co); + BM_ITER_ELEM (ed, &iter_b, v, BM_EDGES_OF_VERT) { + BMVert *vert = BM_edge_other_vert(ed, v); + add_v3_v3(co, vert->co); + } + mul_v3_fl(co, 1.0f / (float)BM_vert_edge_count(v)); + mid_v3_v3v3(v->co, v->co, co); + } + } + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_op_callf(bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "recalc_face_normals faces=%hf", + BM_ELEM_TAG); + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + Mesh *result = BKE_mesh_from_bmesh_nomain(bm, + (&(struct BMeshToMeshParams){ + .calc_object_remap = false, + }), + mesh); + + BKE_id_free(NULL, mesh); + BM_mesh_free(bm); + return result; +} diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index c8e75532075..fa03aec3e08 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -1619,6 +1619,12 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh) for (int i = 0; i < mesh->totloop; i++, ml++) { mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE; } + med = mesh->medge; + for (int i = 0; i < mesh->totedge; i++, med++) { + if (med->flag & ME_LOOSEEDGE) { + med->flag |= ME_EDGEDRAW; + } + } } /** diff --git a/source/blender/blenkernel/intern/mirror.c b/source/blender/blenkernel/intern/mirror.c new file mode 100644 index 00000000000..02e0a2bb3b9 --- /dev/null +++ b/source/blender/blenkernel/intern/mirror.c @@ -0,0 +1,419 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_math.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_mesh.h" +#include "BKE_mirror.h" +#include "BKE_modifier.h" +#include "BKE_deform.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_modifiertypes.h" + +Mesh *BKE_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd, + const Mesh *mesh, + int axis, + const float plane_co[3], + float plane_no[3]) +{ + bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) || + (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) || + (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z)); + + const float bisect_distance = 0.001f; + + Mesh *result; + BMesh *bm; + BMIter viter; + BMVert *v, *v_next; + + bm = BKE_mesh_to_bmesh_ex(mesh, + &(struct BMeshCreateParams){0}, + &(struct BMeshFromMeshParams){ + .calc_face_normal = true, + .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, + .emask = CD_MASK_ORIGINDEX, + .pmask = CD_MASK_ORIGINDEX}, + }); + + /* Define bisecting plane (aka mirror plane). */ + float plane[4]; + if (!do_bisect_flip_axis) { + /* That reversed condition is a tad weird, but for some reason that's how you keep + * the part of the mesh which is on the non-mirrored side when flip option is disabled, + * think that that is the expected behavior. */ + negate_v3(plane_no); + } + plane_from_point_normal_v3(plane, plane_co, plane_no); + + BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance); + + /* Plane definitions for vert killing. */ + float plane_offset[4]; + copy_v3_v3(plane_offset, plane); + plane_offset[3] = plane[3] - bisect_distance; + + /* Delete verts across the mirror plane. */ + BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { + if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { + BM_vert_kill(bm, v); + } + } + + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); + BM_mesh_free(bm); + + return result; +} + +Mesh *BKE_mirror_apply_mirror_on_axis(MirrorModifierData *mmd, + const ModifierEvalContext *UNUSED(ctx), + Object *ob, + const Mesh *mesh, + int axis) +{ + const float tolerance_sq = mmd->tolerance * mmd->tolerance; + const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; + int tot_vtargetmap = 0; /* total merge vertices */ + + const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) || + (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) || + (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z)); + + Mesh *result; + MVert *mv, *mv_prev; + MEdge *me; + MLoop *ml; + MPoly *mp; + float mtx[4][4]; + float plane_co[3], plane_no[3]; + int i; + int a, totshape; + int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; + + /* mtx is the mirror transformation */ + unit_m4(mtx); + mtx[axis][axis] = -1.0f; + + Object *mirror_ob = mmd->mirror_ob; + if (mirror_ob != NULL) { + float tmp[4][4]; + float itmp[4][4]; + + /* tmp is a transform from coords relative to the object's own origin, + * to coords relative to the mirror object origin */ + invert_m4_m4(tmp, mirror_ob->obmat); + mul_m4_m4m4(tmp, tmp, ob->obmat); + + /* itmp is the reverse transform back to origin-relative coordinates */ + invert_m4_m4(itmp, tmp); + + /* combine matrices to get a single matrix that translates coordinates into + * mirror-object-relative space, does the mirror, and translates back to + * origin-relative space */ + mul_m4_series(mtx, itmp, mtx, tmp); + + if (do_bisect) { + copy_v3_v3(plane_co, itmp[3]); + copy_v3_v3(plane_no, itmp[axis]); + } + } + else if (do_bisect) { + copy_v3_v3(plane_co, mtx[3]); + /* Need to negate here, since that axis is inverted (for mirror transform). */ + negate_v3_v3(plane_no, mtx[axis]); + } + + Mesh *mesh_bisect = NULL; + if (do_bisect) { + mesh_bisect = BKE_mirror_bisect_on_mirror_plane(mmd, mesh, axis, plane_co, plane_no); + mesh = mesh_bisect; + } + + const int maxVerts = mesh->totvert; + const int maxEdges = mesh->totedge; + const int maxLoops = mesh->totloop; + const int maxPolys = mesh->totpoly; + + result = BKE_mesh_new_nomain_from_template( + mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); + + /* Copy custom-data to original geometry. */ + CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); + CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); + CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); + CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); + + /* Subsurf for eg won't have mesh data in the custom-data arrays. + * now add mvert/medge/mpoly layers. */ + if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { + memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); + } + if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { + memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); + } + if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { + memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); + memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); + } + + /* Copy custom-data to new geometry, + * copy from its self because this data may have been created in the checks above. */ + CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); + CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); + /* loops are copied later */ + CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); + + if (do_vtargetmap) { + /* second half is filled with -1 */ + vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap"); + + vtmap_a = vtargetmap; + vtmap_b = vtargetmap + maxVerts; + } + + /* mirror vertex coordinates */ + mv_prev = result->mvert; + mv = mv_prev + maxVerts; + for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { + mul_m4_v3(mtx, mv->co); + + if (do_vtargetmap) { + /* compare location of the original and mirrored vertex, to see if they + * should be mapped for merging */ + if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { + *vtmap_a = maxVerts + i; + tot_vtargetmap++; + + /* average location */ + mid_v3_v3v3(mv->co, mv_prev->co, mv->co); + copy_v3_v3(mv_prev->co, mv->co); + } + else { + *vtmap_a = -1; + } + + *vtmap_b = -1; /* fill here to avoid 2x loops */ + + vtmap_a++; + vtmap_b++; + } + } + + /* handle shape keys */ + totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); + for (a = 0; a < totshape; a++) { + float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a); + for (i = maxVerts; i < result->totvert; i++) { + mul_m4_v3(mtx, cos[i]); + } + } + + /* adjust mirrored edge vertex indices */ + me = result->medge + maxEdges; + for (i = 0; i < maxEdges; i++, me++) { + me->v1 += maxVerts; + me->v2 += maxVerts; + } + + /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ + mp = result->mpoly + maxPolys; + ml = result->mloop; + for (i = 0; i < maxPolys; i++, mp++) { + MLoop *ml2; + int j, e; + + /* reverse the loop, but we keep the first vertex in the face the same, + * to ensure that quads are split the same way as on the other side */ + CustomData_copy_data( + &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1); + + for (j = 1; j < mp->totloop; j++) { + CustomData_copy_data(&result->ldata, + &result->ldata, + mp->loopstart + j, + mp->loopstart + maxLoops + mp->totloop - j, + 1); + } + + ml2 = ml + mp->loopstart + maxLoops; + e = ml2[0].e; + for (j = 0; j < mp->totloop - 1; j++) { + ml2[j].e = ml2[j + 1].e; + } + ml2[mp->totloop - 1].e = e; + + mp->loopstart += maxLoops; + } + + /* adjust mirrored loop vertex and edge indices */ + ml = result->mloop + maxLoops; + for (i = 0; i < maxLoops; i++, ml++) { + ml->v += maxVerts; + ml->e += maxEdges; + } + + /* handle uvs, + * let tessface recalc handle updating the MTFace data */ + if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || + (is_zero_v2(mmd->uv_offset_copy) == false)) { + const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; + const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; + + const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); + + for (a = 0; a < totuv; a++) { + MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a); + int j = maxLoops; + dmloopuv += j; /* second set of loops only */ + for (; j-- > 0; dmloopuv++) { + if (do_mirr_u) { + dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0]; + } + if (do_mirr_v) { + dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1]; + } + dmloopuv->uv[0] += mmd->uv_offset_copy[0]; + dmloopuv->uv[1] += mmd->uv_offset_copy[1]; + } + } + } + + /* handle custom split normals */ + if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && + CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) { + const int totloop = result->totloop; + const int totpoly = result->totpoly; + float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__); + CustomData *ldata = &result->ldata; + short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); + MLoopNorSpaceArray lnors_spacearr = {NULL}; + float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__); + + /* The transform matrix of a normal must be + * the transpose of inverse of transform matrix of the geometry... */ + float mtx_nor[4][4]; + invert_m4_m4(mtx_nor, mtx); + transpose_m4(mtx_nor); + + /* calculate custom normals into loop_normals, then mirror first half into second half */ + + BKE_mesh_calc_normals_poly(result->mvert, + NULL, + result->totvert, + result->mloop, + result->mpoly, + totloop, + totpoly, + poly_normals, + false); + + BKE_mesh_normals_loop_split(result->mvert, + result->totvert, + result->medge, + result->totedge, + result->mloop, + loop_normals, + totloop, + result->mpoly, + poly_normals, + totpoly, + true, + mesh->smoothresh, + &lnors_spacearr, + clnors, + NULL); + + /* mirroring has to account for loops being reversed in polys in second half */ + mp = result->mpoly; + for (i = 0; i < maxPolys; i++, mp++) { + MPoly *mpmirror = result->mpoly + maxPolys + i; + int j; + + for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) { + int mirrorj = mpmirror->loopstart; + if (j > mp->loopstart) { + mirrorj += mpmirror->totloop - (j - mp->loopstart); + } + copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); + mul_m4_v3(mtx_nor, loop_normals[mirrorj]); + BKE_lnor_space_custom_normal_to_data( + lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]); + } + } + + MEM_freeN(poly_normals); + MEM_freeN(loop_normals); + BKE_lnor_spacearr_free(&lnors_spacearr); + } + + /* handle vgroup stuff */ + if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { + MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) + + maxVerts; + int *flip_map = NULL, flip_map_len = 0; + + flip_map = defgroup_flip_map(ob, &flip_map_len, false); + + if (flip_map) { + for (i = 0; i < maxVerts; dvert++, i++) { + /* merged vertices get both groups, others get flipped */ + if (do_vtargetmap && (vtargetmap[i] != -1)) { + defvert_flip_merged(dvert, flip_map, flip_map_len); + } + else { + defvert_flip(dvert, flip_map, flip_map_len); + } + } + + MEM_freeN(flip_map); + } + } + + if (do_vtargetmap) { + /* slow - so only call if one or more merge verts are found, + * users may leave this on and not realize there is nothing to merge - campbell */ + if (tot_vtargetmap) { + result = BKE_mesh_merge_verts( + result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); + } + MEM_freeN(vtargetmap); + } + + if (mesh_bisect != NULL) { + BKE_id_free(NULL, mesh_bisect); + } + + return result; +} diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 656ec50f31b..1c83bec17e5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -761,6 +761,23 @@ Object *modifiers_isDeformedByCurve(Object *ob) return NULL; } +bool modifiers_usesMultires(Object *ob) +{ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + MultiresModifierData *mmd = NULL; + + for (; md; md = md->next) { + if (md->type == eModifierType_Multires) { + mmd = (MultiresModifierData *)md; + if (mmd->totlvl != 0) { + return true; + } + } + } + return false; +} + bool modifiers_usesArmature(Object *ob, bArmature *arm) { VirtualModifierData virtualModifierData; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index f67bc419210..9385a9ae24d 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -409,8 +409,8 @@ typedef struct MovieClipCache { /* cache for undistorted shot */ float principal[2]; - float polynomial_k1, polynomial_k2, polynomial_k3; - float division_k1, division_k2; + float polynomial_k1; + float division_k1; short distortion_model; bool undistortion_used; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 8cf960a7f14..6a5e31bd2a2 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -406,25 +406,38 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod multires_ccg_mark_as_modified(subdiv_ccg, flags); } -void multires_force_update(Object *ob) +void multires_flush_sculpt_updates(Object *ob) { - if (ob == NULL) { - return; - } - SculptSession *sculpt_session = ob->sculpt; - if (sculpt_session != NULL && sculpt_session->pbvh != NULL) { - PBVH *pbvh = sculpt_session->pbvh; - if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { + if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) { + SculptSession *sculpt_session = ob->sculpt; + if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS) { Mesh *mesh = ob->data; multiresModifier_reshapeFromCCG( sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); } - else { - /* NOTE: Disabled for until OpenSubdiv is enabled by default. */ - // BLI_assert(!"multires_force_update is used on non-grids PBVH"); + } +} + +void multires_force_sculpt_rebuild(Object *ob) +{ + multires_flush_sculpt_updates(ob); + + if (ob && ob->sculpt) { + SculptSession *ss = ob->sculpt; + if (ss->pbvh) { + BKE_pbvh_free(ss->pbvh); + ob->sculpt->pbvh = NULL; + } + + if (ss->pmap) { + MEM_freeN(ss->pmap); + ss->pmap = NULL; + } + + if (ss->pmap_mem) { + MEM_freeN(ss->pmap_mem); + ss->pmap_mem = NULL; } - BKE_pbvh_free(pbvh); - ob->sculpt->pbvh = NULL; } } @@ -433,14 +446,7 @@ void multires_force_external_reload(Object *ob) Mesh *me = BKE_mesh_from_object(ob); CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - multires_force_update(ob); -} - -void multires_force_render_update(Object *ob) -{ - if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires)) { - multires_force_update(ob); - } + multires_force_sculpt_rebuild(ob); } /* reset the multires levels to match the number of mdisps */ @@ -624,7 +630,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); if (mdisps && levels > 0) { if (lvl > 0) { @@ -689,7 +695,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); if (mdisps && levels > 0 && direction == 1) { multires_del_higher(mmd, ob, lvl); @@ -781,7 +787,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object float(*origco)[3]; int i, j, k, offset, totlvl; - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); me = BKE_mesh_from_object(ob); totlvl = mmd->totlvl; @@ -928,7 +934,7 @@ static void multires_subdivide( BLI_assert(totlvl > lvl); - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (!mdisps) { diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index 3257bc1b193..4e4a8831518 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -795,7 +795,7 @@ static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph, SubdivSettings subdiv_settings; BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh); - if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) { + if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh, NULL)) { BKE_subdiv_free(subdiv); return NULL; } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 2cc1083aba3..09581debd99 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1488,7 +1488,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) /* set default flags */ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ fcu->rna_path = BLI_strdupn("influence", 9); @@ -1515,7 +1515,7 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) /* set default flags */ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ fcu->rna_path = BLI_strdupn("strip_time", 10); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 6e45130ce44..779728cb037 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -947,6 +947,68 @@ void nodeChainIter(const bNodeTree *ntree, } } +static void iter_backwards_ex(const bNodeTree *ntree, + const bNode *node_start, + bool (*callback)(bNode *, bNode *, void *), + void *userdata, + char recursion_mask) +{ + LISTBASE_FOREACH (bNodeSocket *, sock, &node_start->inputs) { + bNodeLink *link = sock->link; + if (link == NULL) { + continue; + } + if ((link->flag & NODE_LINK_VALID) == 0) { + /* Skip links marked as cyclic. */ + continue; + } + if (link->fromnode->iter_flag & recursion_mask) { + continue; + } + else { + link->fromnode->iter_flag |= recursion_mask; + } + + if (!callback(link->fromnode, link->tonode, userdata)) { + return; + } + iter_backwards_ex(ntree, link->fromnode, callback, userdata, recursion_mask); + } +} + +/** + * Iterate over a chain of nodes, starting with \a node_start, executing + * \a callback for each node (which can return false to end iterator). + * + * Faster than nodeChainIter. Iter only once per node. + * Can be called recursively (using another nodeChainIterBackwards) by + * setting the recursion_lvl accordingly. + * + * \note Needs updated socket links (ntreeUpdateTree). + * \note Recursive + */ +void nodeChainIterBackwards(const bNodeTree *ntree, + const bNode *node_start, + bool (*callback)(bNode *, bNode *, void *), + void *userdata, + int recursion_lvl) +{ + if (!node_start) { + return; + } + + /* Limited by iter_flag type. */ + BLI_assert(recursion_lvl < 8); + char recursion_mask = (1 << recursion_lvl); + + /* Reset flag. */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + node->iter_flag &= ~recursion_mask; + } + + iter_backwards_ex(ntree, node_start, callback, userdata, recursion_mask); +} + /** * Iterate over all parents of \a node, executing \a callback for each parent * (which can return false to end iterator) @@ -3348,7 +3410,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree) return; } - /* avoid reentrant updates, can be caused by RNA update callbacks */ + /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ if (ntree->is_updating) { return; } @@ -3409,7 +3471,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree) void nodeUpdate(bNodeTree *ntree, bNode *node) { - /* avoid reentrant updates, can be caused by RNA update callbacks */ + /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ if (ntree->is_updating) { return; } @@ -3436,7 +3498,7 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id) return changed; } - /* avoid reentrant updates, can be caused by RNA update callbacks */ + /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ if (ntree->is_updating) { return changed; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 7b43f281c73..773e2d19b22 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -680,7 +680,7 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode) */ int BKE_object_visibility(const Object *ob, const int dag_eval_mode) { - if ((ob->base_flag & BASE_VISIBLE) == 0) { + if ((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return 0; } @@ -3269,8 +3269,7 @@ void BKE_object_sculpt_data_create(Object *ob) ob->sculpt->mode_type = ob->mode; } -int BKE_object_obdata_texspace_get( - Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot) +int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size) { if (ob->data == NULL) { @@ -3279,14 +3278,12 @@ int BKE_object_obdata_texspace_get( switch (GS(((ID *)ob->data)->name)) { case ID_ME: { - BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size); + BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_size); break; } case ID_CU: { Curve *cu = ob->data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } + BKE_curve_texspace_ensure(cu); if (r_texflag) { *r_texflag = &cu->texflag; } @@ -3296,9 +3293,6 @@ int BKE_object_obdata_texspace_get( if (r_size) { *r_size = cu->size; } - if (r_rot) { - *r_rot = cu->rot; - } break; } case ID_MB: { @@ -3312,9 +3306,6 @@ int BKE_object_obdata_texspace_get( if (r_size) { *r_size = mb->size; } - if (r_rot) { - *r_rot = mb->rot; - } break; } default: diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index b9c4adafab2..6b6c68b197e 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -401,12 +401,8 @@ static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Obj mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat); const MVert *mvert = me_eval->mvert; - const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); - - for (int i = 0, j = 0; i < me_eval->totvert; i++) { - if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) { - vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no); - } + for (int i = 0; i < me_eval->totvert; i++) { + vertex_dupli(vdd, i, mvert[i].co, mvert[i].no); } } diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c index b3ebe9b5ffa..be96927ed63 100644 --- a/source/blender/blenkernel/intern/object_facemap.c +++ b/source/blender/blenkernel/intern/object_facemap.c @@ -261,3 +261,41 @@ bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name) { return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name)); } + +int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len) +{ + /* Build src to merged mapping of facemap indices. */ + if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) { + *r_map_len = 0; + return NULL; + } + + *r_map_len = BLI_listbase_count(&ob_src->fmaps); + int *fmap_index_map = MEM_malloc_arrayN( + *r_map_len, sizeof(*fmap_index_map), "defgroup index map create"); + bool is_fmap_remap_needed = false; + + int i = 0; + for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) { + fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name); + is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i); + } + + if (!is_fmap_remap_needed) { + MEM_freeN(fmap_index_map); + fmap_index_map = NULL; + *r_map_len = 0; + } + + return fmap_index_map; +} + +void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len) +{ + if (map == NULL || map_len == 0) { + return; + } + for (int i = 0; i < fmap_len; i++, fmap++) { + *fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1; + } +} diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 01f3f2e309b..21ca5e6d6a6 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -439,10 +439,10 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, * assumed viewport visibility. Select-ability does not matter here. */ if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) { if (base->flag & BASE_ENABLED_RENDER) { - base->flag |= BASE_VISIBLE; + base->flag |= BASE_VISIBLE_DEPSGRAPH; } else { - base->flag &= ~BASE_VISIBLE; + base->flag &= ~BASE_VISIBLE_DEPSGRAPH; } } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 8e647757b40..5fa3352d497 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -141,7 +141,9 @@ int BKE_packedfile_count_all(Main *bmain) void BKE_packedfile_free(PackedFile *pf) { if (pf) { - MEM_freeN(pf->data); + BLI_assert(pf->data != NULL); + + MEM_SAFE_FREE(pf->data); MEM_freeN(pf); } else { @@ -151,6 +153,9 @@ void BKE_packedfile_free(PackedFile *pf) PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src) { + BLI_assert(pf_src != NULL); + BLI_assert(pf_src->data != NULL); + PackedFile *pf_dst; pf_dst = MEM_dupallocN(pf_src); @@ -161,6 +166,8 @@ PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src) PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen) { + BLI_assert(mem != NULL); + PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); pf->data = mem; pf->size = memlen; @@ -178,7 +185,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const /* render result has no filename and can be ignored * any other files with no name can be ignored too */ if (filename[0] == '\0') { - return NULL; + return pf; } // XXX waitcursor(1); @@ -260,7 +267,7 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose) } if (tot > 0) { - BKE_reportf(reports, RPT_INFO, "Packed %d files", tot); + BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot); } else if (verbose) { BKE_report(reports, RPT_INFO, "No new files have been packed"); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 5980aa456e2..cc9d1b98ba4 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -224,7 +224,6 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) return rna_enum_brush_image_tool_items; case PAINT_MODE_SCULPT_UV: return rna_enum_brush_uv_sculpt_tool_items; - return NULL; case PAINT_MODE_GPENCIL: return rna_enum_brush_gpencil_types_items; case PAINT_MODE_INVALID: @@ -992,10 +991,24 @@ static void sculptsession_free_pbvh(Object *object) { SculptSession *ss = object->sculpt; - if (ss && ss->pbvh) { + if (!ss) { + return; + } + + if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); ss->pbvh = NULL; } + + if (ss->pmap) { + MEM_freeN(ss->pmap); + ss->pmap = NULL; + } + + if (ss->pmap_mem) { + MEM_freeN(ss->pmap_mem); + ss->pmap_mem = NULL; + } } void BKE_sculptsession_bm_to_me_for_render(Object *object) @@ -1090,6 +1103,12 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob) return NULL; } + /* Weight paint operates on original vertices, and needs to treat multires as regular modifier + * to make it so that PBVH vertices are at the multires surface. */ + if ((ob->mode & OB_MODE_SCULPT) == 0) { + return NULL; + } + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) { if (md->type == eModifierType_Multires) { MultiresModifierData *mmd = (MultiresModifierData *)md; @@ -1135,7 +1154,10 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { continue; } - if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) { + if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) { + continue; + } + if (md->type == eModifierType_ShapeKey) { continue; } @@ -1162,7 +1184,7 @@ static void sculpt_update_object( Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); + ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0; ss->building_vp_handle = false; @@ -1183,10 +1205,11 @@ static void sculpt_update_object( /* tessfaces aren't used and will become invalid */ BKE_mesh_tessface_clear(me); - ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; + ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; - /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ - if (mmd && ob->mode & OB_MODE_SCULPT) { + /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, + * so no extra checks is needed here. */ + if (mmd) { ss->multires = mmd; ss->totvert = me_eval->totvert; ss->totpoly = me_eval->totpoly; @@ -1210,23 +1233,22 @@ static void sculpt_update_object( BLI_assert(pbvh == ss->pbvh); UNUSED_VARS_NDEBUG(pbvh); - MEM_SAFE_FREE(ss->pmap); - MEM_SAFE_FREE(ss->pmap_mem); - if (need_pmap && ob->type == OB_MESH) { + if (need_pmap && ob->type == OB_MESH && !ss->pmap) { BKE_mesh_vert_poly_map_create( &ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); } pbvh_show_mask_set(ss->pbvh, ss->show_mask); - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { if (!ss->orig_cos) { int a; BKE_sculptsession_free_deformMats(ss); - ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : - BKE_mesh_vert_coords_alloc(me, NULL); + ss->orig_cos = (ss->shapekey_active) ? + BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active) : + BKE_mesh_vert_coords_alloc(me, NULL); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); @@ -1240,15 +1262,15 @@ static void sculpt_update_object( BKE_sculptsession_free_deformMats(ss); } - if (ss->kb != NULL && ss->deform_cos == NULL) { - ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + if (ss->shapekey_active != NULL && ss->deform_cos == NULL) { + ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); } /* if pbvh is deformed, key block is already applied to it */ - if (ss->kb) { + if (ss->shapekey_active) { bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh); if (!pbvh_deformed || ss->deform_cos == NULL) { - float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (vertCos) { if (!pbvh_deformed) { @@ -1427,17 +1449,17 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush * stuff and show final evaluated mesh so user would see actual object shape. */ - deformed |= object->sculpt->modifiers_active; + deformed |= object->sculpt->deform_modifiers_active; if (for_construction) { - deformed |= object->sculpt->kb != NULL; + deformed |= object->sculpt->shapekey_active != NULL; } else { /* As in case with modifiers, we can't synchronize deformation made against * PBVH and non-locked keyblock, so also use PBVH only for brushes and * final DM to give final result to user. */ - deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0; + deformed |= object->sculpt->shapekey_active && (object->shapeflag & OB_SHAPE_LOCK) == 0; } return deformed; @@ -1467,6 +1489,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); BKE_pbvh_build_mesh(pbvh, + me, me->mpoly, me->mloop, me->mvert, @@ -1566,7 +1589,7 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d) if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { /* Regular mesh only draws from PBVH without modifiers and shape keys. */ const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID)); - return !(ss->kb || ss->modifiers_active || full_shading); + return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading); } else { /* Multires and dyntopo always draw directly from the PBVH. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 312b8f883df..74fbfc318a8 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4068,9 +4068,7 @@ void psys_get_texture( 0, texvec); - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } + BKE_mesh_texspace_ensure(me); sub_v3_v3(texvec, me->loc); if (me->size[0] != 0.0f) { texvec[0] /= me->size[0]; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 0eca4489309..01612ded396 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -27,6 +27,7 @@ #include "BLI_ghash.h" #include "BLI_task.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BKE_pbvh.h" @@ -51,8 +52,6 @@ #define STACK_FIXED_DEPTH 100 -#define PBVH_THREADED_LIMIT 4 - typedef struct PBVHStack { PBVHNode *node; bool revisiting; @@ -535,6 +534,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) * (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply(). */ void BKE_pbvh_build_mesh(PBVH *bvh, + const Mesh *mesh, const MPoly *mpoly, const MLoop *mloop, MVert *verts, @@ -547,6 +547,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh, BBC *prim_bbc = NULL; BB cb; + bvh->mesh = mesh; bvh->type = PBVH_FACES; bvh->mpoly = mpoly; bvh->mloop = mloop; @@ -990,6 +991,7 @@ typedef struct PBVHUpdateData { float (*vnors)[3]; int flag; + bool show_vcol; } PBVHUpdateData; static void pbvh_update_normals_accum_task_cb(void *__restrict userdata, @@ -1059,11 +1061,12 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata, const int v = verts[i]; MVert *mvert = &bvh->verts[v]; - /* mvert is shared between nodes, hence between threads. */ - if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) & - ME_VERT_PBVH_UPDATE) { + /* No atomics necessary because we are iterating over uniq_verts only, + * so we know only this thread will handle this vertex. */ + if (mvert->flag & ME_VERT_PBVH_UPDATE) { normalize_v3(vnors[v]); normal_float_to_short_v3(mvert->no, vnors[v]); + mvert->flag &= ~ME_VERT_PBVH_UPDATE; } } @@ -1093,17 +1096,65 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode) .vnors = vnors, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (totnode > PBVH_THREADED_LIMIT); - - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings); MEM_freeN(vnors); } +static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + + PBVHUpdateData *data = userdata; + PBVH *bvh = data->bvh; + PBVHNode *node = data->nodes[n]; + if (node->flag & PBVH_UpdateMask) { + + bool has_unmasked = false; + bool has_masked = true; + if (node->flag & PBVH_Leaf) { + PBVHVertexIter vd; + + BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_UNIQUE) + { + if (vd.mask && *vd.mask < 1.0f) { + has_unmasked = true; + } + if (vd.mask && *vd.mask > 0.0f) { + has_masked = false; + } + } + BKE_pbvh_vertex_iter_end; + } + else { + has_unmasked = true; + has_masked = true; + } + BKE_pbvh_node_fully_masked_set(node, !has_unmasked); + BKE_pbvh_node_fully_unmasked_set(node, has_masked); + + node->flag &= ~PBVH_UpdateMask; + } +} + +static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) +{ + PBVHUpdateData data = { + .bvh = bvh, + .nodes = nodes, + .flag = flag, + }; + + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings); +} + static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -1137,10 +1188,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) .flag = flag, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (totnode > PBVH_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) @@ -1151,71 +1201,106 @@ static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol) return update_flags; } -static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol) -{ - /* can't be done in parallel with OpenGL */ - for (int n = 0; n < totnode; n++) { - PBVHNode *node = nodes[n]; - - if (node->flag & PBVH_RebuildDrawBuffers) { - GPU_pbvh_buffers_free(node->draw_buffers); - switch (bvh->type) { - case PBVH_GRIDS: - node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden); - break; - case PBVH_FACES: - node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices, - bvh->mpoly, - bvh->mloop, - bvh->looptri, - bvh->verts, - node->prim_indices, - node->totprim); - break; - case PBVH_BMESH: - node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags & - PBVH_DYNTOPO_SMOOTH_SHADING); - break; - } - - node->flag &= ~PBVH_RebuildDrawBuffers; - } +static void pbvh_update_draw_buffer_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + /* Create and update draw buffers. The functions called here must not + * do any OpenGL calls. Flags are not cleared immediately, that happens + * after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */ + PBVHUpdateData *data = userdata; + PBVH *bvh = data->bvh; + PBVHNode *node = data->nodes[n]; - if (node->flag & PBVH_UpdateDrawBuffers) { - const int update_flags = pbvh_get_buffers_update_flags(bvh, show_vcol); - switch (bvh->type) { - case PBVH_GRIDS: - GPU_pbvh_grid_buffers_update(node->draw_buffers, - bvh->grids, - bvh->grid_flag_mats, - node->prim_indices, - node->totprim, - &bvh->gridkey, - update_flags); - break; - case PBVH_FACES: - GPU_pbvh_mesh_buffers_update(node->draw_buffers, - bvh->verts, - node->vert_indices, - node->uniq_verts + node->face_verts, - CustomData_get_layer(bvh->vdata, CD_PAINT_MASK), - CustomData_get_layer(bvh->ldata, CD_MLOOPCOL), - node->face_vert_indices, - update_flags); - break; - case PBVH_BMESH: - GPU_pbvh_bmesh_buffers_update(node->draw_buffers, - bvh->bm, - node->bm_faces, - node->bm_unique_verts, - node->bm_other_verts, - update_flags); - break; + if (node->flag & PBVH_RebuildDrawBuffers) { + switch (bvh->type) { + case PBVH_GRIDS: + node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden); + break; + case PBVH_FACES: + node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices, + bvh->mpoly, + bvh->mloop, + bvh->looptri, + bvh->verts, + node->prim_indices, + node->totprim, + bvh->mesh); + break; + case PBVH_BMESH: + node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags & + PBVH_DYNTOPO_SMOOTH_SHADING); + break; + } + } + + if (node->flag & PBVH_UpdateDrawBuffers) { + const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol); + switch (bvh->type) { + case PBVH_GRIDS: + GPU_pbvh_grid_buffers_update(node->draw_buffers, + bvh->grids, + bvh->grid_flag_mats, + node->prim_indices, + node->totprim, + &bvh->gridkey, + update_flags); + break; + case PBVH_FACES: + GPU_pbvh_mesh_buffers_update(node->draw_buffers, + bvh->verts, + node->vert_indices, + node->uniq_verts + node->face_verts, + CustomData_get_layer(bvh->vdata, CD_PAINT_MASK), + CustomData_get_layer(bvh->ldata, CD_MLOOPCOL), + node->face_vert_indices, + update_flags); + break; + case PBVH_BMESH: + GPU_pbvh_bmesh_buffers_update(node->draw_buffers, + bvh->bm, + node->bm_faces, + node->bm_unique_verts, + node->bm_other_verts, + update_flags); + break; + } + } +} + +static void pbvh_update_draw_buffers( + PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag) +{ + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) { + /* Free buffers uses OpenGL, so not in parallel. */ + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + if (node->flag & PBVH_RebuildDrawBuffers) { + GPU_pbvh_buffers_free(node->draw_buffers); + node->draw_buffers = NULL; + } + else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { + if (bvh->type == PBVH_GRIDS) { + GPU_pbvh_grid_buffers_update_free( + node->draw_buffers, bvh->grid_flag_mats, node->prim_indices); + } + else if (bvh->type == PBVH_BMESH) { + GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); + } } - - node->flag &= ~PBVH_UpdateDrawBuffers; } } + + /* Parallel creation and update of draw buffers. */ + PBVHUpdateData data = { + .bvh = bvh, + .nodes = nodes, + .show_vcol = show_vcol, + }; + + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings); } static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) @@ -1270,6 +1355,24 @@ void BKE_pbvh_update_bounds(PBVH *bvh, int flag) pbvh_flush_bb(bvh, bvh->nodes, flag); } + MEM_SAFE_FREE(nodes); +} + +void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag) +{ + if (!bvh->nodes) { + return; + } + + PBVHNode **nodes; + int totnode; + + BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode); + + if (flag & (PBVH_UpdateMask)) { + pbvh_update_mask_redraw(bvh, nodes, totnode, flag); + } + if (nodes) { MEM_freeN(nodes); } @@ -1378,19 +1481,24 @@ BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh) return bvh->grid_hidden; } -void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) +const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh) { BLI_assert(bvh->type == PBVH_GRIDS); - *key = bvh->gridkey; + return &bvh->gridkey; } -struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids) +struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh) { BLI_assert(bvh->type == PBVH_GRIDS); - *num_grids = bvh->totgrid; return bvh->grids; } +int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh) +{ + BLI_assert(bvh->type == PBVH_GRIDS); + return bvh->totgrid * bvh->gridkey.grid_area; +} + BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) { BLI_assert(bvh->type == PBVH_BMESH); @@ -1405,6 +1513,11 @@ void BKE_pbvh_node_mark_update(PBVHNode *node) PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } +void BKE_pbvh_node_mark_update_mask(PBVHNode *node) +{ + node->flag |= PBVH_UpdateMask | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; +} + void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node) { node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; @@ -1432,6 +1545,40 @@ void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) } } +void BKE_pbvh_node_fully_masked_set(PBVHNode *node, int fully_masked) +{ + BLI_assert(node->flag & PBVH_Leaf); + + if (fully_masked) { + node->flag |= PBVH_FullyMasked; + } + else { + node->flag &= ~PBVH_FullyMasked; + } +} + +bool BKE_pbvh_node_fully_masked_get(PBVHNode *node) +{ + return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyMasked); +} + +void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked) +{ + BLI_assert(node->flag & PBVH_Leaf); + + if (fully_masked) { + node->flag |= PBVH_FullyUnmasked; + } + else { + node->flag &= ~PBVH_FullyUnmasked; + } +} + +bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node) +{ + return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked); +} + void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, const int **r_vert_indices, @@ -1571,8 +1718,8 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, /** * \note doing a full search on all vertices here seems expensive, - * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU - * (which is far more expensive!) See: T47232. + * however this is important to avoid having to recalculate boundbox & sync the buffers to the + * GPU (which is far more expensive!) See: T47232. */ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node) { @@ -1761,14 +1908,11 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, const MVert *vert = bvh->verts; const MLoop *mloop = bvh->mloop; const int *faces = node->prim_indices; - int i, totface = node->totprim; + int totface = node->totprim; bool hit = false; - float min_depth = FLT_MAX; - float location[3] = {0.0f}; - float nearest_vertex_co[3]; - copy_v3_fl(nearest_vertex_co, 0.0f); + float nearest_vertex_co[3] = {0.0f}; - for (i = 0; i < totface; i++) { + for (int i = 0; i < totface; i++) { const MLoopTri *lt = &bvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; @@ -1776,35 +1920,33 @@ static bool pbvh_faces_node_raycast(PBVH *bvh, continue; } + const float *co[3]; if (origco) { /* intersect with backuped original coordinates */ - hit |= ray_face_intersection_tri(ray_start, - isect_precalc, - origco[face_verts[0]], - origco[face_verts[1]], - origco[face_verts[2]], - depth); + co[0] = origco[face_verts[0]]; + co[1] = origco[face_verts[1]]; + co[2] = origco[face_verts[2]]; } else { /* intersect with current coordinates */ - hit |= ray_face_intersection_tri(ray_start, - isect_precalc, - vert[mloop[lt->tri[0]].v].co, - vert[mloop[lt->tri[1]].v].co, - vert[mloop[lt->tri[2]].v].co, - depth); - - if (hit && *depth < min_depth) { - min_depth = *depth; - normal_tri_v3(r_face_normal, - vert[mloop[lt->tri[0]].v].co, - vert[mloop[lt->tri[1]].v].co, - vert[mloop[lt->tri[2]].v].co); + co[0] = vert[mloop[lt->tri[0]].v].co; + co[1] = vert[mloop[lt->tri[1]].v].co; + co[2] = vert[mloop[lt->tri[2]].v].co; + } + + if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) { + hit = true; + + if (r_face_normal) { + normal_tri_v3(r_face_normal, co[0], co[1], co[2]); + } + + if (r_active_vertex_index) { + float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, vert[mloop[lt->tri[j]].v].co) < - len_squared_v3v3(location, nearest_vertex_co)) { - copy_v3_v3(nearest_vertex_co, vert[mloop[lt->tri[j]].v].co); + if (len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, co[j]); *r_active_vertex_index = mloop[lt->tri[j]].v; } } @@ -1819,22 +1961,28 @@ static bool pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], const float ray_start[3], + const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, - float *depth) + float *depth, + int *r_active_vertex_index, + float *r_face_normal) { const int totgrid = node->totprim; const int gridsize = bvh->gridkey.grid_size; bool hit = false; + float nearest_vertex_co[3] = {0.0}; + const CCGKey *gridkey = &bvh->gridkey; for (int i = 0; i < totgrid; i++) { - CCGElem *grid = bvh->grids[node->prim_indices[i]]; + const int grid_index = node->prim_indices[i]; + CCGElem *grid = bvh->grids[grid_index]; BLI_bitmap *gh; if (!grid) { continue; } - gh = bvh->grid_hidden[node->prim_indices[i]]; + gh = bvh->grid_hidden[grid_index]; for (int y = 0; y < gridsize - 1; y++) { for (int x = 0; x < gridsize - 1; x++) { @@ -1845,23 +1993,40 @@ static bool pbvh_grids_node_raycast(PBVH *bvh, } } + const float *co[4]; if (origco) { - hit |= ray_face_intersection_quad(ray_start, - isect_precalc, - origco[y * gridsize + x], - origco[y * gridsize + x + 1], - origco[(y + 1) * gridsize + x + 1], - origco[(y + 1) * gridsize + x], - depth); + co[0] = origco[y * gridsize + x]; + co[1] = origco[y * gridsize + x + 1]; + co[2] = origco[(y + 1) * gridsize + x + 1]; + co[3] = origco[(y + 1) * gridsize + x]; } else { - hit |= ray_face_intersection_quad(ray_start, - isect_precalc, - CCG_grid_elem_co(&bvh->gridkey, grid, x, y), - CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y), - CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1), - CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1), - depth); + co[0] = CCG_grid_elem_co(gridkey, grid, x, y); + co[1] = CCG_grid_elem_co(gridkey, grid, x + 1, y); + co[2] = CCG_grid_elem_co(gridkey, grid, x + 1, y + 1); + co[3] = CCG_grid_elem_co(gridkey, grid, x, y + 1); + } + + if (ray_face_intersection_quad( + ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth)) { + hit = true; + + if (r_face_normal) { + normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]); + } + + if (r_active_vertex_index) { + float location[3] = {0.0}; + madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); + for (int j = 0; j < 4; j++) { + if (len_squared_v3v3(location, co[j]) < + len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, co[j]); + *r_active_vertex_index = gridkey->grid_area * grid_index + y * gridkey->grid_size + + x; + } + } + } } } } @@ -1904,7 +2069,15 @@ bool BKE_pbvh_node_raycast(PBVH *bvh, face_normal); break; case PBVH_GRIDS: - hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, isect_precalc, depth); + hit |= pbvh_grids_node_raycast(bvh, + node, + origco, + ray_start, + ray_normal, + isect_precalc, + depth, + active_vertex_index, + face_normal); break; case PBVH_BMESH: BM_mesh_elem_index_ensure(bvh->bm, BM_VERT); @@ -2167,16 +2340,18 @@ typedef enum { * Returns true if the AABB is at least partially within the frustum * (ok, not a real frustum), false otherwise. */ -static PlaneAABBIsect test_planes_aabb(const float bb_min[3], - const float bb_max[3], - const float (*planes)[4]) +static PlaneAABBIsect test_frustum_aabb(const float bb_min[3], + const float bb_max[3], + PBVHFrustumPlanes *frustum) { - float vmin[3], vmax[3]; PlaneAABBIsect ret = ISECT_INSIDE; + float(*planes)[4] = frustum->planes; + + for (int i = 0; i < frustum->num_planes; i++) { + float vmin[3], vmax[3]; - for (int i = 0; i < 4; i++) { for (int axis = 0; axis < 3; axis++) { - if (planes[i][axis] > 0) { + if (planes[i][axis] < 0) { vmin[axis] = bb_min[axis]; vmax[axis] = bb_max[axis]; } @@ -2186,10 +2361,10 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], } } - if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0) { + if (dot_v3v3(planes[i], vmin) + planes[i][3] < 0) { return ISECT_OUTSIDE; } - else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0) { + else if (dot_v3v3(planes[i], vmax) + planes[i][3] <= 0) { ret = ISECT_INTERSECT; } } @@ -2197,38 +2372,24 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], return ret; } -bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) +bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *data) { const float *bb_min, *bb_max; /* BKE_pbvh_node_get_BB */ bb_min = node->vb.bmin; bb_max = node->vb.bmax; - return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; + return test_frustum_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; } -bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) +bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data) { const float *bb_min, *bb_max; /* BKE_pbvh_node_get_BB */ bb_min = node->vb.bmin; bb_max = node->vb.bmax; - return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; -} - -typedef struct PBVHNodeDrawCallbackData { - void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers); - void *user_data; -} PBVHNodeDrawCallbackData; - -static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) -{ - PBVHNodeDrawCallbackData *data = data_v; - - if (!(node->flag & PBVH_FullyHidden)) { - data->draw_fn(data->user_data, node->draw_buffers); - } + return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg) @@ -2240,63 +2401,96 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg) BKE_pbvh_search_gather( bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode); - if (bvh->type == PBVH_BMESH) { - pbvh_bmesh_normals_update(nodes, totnode); - } - else if (bvh->type == PBVH_FACES) { - pbvh_faces_update_normals(bvh, nodes, totnode); - } - else if (bvh->type == PBVH_GRIDS) { - struct CCGFace **faces; - int num_faces; - BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces); - if (num_faces > 0) { - BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces); - MEM_freeN(faces); + if (totnode > 0) { + if (bvh->type == PBVH_BMESH) { + pbvh_bmesh_normals_update(nodes, totnode); + } + else if (bvh->type == PBVH_FACES) { + pbvh_faces_update_normals(bvh, nodes, totnode); + } + else if (bvh->type == PBVH_GRIDS) { + struct CCGFace **faces; + int num_faces; + BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces); + if (num_faces > 0) { + BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces); + MEM_freeN(faces); + } } } - if (nodes) { - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); +} + +/** + * PBVH drawing, updating draw buffers as needed and culling any nodes outside + * the specified frustum. + */ +typedef struct PBVHDrawSearchData { + PBVHFrustumPlanes *frustum; + int accum_update_flag; +} PBVHDrawSearchData; + +static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v) +{ + PBVHDrawSearchData *data = data_v; + if (data->frustum && !BKE_pbvh_node_frustum_contain_AABB(node, data->frustum)) { + return false; } + + data->accum_update_flag |= node->flag; + return true; } -void BKE_pbvh_update_draw_buffers(PBVH *bvh, bool show_vcol) +void BKE_pbvh_draw_cb(PBVH *bvh, + bool show_vcol, + bool update_only_visible, + PBVHFrustumPlanes *frustum, + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), + void *user_data) { - /* Update GPU buffers */ PBVHNode **nodes; int totnode; - BKE_pbvh_search_gather( - bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateDrawBuffers), &nodes, &totnode); + const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; - pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol); + if (!update_only_visible) { + /* Update all draw buffers, also those outside the view. */ + BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode); - if (nodes) { - MEM_freeN(nodes); + if (totnode) { + pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag); + } + + MEM_SAFE_FREE(nodes); } -} -/** - * Version of #BKE_pbvh_draw that runs a callback. - */ -void BKE_pbvh_draw_cb(PBVH *bvh, - float (*planes)[4], - void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), - void *user_data) -{ - PBVHNodeDrawCallbackData draw_data = { - .draw_fn = draw_fn, - .user_data = user_data, - }; + /* Gather visible nodes. */ + PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0}; + BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode); - if (planes) { - BKE_pbvh_search_callback( - bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data); + if (update_only_visible && (data.accum_update_flag & update_flag)) { + /* Update draw buffers in visible nodes. */ + pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag); } - else { - BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data); + + /* Draw. */ + for (int a = 0; a < totnode; a++) { + PBVHNode *node = nodes[a]; + + if (node->flag & PBVH_UpdateDrawBuffers) { + /* Flush buffers uses OpenGL, so not in parallel. */ + GPU_pbvh_buffers_update_flush(node->draw_buffers); + } + + node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); + + if (!(node->flag & PBVH_FullyHidden)) { + draw_fn(user_data, node->draw_buffers); + } } + + MEM_SAFE_FREE(nodes); } void BKE_pbvh_draw_debug_cb( @@ -2494,7 +2688,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids); BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); - vi->key = &bvh->gridkey; + vi->key = bvh->gridkey; vi->grids = grids; vi->grid_indices = grid_indices; @@ -2546,3 +2740,11 @@ void pbvh_show_mask_set(PBVH *bvh, bool show_mask) { bvh->show_mask = show_mask; } + +void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings, + bool use_threading, + int totnode) +{ + memset(settings, 0, sizeof(*settings)); + settings->use_threading = use_threading && totnode > 1; +} diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index c04e172f116..6d38ae13994 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -1516,10 +1516,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, float *r_face_normal) { bool hit = false; - - float min_depth = FLT_MAX; float nearest_vertex_co[3] = {0.0f}; - float location[3] = {0.0f}; + if (use_original && node->bm_tot_ortri) { for (int i = 0; i < node->bm_tot_ortri; i++) { const int *t = node->bm_ortri[i]; @@ -1542,18 +1540,24 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, BMVert *v_tri[3]; BM_face_as_array_vert_tri(f, v_tri); - hit |= ray_face_intersection_tri( - ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth); - - if (hit && *depth < min_depth) { - min_depth = *depth; - normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); - madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); - for (int j = 0; j < 3; j++) { - if (len_squared_v3v3(location, v_tri[j]->co) < - len_squared_v3v3(location, nearest_vertex_co)) { - copy_v3_v3(nearest_vertex_co, v_tri[j]->co); - *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + + if (ray_face_intersection_tri( + ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) { + hit = true; + + if (r_face_normal) { + normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); + } + + if (r_active_vertex_index) { + float location[3] = {0.0f}; + madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); + for (int j = 0; j < 3; j++) { + if (len_squared_v3v3(location, v_tri[j]->co) < + len_squared_v3v3(location, nearest_vertex_co)) { + copy_v3_v3(nearest_vertex_co, v_tri[j]->co); + *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + } } } } @@ -1974,7 +1978,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, if (mode & PBVH_Collapse) { EdgeQueue q; - BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP); + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = { &q, queue_pool, @@ -1993,7 +1997,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, if (mode & PBVH_Subdivide) { EdgeQueue q; - BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP); + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); EdgeQueueContext eq_ctx = { &q, queue_pool, diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index bad103743eb..bdee05f1aab 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -127,6 +127,7 @@ struct PBVH { int leaf_limit; /* Mesh data */ + const struct Mesh *mesh; MVert *verts; const MPoly *mpoly; const MLoop *mloop; diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenkernel/intern/pbvh_parallel.cc new file mode 100644 index 00000000000..aa4c659c8bd --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_parallel.cc @@ -0,0 +1,145 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_task.h" +#include "BLI_threads.h" + +#include "BKE_pbvh.h" + +#include "atomic_ops.h" + +#ifdef WITH_TBB + +# include <tbb/tbb.h> + +/* Functor for running TBB parallel_for and parallel_reduce. */ +struct PBVHTask { + PBVHParallelRangeFunc func; + void *userdata; + const PBVHParallelSettings *settings; + + void *userdata_chunk; + + /* Root constructor. */ + PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings) + : func(func), userdata(userdata), settings(settings) + { + init_chunk(settings->userdata_chunk); + } + + /* Copy constructor. */ + PBVHTask(const PBVHTask &other) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(other.userdata_chunk); + } + + /* Splitting constructor for parallel reduce. */ + PBVHTask(PBVHTask &other, tbb::split) + : func(other.func), userdata(other.userdata), settings(other.settings) + { + init_chunk(settings->userdata_chunk); + } + + ~PBVHTask() + { + MEM_SAFE_FREE(userdata_chunk); + } + + void init_chunk(void *from_chunk) + { + if (from_chunk) { + userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask"); + memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size); + } + else { + userdata_chunk = NULL; + } + } + + void operator()(const tbb::blocked_range<int> &r) const + { + TaskParallelTLS tls; + tls.thread_id = get_thread_id(); + tls.userdata_chunk = userdata_chunk; + for (int i = r.begin(); i != r.end(); ++i) { + func(userdata, i, &tls); + } + } + + void join(const PBVHTask &other) + { + settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk); + } + + int get_thread_id() const + { + /* Get a unique thread ID for texture nodes. In the future we should get rid + * of the thread ID and change texture evaluation to not require per-thread + * storage that can't be efficiently allocated on the stack. */ + static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1); + static int pbvh_thread_id_counter = 0; + + int &thread_id = pbvh_thread_id.local(); + if (thread_id == -1) { + thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1); + if (thread_id >= BLENDER_MAX_THREADS) { + BLI_assert(!"Maximum number of threads exceeded for sculpting"); + thread_id = thread_id % BLENDER_MAX_THREADS; + } + } + return thread_id; + } +}; + +#endif + +void BKE_pbvh_parallel_range(const int start, + const int stop, + void *userdata, + PBVHParallelRangeFunc func, + const struct PBVHParallelSettings *settings) +{ +#ifdef WITH_TBB + /* Multithreading. */ + if (settings->use_threading) { + PBVHTask task(func, userdata, settings); + + if (settings->func_reduce) { + parallel_reduce(tbb::blocked_range<int>(start, stop), task); + if (settings->userdata_chunk) { + memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size); + } + } + else { + parallel_for(tbb::blocked_range<int>(start, stop), task); + } + + return; + } +#endif + + /* Single threaded. Nothing to reduce as everything is accumulated into the + * main userdata chunk directly. */ + TaskParallelTLS tls; + tls.thread_id = 0; + tls.userdata_chunk = settings->userdata_chunk; + for (int i = start; i < stop; i++) { + func(userdata, i, &tls); + } +} diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 514f000d73d..c57808f3dee 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -51,6 +51,7 @@ #include "BKE_collection.h" #include "BKE_effect.h" +#include "BKE_global.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -61,7 +62,6 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" #ifdef WITH_BULLET -# include "BKE_global.h" # include "BKE_library.h" # include "BKE_library_query.h" #endif @@ -174,13 +174,22 @@ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw) /* free physics references */ if (is_orig) { if (rbo->shared->physics_object) { - BLI_assert(rbw); - if (rbw) { + if (rbw != NULL) { /* We can only remove the body from the world if the world is known. * The world is generally only unknown if it's an evaluated copy of * an object that's being freed, in which case this code isn't run anyway. */ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); } + else { + /* We have no access to 'owner' RBW when deleting the object ID itself... No choice bu to + * loop over all scenes then. */ + for (Scene *scene = G_MAIN->scenes.first; scene != NULL; scene = scene->id.next) { + RigidBodyWorld *scene_rbw = scene->rigidbody_world; + if (scene_rbw != NULL) { + RB_dworld_remove_body(scene_rbw->shared->physics_world, rbo->shared->physics_object); + } + } + } RB_body_delete(rbo->shared->physics_object); rbo->shared->physics_object = NULL; @@ -1415,7 +1424,7 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R return true; } -void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) +void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob, const bool free_us) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyCon *rbc; @@ -1438,8 +1447,13 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, obt) { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; - if (ELEM(ob, rbc->ob1, rbc->ob2)) { - BKE_rigidbody_remove_constraint(scene, obt); + if (rbc->ob1 == ob) { + rbc->ob1 = NULL; + DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE); + } + if (rbc->ob2 == ob) { + rbc->ob2 = NULL; + DEG_id_tag_update(&obt->id, ID_RECALC_COPY_ON_WRITE); } } } @@ -1454,7 +1468,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) * when we remove them from RB simulation. */ BKE_collection_object_add(bmain, scene->master_collection, ob); } - BKE_collection_object_remove(bmain, rbw->group, ob, false); + BKE_collection_object_remove(bmain, rbw->group, ob, free_us); } /* remove object's settings */ @@ -1468,15 +1482,24 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob) DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } -void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyCon *rbc = ob->rigidbody_constraint; - /* remove from rigidbody world, free object won't do this */ - if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + if (rbw != NULL) { + /* Remove from RBW constraints collection. */ + if (rbw->constraints != NULL) { + BKE_collection_object_remove(bmain, rbw->constraints, ob, free_us); + DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE); + } + + /* remove from rigidbody world, free object won't do this */ + if (rbw->shared->physics_world && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } } + /* remove object's settings */ BKE_rigidbody_free_constraint(ob); @@ -1657,9 +1680,12 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph, float ctime = DEG_get_ctime(depsgraph); /* update world */ - if (rebuild) { - BKE_rigidbody_validate_sim_world(scene, rbw, true); + /* Note physics_world can get NULL when undoing the deletion of the last object in it (see + * T70667). */ + if (rebuild || rbw->shared->physics_world == NULL) { + BKE_rigidbody_validate_sim_world(scene, rbw, rebuild); } + rigidbody_update_sim_world(scene, rbw); /* XXX TODO For rebuild: remove all constraints first. @@ -2086,10 +2112,10 @@ bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, R return false; } -void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) +void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob, const bool free_us) { } -void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +void BKE_rigidbody_remove_constraint(Main *bmain, Scene *scene, Object *ob, const bool free_us) { } void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 855e0c58e16..2d5061db487 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -345,6 +345,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons flag_subdata); } + if (sce_src->display.shading.prop) { + sce_dst->display.shading.prop = IDP_CopyProperty(sce_src->display.shading.prop); + } + BKE_sound_reset_scene_runtime(sce_dst); /* Copy sequencer, this is local data! */ @@ -1072,19 +1076,19 @@ Object *BKE_scene_camera_switch_find(Scene *scene) } #endif -int BKE_scene_camera_switch_update(Scene *scene) +bool BKE_scene_camera_switch_update(Scene *scene) { #ifdef DURIAN_CAMERA_SWITCH Object *camera = BKE_scene_camera_switch_find(scene); - if (camera) { + if (camera && (camera != scene->camera)) { scene->camera = camera; DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - return 1; + return true; } #else (void)scene; #endif - return 0; + return false; } char *BKE_scene_find_marker_name(Scene *scene, int frame) @@ -1140,15 +1144,18 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in return (delta_prev < delta_next) ? second_prev : second_next; } -void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob) +void BKE_scene_remove_rigidbody_object(struct Main *bmain, + Scene *scene, + Object *ob, + const bool free_us) { /* remove rigid body constraint from world before removing object */ if (ob->rigidbody_constraint) { - BKE_rigidbody_remove_constraint(scene, ob); + BKE_rigidbody_remove_constraint(bmain, scene, ob, free_us); } /* remove rigid body object from world before removing object */ if (ob->rigidbody_object) { - BKE_rigidbody_remove_object(bmain, scene, ob); + BKE_rigidbody_remove_object(bmain, scene, ob, free_us); } } @@ -1738,6 +1745,8 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl switch (unit_type) { case B_UNIT_LENGTH: + case B_UNIT_VELOCITY: + case B_UNIT_ACCELERATION: return value * (double)unit->scale_length; case B_UNIT_AREA: case B_UNIT_POWER: diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index eb4fc6994a9..ccb1869ee21 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -241,10 +241,11 @@ static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCac * This can happen because only FINAL_OUT item insertion will trigger recycling * but that is also the point, where prefetch can be suspended. * - * We could use temp cache as a shield and later untemp entry, + * We could use temp cache as a shield and later make it a non-temporary entry, * but it is not worth of increasing system complexity. */ - if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) { + if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && + BKE_sequencer_prefetch_job_is_running(scene)) { int pfjob_start, pfjob_end; BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end); @@ -319,7 +320,7 @@ static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base) } } -SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) +static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) { SeqCache *cache = seq_cache_get_from_scene(scene); SeqCacheKey *finalkey = NULL; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index dbdaaaa5fc3..236fb43e89c 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -3822,7 +3822,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user) char path[FILE_MAX]; STRNCPY(path, data->text_font->name); BLI_assert(BLI_thread_is_main()); - BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&data->text_font->id)); data->text_blf_id = BLF_load(path); } diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index a7543881dad..57b8c92de3e 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" +#include "DNA_mask_types.h" #include "DNA_sequence_types.h" #include "DNA_scene_types.h" @@ -1044,7 +1045,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, frame_offset = seq->start; } else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ { - frame_offset = 0; + frame_offset = ((Mask *)smd->mask_id)->sfra; } ImBuf *mask = modifier_mask_get(smd, context, cfra, frame_offset, ibuf->rect_float != NULL); diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c index 172db70823a..6dd1c47407f 100644 --- a/source/blender/blenkernel/intern/seqprefetch.c +++ b/source/blender/blenkernel/intern/seqprefetch.c @@ -31,6 +31,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_anim_types.h" #include "BLI_listbase.h" #include "BLI_threads.h" @@ -55,6 +56,7 @@ typedef struct PrefetchJob { struct PrefetchJob *next, *prev; struct Main *bmain; + struct Main *bmain_eval; struct Scene *scene; struct Scene *scene_eval; struct Depsgraph *depsgraph; @@ -109,7 +111,7 @@ static PrefetchJob *seq_prefetch_job_get(Scene *scene) return NULL; } -static bool seq_prefetch_job_is_running(Scene *scene) +bool BKE_sequencer_prefetch_job_is_running(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); @@ -185,12 +187,12 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob) static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob) { DEG_evaluate_on_framechange( - pfjob->bmain, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched); + pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched); } static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob) { - Main *bmain = pfjob->bmain; + Main *bmain = pfjob->bmain_eval; Scene *scene = pfjob->scene; ViewLayer *view_layer = BKE_view_layer_default_render(scene); @@ -198,7 +200,7 @@ static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob) DEG_debug_name_set(pfjob->depsgraph, "SEQUENCER PREFETCH"); /* Make sure there is a correct evaluated scene pointer. */ - DEG_graph_build_for_render_pipeline(pfjob->depsgraph, pfjob->bmain, scene, view_layer); + DEG_graph_build_for_render_pipeline(pfjob->depsgraph, bmain, scene, view_layer); /* Update immediately so we have proper evaluated scene. */ seq_prefetch_update_depsgraph(pfjob); @@ -229,7 +231,9 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob) } } -/* Use also to update scene and context changes */ +/* Use also to update scene and context changes + * This function should almost always be called by cache invalidation, not directly. + */ void BKE_sequencer_prefetch_stop(Scene *scene) { PrefetchJob *pfjob; @@ -251,7 +255,7 @@ static void seq_prefetch_update_context(const SeqRenderData *context) PrefetchJob *pfjob; pfjob = seq_prefetch_job_get(context->scene); - BKE_sequencer_new_render_data(pfjob->bmain, + BKE_sequencer_new_render_data(pfjob->bmain_eval, pfjob->depsgraph, pfjob->scene_eval, context->rectx, @@ -314,6 +318,7 @@ void BKE_sequencer_prefetch_free(Scene *scene) BLI_mutex_end(&pfjob->prefetch_suspend_mutex); BLI_condition_end(&pfjob->prefetch_suspend_cond); seq_prefetch_free_depsgraph(pfjob); + BKE_main_free(pfjob->bmain_eval); MEM_freeN(pfjob); scene->ed->prefetch_job = NULL; } @@ -322,16 +327,26 @@ static void *seq_prefetch_frames(void *job) { PrefetchJob *pfjob = (PrefetchJob *)job; - /* set to NULL before return! */ - pfjob->scene_eval->ed->prefetch_job = pfjob; + while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) { + pfjob->scene_eval->ed->prefetch_job = NULL; - while (pfjob->cfra + pfjob->num_frames_prefetched < pfjob->scene->r.efra) { - BKE_animsys_evaluate_all_animation(pfjob->context_cpy.bmain, - pfjob->context_cpy.depsgraph, - pfjob->context_cpy.scene, - pfjob->cfra + pfjob->num_frames_prefetched); + AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id); + BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene, + &pfjob->context_cpy.scene->id, + adt, + pfjob->cfra + pfjob->num_frames_prefetched, + ADT_RECALC_ALL, + false); seq_prefetch_update_depsgraph(pfjob); + /* This is quite hacky solution: + * We need cross-reference original scene with copy for cache. + * However depsgraph must not have this data, because it will try to kill this job. + * Scene copy don't reference original scene. Perhaps, this could be done by depsgraph. + * Set to NULL before return! + */ + pfjob->scene_eval->ed->prefetch_job = pfjob; + ImBuf *ibuf = BKE_sequencer_give_ibuf( &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0); BKE_sequencer_cache_free_temp_cache( @@ -371,10 +386,9 @@ static void *seq_prefetch_frames(void *job) return 0; } -PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) +static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) { - PrefetchJob *pfjob; - pfjob = seq_prefetch_job_get(context->scene); + PrefetchJob *pfjob = seq_prefetch_job_get(context->scene); if (!pfjob) { if (context->scene->ed) { @@ -386,6 +400,7 @@ PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) BLI_condition_init(&pfjob->prefetch_suspend_cond); pfjob->bmain = context->bmain; + pfjob->bmain_eval = BKE_main_new(); pfjob->scene = context->scene; seq_prefetch_init_depsgraph(pfjob); @@ -419,7 +434,7 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa if (!context->is_prefetch_render && !context->is_proxy_render) { bool playing = seq_prefetch_is_playing(context->bmain); bool scrubbing = seq_prefetch_is_scrubbing(context->bmain); - bool running = seq_prefetch_job_is_running(scene); + bool running = BKE_sequencer_prefetch_job_is_running(scene); seq_prefetch_resume(scene); /* conditions to start: * prefetch enabled, prefetch not running, not scrubbing, @@ -437,7 +452,7 @@ bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene) { bool playing = seq_prefetch_is_playing(bmain); bool scrubbing = seq_prefetch_is_scrubbing(bmain); - bool running = seq_prefetch_job_is_running(scene); + bool running = BKE_sequencer_prefetch_job_is_running(scene); bool suspended = seq_prefetch_job_is_waiting(scene); /* force redraw, when prefetching and using cache view. */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 2e36982f7d8..26dd9aab511 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3340,7 +3340,8 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr /* anim-data */ adt = BKE_animdata_from_id(&mask->id); - BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata( + context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false); maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__); @@ -4349,6 +4350,7 @@ static void sequence_invalidate_cache(Scene *scene, } sequence_do_invalidate_dependent(scene, seq, &ed->seqbase); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); BKE_sequencer_prefetch_stop(scene); } @@ -5543,7 +5545,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad Strip *strip; seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ /* basic defaults */ seq->len = seq_load->len ? seq_load->len : 1; @@ -5702,7 +5704,9 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->views_format = seq_load->views_format; } seq->flag |= seq_load->flag & SEQ_USE_VIEWS; - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + + seq->type = SEQ_TYPE_MOVIE; + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ for (i = 0; i < totfiles; i++) { if (anim_arr[i]) { diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 992ceda7b74..6f755aa6460 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -866,9 +866,9 @@ static bool target_project_solve_point_tri(const float *vtri_co[3], { float x[3], tmp[3]; float dist = sqrtf(hit_dist_sq); - float epsilon = dist * 1.0e-5f; - - CLAMP_MIN(epsilon, 1.0e-5f); + float magnitude_estimate = dist + len_manhattan_v3(vtri_co[0]) + len_manhattan_v3(vtri_co[1]) + + len_manhattan_v3(vtri_co[2]); + float epsilon = magnitude_estimate * 1.0e-6f; /* Initial solution vector: barycentric weights plus distance along normal. */ interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co); @@ -929,7 +929,7 @@ static bool update_hit(BVHTreeNearest *nearest, if (dist_sq < nearest->dist_sq) { #ifdef TRACE_TARGET_PROJECT printf( - "===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq); + "#=#=#> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq); #endif nearest->index = index; nearest->dist_sq = dist_sq; @@ -1088,14 +1088,14 @@ void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, if (type == MOD_SHRINKWRAP_TARGET_PROJECT) { #ifdef TRACE_TARGET_PROJECT - printf("====== TARGET PROJECT START ======\n"); + printf("\n====== TARGET PROJECT START ======\n"); #endif BLI_bvhtree_find_nearest_ex( tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER); #ifdef TRACE_TARGET_PROJECT - printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq); + printf("====== TARGET PROJECT END: %d %g ======\n\n", nearest->index, nearest->dist_sq); #endif if (nearest->index < 0) { @@ -1260,7 +1260,10 @@ static void shrinkwrap_snap_with_side(float r_point_co[3], float forcesign, bool forcesnap) { - float dist = len_v3v3(point_co, hit_co); + float delta[3]; + sub_v3_v3v3(delta, point_co, hit_co); + + float dist = len_v3(delta); /* If exactly on the surface, push out along normal */ if (dist < FLT_EPSILON) { @@ -1273,13 +1276,28 @@ static void shrinkwrap_snap_with_side(float r_point_co[3], } /* Move to the correct side if needed */ else { - float delta[3]; - sub_v3_v3v3(delta, point_co, hit_co); - float dsign = signf(dot_v3v3(delta, hit_no) * forcesign); + float dsign = signf(dot_v3v3(delta, hit_no)); + + if (forcesign == 0.0f) { + forcesign = dsign; + } /* If on the wrong side or too close, move to correct */ - if (forcesnap || dsign * dist < goal_dist) { - interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist); + if (forcesnap || dsign * dist * forcesign < goal_dist) { + mul_v3_fl(delta, dsign / dist); + + /* At very small distance, blend in the hit normal to stabilize math. */ + float dist_epsilon = (fabsf(goal_dist) + len_manhattan_v3(hit_co)) * 1e-4f; + + if (dist < dist_epsilon) { +#ifdef TRACE_TARGET_PROJECT + printf("zero_factor %g = %g / %g\n", dist / dist_epsilon, dist, dist_epsilon); +#endif + + interp_v3_v3v3(delta, hit_no, delta, dist / dist_epsilon); + } + + madd_v3_v3v3fl(r_point_co, hit_co, delta, goal_dist * forcesign); } else { copy_v3_v3(r_point_co, point_co); @@ -1304,13 +1322,13 @@ void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree, const float point_co[3], float r_point_co[3]) { - float dist, tmp[3]; + float tmp[3]; switch (mode) { /* Offsets along the line between point_co and hit_co. */ case MOD_SHRINKWRAP_ON_SURFACE: - if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) { - interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist); + if (goal_dist != 0) { + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, 0, true); } else { copy_v3_v3(r_point_co, hit_co); @@ -1506,3 +1524,38 @@ void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C, MEM_freeN(vertexCos); } + +void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target) +{ + ShrinkwrapModifierData ssmd = {0}; + int totvert; + + ssmd.target = ob_target; + ssmd.shrinkType = MOD_SHRINKWRAP_TARGET_PROJECT; + ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE; + ssmd.keepDist = 0.0f; + ssmd.projLimit = target_me->remesh_voxel_size; + + float(*vertexCos)[3] = BKE_mesh_vert_coords_alloc(src_me, &totvert); + + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + + calc.smd = &ssmd; + calc.numVerts = src_me->totvert; + calc.vertexCos = vertexCos; + calc.vgroup = -1; + calc.target = target_me; + calc.keepDist = ssmd.keepDist; + BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target); + + ShrinkwrapTreeData tree; + if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) { + calc.tree = &tree; + TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); + BKE_shrinkwrap_free_tree(&tree); + } + + BKE_mesh_vert_coords_apply(src_me, vertexCos); + + MEM_freeN(vertexCos); +} diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 74873db179d..3db51c95fcb 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2527,17 +2527,13 @@ static void update_flowsfluids( } /* sample subframes */ else { -# if 0 int scene_frame = (int)DEG_get_ctime(depsgraph); -# endif // float scene_subframe = scene->r.subframe; // UNUSED int subframe; for (subframe = 0; subframe <= subframes; subframe++) { EmissionMap em_temp = {NULL}; float sample_size = 1.0f / (float)(subframes + 1); -# if 0 float prev_frame_pos = sample_size * (float)(subframe + 1); -# endif float sdt = dt * sample_size; int hires_multiplier = 1; @@ -2545,8 +2541,6 @@ static void update_flowsfluids( hires_multiplier = sds->amplify + 1; } - /* TODO: setting the scene frame no longer works with the new depsgraph. */ -# if 0 /* set scene frame to match previous frame + subframe * or use current frame for last sample */ if (subframe < subframes) { @@ -2557,7 +2551,6 @@ static void update_flowsfluids( scene->r.cfra = scene_frame; scene->r.subframe = 0.0f; } -# endif if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { /* emit_from_particles() updates timestep internally */ @@ -2569,8 +2562,13 @@ static void update_flowsfluids( else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ /* update flow object frame */ BLI_mutex_lock(&object_update_lock); - BKE_object_modifier_update_subframe( - depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke); + BKE_object_modifier_update_subframe(depsgraph, + scene, + collob, + true, + 5, + BKE_scene_frame_get(scene), + eModifierType_Smoke); BLI_mutex_unlock(&object_update_lock); /* apply flow */ @@ -3352,14 +3350,16 @@ struct Mesh *smokeModifier_do( if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain && smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) { result = createDomainGeometry(smd->domain, ob); + BKE_mesh_copy_settings(result, me); } else { result = BKE_mesh_copy_for_eval(me, false); } - /* XXX This is really not a nice hack, but until root of the problem is understood, - * this should be an acceptable workaround I think. - * See T58492 for details on the issue. */ - result->texflag |= ME_AUTOSPACE; + + /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the + * original mesh. So recompute it at this point in the modifier stack. See T58492. */ + BKE_mesh_texspace_calc(result); + return result; } diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index d346d4d6f8d..8654c50a783 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -129,6 +129,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) const int num_grids = topology_refiner_count_face_corners(topology_refiner); const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level); const int grid_area = grid_size * grid_size; + subdiv_ccg->grid_element_size = element_size; subdiv_ccg->num_grids = num_grids; subdiv_ccg->grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"); subdiv_ccg->grids_storage = MEM_calloc_arrayN( @@ -169,11 +170,11 @@ typedef struct CCGEvalGridsData { SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator; } CCGEvalGridsData; -static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data, - const int ptex_face_index, - const float u, - const float v, - unsigned char *element) +static void subdiv_ccg_eval_grid_element_limit(CCGEvalGridsData *data, + const int ptex_face_index, + const float u, + const float v, + unsigned char *element) { Subdiv *subdiv = data->subdiv; SubdivCCG *subdiv_ccg = data->subdiv_ccg; @@ -191,16 +192,35 @@ static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data, else { BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, (float *)element); } - if (subdiv_ccg->has_mask) { - float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset); - if (data->mask_evaluator != NULL) { - *mask_value_ptr = data->mask_evaluator->eval_mask( - data->mask_evaluator, ptex_face_index, u, v); - } - else { - *mask_value_ptr = 0.0f; - } +} + +static void subdiv_ccg_eval_grid_element_mask(CCGEvalGridsData *data, + const int ptex_face_index, + const float u, + const float v, + unsigned char *element) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + if (!subdiv_ccg->has_mask) { + return; + } + float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset); + if (data->mask_evaluator != NULL) { + *mask_value_ptr = data->mask_evaluator->eval_mask(data->mask_evaluator, ptex_face_index, u, v); } + else { + *mask_value_ptr = 0.0f; + } +} + +static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data, + const int ptex_face_index, + const float u, + const float v, + unsigned char *element) +{ + subdiv_ccg_eval_grid_element_limit(data, ptex_face_index, u, v, element); + subdiv_ccg_eval_grid_element_mask(data, ptex_face_index, u, v, element); } static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_index) @@ -366,25 +386,33 @@ static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg, const int subdiv_ccg->num_adjacent_edges, sizeof(*subdiv_ccg->adjacent_edges), "ccg adjacent edges"); } +static SubdivCCGCoord subdiv_ccg_coord(int grid_index, int x, int y) +{ + SubdivCCGCoord coord = {.grid_index = grid_index, .x = x, .y = y}; + return coord; +} + +static CCGElem *subdiv_ccg_coord_to_elem(const CCGKey *key, + const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + return CCG_grid_elem(key, subdiv_ccg->grids[coord->grid_index], coord->x, coord->y); +} + /* Returns storage where boundary elements are to be stored. */ -static CCGElem **subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg, - SubdivCCGAdjacentEdge *adjacent_edge, - SubdivCCGFace *face) +static SubdivCCGCoord *subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg, + SubdivCCGAdjacentEdge *adjacent_edge) { const int grid_size = subdiv_ccg->grid_size * 2; const int adjacent_face_index = adjacent_edge->num_adjacent_faces; ++adjacent_edge->num_adjacent_faces; - /* Store new adjacent face. */ - adjacent_edge->faces = MEM_reallocN( - adjacent_edge->faces, adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces)); - adjacent_edge->faces[adjacent_face_index] = face; /* Allocate memory for the boundary elements. */ - adjacent_edge->boundary_elements = MEM_reallocN(adjacent_edge->boundary_elements, - adjacent_edge->num_adjacent_faces * - sizeof(*adjacent_edge->boundary_elements)); - adjacent_edge->boundary_elements[adjacent_face_index] = MEM_malloc_arrayN( - grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary"); - return adjacent_edge->boundary_elements[adjacent_face_index]; + adjacent_edge->boundary_coords = MEM_reallocN(adjacent_edge->boundary_coords, + adjacent_edge->num_adjacent_faces * + sizeof(*adjacent_edge->boundary_coords)); + adjacent_edge->boundary_coords[adjacent_face_index] = MEM_malloc_arrayN( + grid_size * 2, sizeof(SubdivCCGCoord), "ccg adjacent boundary"); + return adjacent_edge->boundary_coords[adjacent_face_index]; } static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) @@ -404,9 +432,6 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) StaticOrHeapIntStorage face_edges_storage; static_or_heap_storage_init(&face_vertices_storage); static_or_heap_storage_init(&face_edges_storage); - /* Key to access elements. */ - CCGKey key; - BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); /* Store adjacency for all faces. */ const int num_faces = subdiv_ccg->num_faces; for (int face_index = 0; face_index < num_faces; face_index++) { @@ -428,34 +453,32 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) const bool is_edge_flipped = (edge_vertices[0] != vertex_index); /* Grid which is adjacent to the current corner. */ const int current_grid_index = face->start_grid_index + corner; - CCGElem *current_grid = subdiv_ccg->grids[current_grid_index]; /* Grid which is adjacent to the next corner. */ const int next_grid_index = face->start_grid_index + (corner + 1) % num_face_grids; - CCGElem *next_grid = subdiv_ccg->grids[next_grid_index]; /* Add new face to the adjacent edge. */ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index]; - CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face( - subdiv_ccg, adjacent_edge, face); + SubdivCCGCoord *boundary_coords = subdiv_ccg_adjacent_edge_add_face(subdiv_ccg, + adjacent_edge); /* Fill CCG elements along the edge. */ int boundary_element_index = 0; if (is_edge_flipped) { for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, next_grid, grid_size - i - 1, grid_size - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + next_grid_index, grid_size - i - 1, grid_size - 1); } for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, current_grid, grid_size - 1, i); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + current_grid_index, grid_size - 1, i); } } else { for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, current_grid, grid_size - 1, grid_size - i - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + current_grid_index, grid_size - 1, grid_size - i - 1); } for (int i = 0; i < grid_size; i++) { - boundary_elements[boundary_element_index++] = CCG_grid_elem( - &key, next_grid, i, grid_size - 1); + boundary_coords[boundary_element_index++] = subdiv_ccg_coord( + next_grid_index, i, grid_size - 1); } } } @@ -475,21 +498,16 @@ static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg, const i /* Returns storage where corner elements are to be stored. This is a pointer * to the actual storage. */ -static CCGElem **subdiv_ccg_adjacent_vertex_add_face(SubdivCCGAdjacentVertex *adjacent_vertex, - SubdivCCGFace *face) +static SubdivCCGCoord *subdiv_ccg_adjacent_vertex_add_face( + SubdivCCGAdjacentVertex *adjacent_vertex) { const int adjacent_face_index = adjacent_vertex->num_adjacent_faces; ++adjacent_vertex->num_adjacent_faces; - /* Store new adjacent face. */ - adjacent_vertex->faces = MEM_reallocN(adjacent_vertex->faces, - adjacent_vertex->num_adjacent_faces * - sizeof(*adjacent_vertex->faces)); - adjacent_vertex->faces[adjacent_face_index] = face; /* Allocate memory for the boundary elements. */ - adjacent_vertex->corner_elements = MEM_reallocN(adjacent_vertex->corner_elements, - adjacent_vertex->num_adjacent_faces * - sizeof(*adjacent_vertex->corner_elements)); - return &adjacent_vertex->corner_elements[adjacent_face_index]; + adjacent_vertex->corner_coords = MEM_reallocN(adjacent_vertex->corner_coords, + adjacent_vertex->num_adjacent_faces * + sizeof(*adjacent_vertex->corner_coords)); + return &adjacent_vertex->corner_coords[adjacent_face_index]; } static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg) @@ -522,11 +540,10 @@ static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg) const int vertex_index = face_vertices[corner]; /* Grid which is adjacent to the current corner. */ const int grid_index = face->start_grid_index + corner; - CCGElem *grid = subdiv_ccg->grids[grid_index]; /* Add new face to the adjacent edge. */ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[vertex_index]; - CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex, face); - *corner_element = CCG_grid_elem(&key, grid, grid_size - 1, grid_size - 1); + SubdivCCGCoord *corner_coord = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex); + *corner_coord = subdiv_ccg_coord(grid_index, grid_size - 1, grid_size - 1); } } /* Free possibly heap-allocated storage. */ @@ -572,9 +589,9 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv, { /* Make sure evaluator is ready. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); - if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) { + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) { if (coarse_mesh->totpoly) { - return false; + return NULL; } } BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); @@ -619,17 +636,15 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg) for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) { SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i]; for (int face_index = 0; face_index < adjacent_edge->num_adjacent_faces; face_index++) { - MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]); + MEM_SAFE_FREE(adjacent_edge->boundary_coords[face_index]); } - MEM_SAFE_FREE(adjacent_edge->faces); - MEM_SAFE_FREE(adjacent_edge->boundary_elements); + MEM_SAFE_FREE(adjacent_edge->boundary_coords); } MEM_SAFE_FREE(subdiv_ccg->adjacent_edges); /* Free map of adjacent vertices. */ for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) { SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[i]; - MEM_SAFE_FREE(adjacent_vertex->faces); - MEM_SAFE_FREE(adjacent_vertex->corner_elements); + MEM_SAFE_FREE(adjacent_vertex->corner_coords); } MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices); MEM_freeN(subdiv_ccg); @@ -1032,7 +1047,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg, } for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { for (int i = 1; i < grid_size2 - 1; i++) { - CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]); element_accumulator_add(&tls->accumulators[i], subdiv_ccg, key, grid_element); } } @@ -1042,7 +1058,8 @@ static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg, /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { for (int i = 1; i < grid_size2 - 1; i++) { - CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_edge->boundary_coords[face_index][i]); element_accumulator_copy(subdiv_ccg, key, grid_element, &tls->accumulators[i]); } } @@ -1084,13 +1101,15 @@ static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg, GridElementAccumulator accumulator; element_accumulator_init(&accumulator); for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { - CCGElem *grid_element = adjacent_vertex->corner_elements[face_index]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]); element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element); } element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces); /* Copy averaged value to all the other faces. */ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) { - CCGElem *grid_element = adjacent_vertex->corner_elements[face_index]; + CCGElem *grid_element = subdiv_ccg_coord_to_elem( + key, subdiv_ccg, &adjacent_vertex->corner_coords[face_index]); element_accumulator_copy(subdiv_ccg, key, grid_element, &accumulator); } } @@ -1224,3 +1243,540 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg, *r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1); *r_num_loops = *r_num_faces * 4; } + +/* ============================================================================= + * Neighbors. + */ + +void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord) +{ + printf("%s: grid index: %d, coord: (%d, %d)\n", message, coord->grid_index, coord->x, coord->y); +} + +bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + if (coord->grid_index < 0 || coord->grid_index >= subdiv_ccg->num_grids) { + return false; + } + const int grid_size = subdiv_ccg->grid_size; + if (coord->x < 0 || coord->x >= grid_size) { + return false; + } + if (coord->y < 0 || coord->y >= grid_size) { + return false; + } + return true; +} + +BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors *neighbors, + const int num_unique, + const int num_duplicates) +{ + const int size = num_unique + num_duplicates; + neighbors->size = size; + neighbors->num_duplicates = num_duplicates; + if (size < ARRAY_SIZE(neighbors->coords_fixed)) { + neighbors->coords = neighbors->coords_fixed; + } + else { + neighbors->coords = MEM_mallocN(sizeof(*neighbors->coords) * size, + "SubdivCCGNeighbors.coords"); + } +} + +/* Check whether given coordinate belongs to a grid corner. */ +BLI_INLINE bool is_corner_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return (coord->x == 0 && coord->y == 0) || (coord->x == 0 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == grid_size_1) || + (coord->x == grid_size_1 && coord->y == 0); +} + +/* Check whether given coordinate belongs to a grid boundary. */ +BLI_INLINE bool is_boundary_grid_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + return coord->x == 0 || coord->y == 0 || coord->x == grid_size_1 || coord->y == grid_size_1; +} + +/* Check whether coordinate is at the boundary between two grids of the same face. */ +BLI_INLINE bool is_inner_edge_grid_coordinate(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == 0) { + return coord->y > 0 && coord->y < grid_size_1; + } + if (coord->y == 0) { + return coord->x > 0 && coord->x < grid_size_1; + } + return false; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_row(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->y > 0); + SubdivCCGCoord result = *coord; + result.y -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_row(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->y < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.y += 1; + return result; +} + +BLI_INLINE SubdivCCGCoord coord_at_prev_col(const SubdivCCG *UNUSED(subdiv_ccg), + const SubdivCCGCoord *coord) +{ + BLI_assert(coord->x > 0); + SubdivCCGCoord result = *coord; + result.x -= 1; + return result; +} +BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + UNUSED_VARS_NDEBUG(subdiv_ccg); + BLI_assert(coord->x < subdiv_ccg->grid_size - 1); + SubdivCCGCoord result = *coord; + result.x += 1; + return result; +} + +/* For the input coordinate which is at the boundary of the grid do one step inside. */ +static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) + +{ + SubdivCCGCoord result = *coord; + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (result.x == grid_size_1) { + --result.x; + } + else if (result.y == grid_size_1) { + --result.y; + } + else if (result.x == 0) { + ++result.x; + } + else if (result.y == 0) { + ++result.y; + } + else { + BLI_assert(!"non-boundary element given"); + } + return result; +} + +BLI_INLINE +int next_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int next_face_grid_index = face_grid_index + 1 - face->start_grid_index; + if (next_face_grid_index == face->num_grids) { + next_face_grid_index = 0; + } + return face->start_grid_index + next_face_grid_index; +} +BLI_INLINE int prev_grid_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_grid_index = coord->grid_index; + int prev_face_grid_index = face_grid_index - 1 - face->start_grid_index; + if (prev_face_grid_index < 0) { + prev_face_grid_index = face->num_grids - 1; + } + return face->start_grid_index + prev_face_grid_index; +} + +/* Simple case of getting neighbors of a corner coordinate: the corner is a face center, so + * can only iterate over grid of a single face, without looking into adjacency. */ +static void neighbor_coords_corner_center_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int num_adjacent_grids = face->num_grids; + + subdiv_ccg_neighbors_init( + r_neighbors, num_adjacent_grids, (include_duplicates) ? num_adjacent_grids - 1 : 0); + + int duplicate_face_grid_index = num_adjacent_grids; + for (int face_grid_index = 0; face_grid_index < num_adjacent_grids; ++face_grid_index) { + SubdivCCGCoord neighbor_coord; + neighbor_coord.grid_index = face->start_grid_index + face_grid_index; + neighbor_coord.x = 1; + neighbor_coord.y = 0; + r_neighbors->coords[face_grid_index] = neighbor_coord; + + if (include_duplicates && neighbor_coord.grid_index != coord->grid_index) { + neighbor_coord.x = 0; + r_neighbors->coords[duplicate_face_grid_index++] = neighbor_coord; + } + } +} + +/* Get index within adjacent_vertices array for the given CCG coordinate. */ +static int adjacent_vertex_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + const int face_index = face - subdiv_ccg->faces; + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int num_face_grids = face->num_grids; + const int num_face_vertices = num_face_grids; + + StaticOrHeapIntStorage face_vertices_storage; + static_or_heap_storage_init(&face_vertices_storage); + + int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_vertices); + topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices); + + const int adjacent_vertex_index = face_vertices[face_grid_index]; + static_or_heap_storage_free(&face_vertices_storage); + return adjacent_vertex_index; +} + +/* The corner is adjacent to a coarse vertex. */ +static void neighbor_coords_corner_vertex_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_vertex_index >= 0); + BLI_assert(adjacent_vertex_index < subdiv_ccg->num_adjacent_vertices); + const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner, + adjacent_vertex_index); + + SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[adjacent_vertex_index]; + const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces; + + subdiv_ccg_neighbors_init( + r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0); + + StaticOrHeapIntStorage vertex_edges_storage; + static_or_heap_storage_init(&vertex_edges_storage); + + int *vertex_edges = static_or_heap_storage_get(&vertex_edges_storage, num_vertex_edges); + topology_refiner->getVertexEdges(topology_refiner, adjacent_vertex_index, vertex_edges); + + for (int i = 0; i < num_vertex_edges; ++i) { + const int edge_index = vertex_edges[i]; + + /* Use very first grid of every edge. */ + const int edge_face_index = 0; + + /* Depending edge orientation we use first (zero-based) or previous-to-last point. */ + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices); + int edge_point_index, duplicate_edge_point_index; + if (edge_vertices_indices[0] == adjacent_vertex_index) { + duplicate_edge_point_index = 0; + edge_point_index = duplicate_edge_point_index + 1; + } + else { + /* Edge "consists" of 2 grids, which makes it 2 * grid_size elements per edge. + * The index of last edge element is 2 * grid_size - 1 (due to zero-based indices), + * and we are interested in previous to last element. */ + duplicate_edge_point_index = subdiv_ccg->grid_size * 2 - 1; + edge_point_index = duplicate_edge_point_index - 1; + } + + SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index]; + r_neighbors->coords[i] = adjacent_edge->boundary_coords[edge_face_index][edge_point_index]; + } + + if (include_duplicates) { + /* Add duplicates of the current grid vertex in adjacent faces if requested. */ + for (int i = 0, duplicate_i = num_vertex_edges; i < num_adjacent_faces; i++) { + SubdivCCGCoord neighbor_coord = adjacent_vertex->corner_coords[i]; + if (neighbor_coord.grid_index != coord->grid_index) { + r_neighbors->coords[duplicate_i++] = neighbor_coord; + } + } + } + + static_or_heap_storage_free(&vertex_edges_storage); +} + +static int adjacent_edge_index_from_coord(const SubdivCCG *subdiv_ccg, const SubdivCCGCoord *coord) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + SubdivCCGFace *face = subdiv_ccg->grid_faces[coord->grid_index]; + + const int face_grid_index = coord->grid_index - face->start_grid_index; + const int face_index = face - subdiv_ccg->faces; + const int num_face_edges = topology_refiner->getNumFaceEdges(topology_refiner, face_index); + + StaticOrHeapIntStorage face_edges_storage; + static_or_heap_storage_init(&face_edges_storage); + int *face_edges_indices = static_or_heap_storage_get(&face_edges_storage, num_face_edges); + topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges_indices); + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_index = face_edges_indices[face_grid_index]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_index = + face_edges_indices[face_grid_index == 0 ? face->num_grids - 1 : face_grid_index - 1]; + } + + static_or_heap_storage_free(&face_edges_storage); + + return adjacent_edge_index; +} + +static int adjacent_edge_point_index_from_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const int adjacent_edge_index) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + + const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); + int edge_vertices_indices[2]; + topology_refiner->getEdgeVertices(topology_refiner, adjacent_edge_index, edge_vertices_indices); + + /* Vertex index of an edge which is used to see whether edge points in the right direction. + * Tricky part here is that depending whether input coordinate is are maximum X or Y coordinate + * of the grid we need to use different edge direction. + * Basically, the edge adjacent to a previous loop needs to point opposite direction. */ + int directional_edge_vertex_index = -1; + + const int grid_size_1 = subdiv_ccg->grid_size - 1; + int adjacent_edge_point_index = -1; + if (coord->x == grid_size_1) { + adjacent_edge_point_index = subdiv_ccg->grid_size - coord->y - 1; + directional_edge_vertex_index = edge_vertices_indices[0]; + } + else { + BLI_assert(coord->y == grid_size_1); + adjacent_edge_point_index = subdiv_ccg->grid_size + coord->x; + directional_edge_vertex_index = edge_vertices_indices[1]; + } + + /* Flip the index if the edde points opposite direction. */ + if (adjacent_vertex_index != directional_edge_vertex_index) { + const int num_edge_points = subdiv_ccg->grid_size * 2; + adjacent_edge_point_index = num_edge_points - adjacent_edge_point_index - 1; + } + + return adjacent_edge_point_index; +} + +/* Adjacent edge has two points in the middle which corresponds to grid corners, but which are + * the same point in the final geometry. + * So need to use extra step when calculating next/previous points, so we don't go from a corner + * of one grid to a corner of adjacent grid. */ +static int next_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size - 1) { + return point_index + 2; + } + return point_index + 1; +} +static int prev_adjacent_edge_point_index(const SubdivCCG *subdiv_ccg, const int point_index) +{ + if (point_index == subdiv_ccg->grid_size) { + return point_index - 2; + } + return point_index - 1; +} + +/* Common implementation of neighbor calculation when input coordinate is at the edge between two + * coarse faces, but is not at the coarse vertex. */ +static void neighbor_coords_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) + +{ + const int adjacent_edge_index = adjacent_edge_index_from_coord(subdiv_ccg, coord); + BLI_assert(adjacent_edge_index >= 0); + BLI_assert(adjacent_edge_index < subdiv_ccg->num_adjacent_edges); + const SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index]; + + /* 2 neighbor points along the edge, plus one inner point per every adjacent grid. */ + const int num_adjacent_faces = adjacent_edge->num_adjacent_faces; + subdiv_ccg_neighbors_init( + r_neighbors, num_adjacent_faces + 2, (include_duplicates) ? num_adjacent_faces - 1 : 0); + + const int point_index = adjacent_edge_point_index_from_coord( + subdiv_ccg, coord, adjacent_edge_index); + const int next_point_index = next_adjacent_edge_point_index(subdiv_ccg, point_index); + const int prev_point_index = prev_adjacent_edge_point_index(subdiv_ccg, point_index); + + for (int i = 0, duplicate_i = num_adjacent_faces; i < num_adjacent_faces; ++i) { + SubdivCCGCoord *boundary_coords = adjacent_edge->boundary_coords[i]; + /* One step into the grid from the edge for each adjacent face. */ + SubdivCCGCoord grid_coord = boundary_coords[point_index]; + r_neighbors->coords[i + 2] = coord_step_inside_from_boundary(subdiv_ccg, &grid_coord); + + if (grid_coord.grid_index == coord->grid_index) { + /* Prev and next along the edge for the current grid. */ + r_neighbors->coords[0] = boundary_coords[prev_point_index]; + r_neighbors->coords[1] = boundary_coords[next_point_index]; + } + else if (include_duplicates) { + /* Same coordinate on neighboring grids if requested. */ + r_neighbors->coords[duplicate_i + 2] = grid_coord; + duplicate_i++; + } + } +} + +/* The corner is at the middle of edge between faces. */ +static void neighbor_coords_corner_edge_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); +} + +/* Input coordinate is at one of 4 corners of its grid corners. */ +static void neighbor_coords_corner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + if (coord->x == 0 && coord->y == 0) { + neighbor_coords_corner_center_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + const int grid_size_1 = subdiv_ccg->grid_size - 1; + if (coord->x == grid_size_1 && coord->y == grid_size_1) { + neighbor_coords_corner_vertex_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_corner_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + } +} + +/* Simple case of getting neighbors of a boundary coordinate: the input coordinate is at the + * boundary between two grids of the same face and there is no need to check adjacency with + * other faces. */ +static void neighbor_coords_boundary_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4, (include_duplicates) ? 1 : 0); + + if (coord->x == 0) { + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_col(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = prev_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = coord->y; + r_neighbors->coords[3].y = 1; + + if (include_duplicates) { + r_neighbors->coords[4] = r_neighbors->coords[3]; + r_neighbors->coords[4].y = 0; + } + } + else if (coord->y == 0) { + r_neighbors->coords[0] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_col(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_next_row(subdiv_ccg, coord); + + r_neighbors->coords[3].grid_index = next_grid_index_from_coord(subdiv_ccg, coord); + r_neighbors->coords[3].x = 1; + r_neighbors->coords[3].y = coord->x; + + if (include_duplicates) { + r_neighbors->coords[4] = r_neighbors->coords[3]; + r_neighbors->coords[4].x = 0; + } + } +} + +/* Input coordinate is on an edge between two faces. Need to check adjacency. */ +static void neighbor_coords_boundary_outer_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + neighbor_coords_edge_get(subdiv_ccg, coord, include_duplicates, r_neighbors); +} + +/* Input coordinate is at one of 4 boundaries of its grid. + * It could either be an inner boundary (which connects face center to the face edge) or could be + * a part of coarse face edge. */ +static void neighbor_coords_boundary_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + if (is_inner_edge_grid_coordinate(subdiv_ccg, coord)) { + neighbor_coords_boundary_inner_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_boundary_outer_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } +} + +/* Input coordinate is inside of its grid, all the neighbors belong to the same grid. */ +static void neighbor_coords_inner_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + SubdivCCGNeighbors *r_neighbors) +{ + subdiv_ccg_neighbors_init(r_neighbors, 4, 0); + + r_neighbors->coords[0] = coord_at_prev_row(subdiv_ccg, coord); + r_neighbors->coords[1] = coord_at_next_row(subdiv_ccg, coord); + r_neighbors->coords[2] = coord_at_prev_col(subdiv_ccg, coord); + r_neighbors->coords[3] = coord_at_next_col(subdiv_ccg, coord); +} + +void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + const bool include_duplicates, + SubdivCCGNeighbors *r_neighbors) +{ + BLI_assert(coord->grid_index >= 0); + BLI_assert(coord->grid_index < subdiv_ccg->num_grids); + BLI_assert(coord->x >= 0); + BLI_assert(coord->x < subdiv_ccg->grid_size); + BLI_assert(coord->y >= 0); + BLI_assert(coord->y < subdiv_ccg->grid_size); + + if (is_corner_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_corner_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else if (is_boundary_grid_coord(subdiv_ccg, coord)) { + neighbor_coords_boundary_get(subdiv_ccg, coord, include_duplicates, r_neighbors); + } + else { + neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors); + } + +#ifndef NDEBUG + for (int i = 0; i < r_neighbors->size; i++) { + BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, &r_neighbors->coords[i])); + } +#endif +} diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c new file mode 100644 index 00000000000..9c7949e7bdb --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_deform.c @@ -0,0 +1,237 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_subdiv_deform.h" + +#include <string.h> + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" + +#include "MEM_guardedalloc.h" + +/* ================================================================================================ + * Subdivision context. + */ + +typedef struct SubdivDeformContext { + const Mesh *coarse_mesh; + Subdiv *subdiv; + + float (*vertex_cos)[3]; + int num_verts; + + /* Accumulated values. + * + * Averaging is happening for vertices which correspond to the coarse ones. + * This is needed for displacement. + * + * Displacement is being accumulated to a vertices coordinates, since those + * are not needed during traversal of face-vertices vertices. */ + /* Per-subdivided vertex counter of averaged values. */ + int *accumulated_counters; + + bool have_displacement; +} SubdivDeformContext; + +static void subdiv_mesh_prepare_accumulator(SubdivDeformContext *ctx, int num_vertices) +{ + if (!ctx->have_displacement) { + return; + } + ctx->accumulated_counters = MEM_calloc_arrayN( + sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters"); +} + +static void subdiv_mesh_context_free(SubdivDeformContext *ctx) +{ + MEM_SAFE_FREE(ctx->accumulated_counters); +} + +/* ================================================================================================ + * Accumulation helpers. + */ + +static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx, + const int ptex_face_index, + const float u, + const float v, + int vertex_index) +{ + Subdiv *subdiv = ctx->subdiv; + float dummy_P[3], dPdu[3], dPdv[3], D[3]; + BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv); + /* Accumulate displacement if needed. */ + if (ctx->have_displacement) { + BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D); + /* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily + * initialized to zeroes. */ + if (ctx->accumulated_counters[vertex_index] == 0) { + copy_v3_v3(ctx->vertex_cos[vertex_index], D); + } + else { + add_v3_v3(ctx->vertex_cos[vertex_index], D); + } + } + ++ctx->accumulated_counters[vertex_index]; +} + +/* ================================================================================================ + * Subdivision callbacks. + */ + +static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context, + const int UNUSED(num_vertices), + const int UNUSED(num_edges), + const int UNUSED(num_loops), + const int UNUSED(num_polygons)) +{ + SubdivDeformContext *subdiv_context = foreach_context->user_data; + subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert); + return true; +} + +static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int ptex_face_index, + const float u, + const float v, + const int coarse_vertex_index, + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int UNUSED(subdiv_vertex_index)) +{ + SubdivDeformContext *ctx = foreach_context->user_data; + subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index); +} + +static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int ptex_face_index, + const float u, + const float v, + const int coarse_vertex_index, + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int UNUSED(subdiv_vertex_index)) +{ + SubdivDeformContext *ctx = foreach_context->user_data; + BLI_assert(coarse_vertex_index != ORIGINDEX_NONE); + BLI_assert(coarse_vertex_index < ctx->num_verts); + float inv_num_accumulated = 1.0f; + if (ctx->accumulated_counters != NULL) { + inv_num_accumulated = 1.0f / ctx->accumulated_counters[coarse_vertex_index]; + } + /* Displacement is accumulated in subdiv vertex position. + * Needs to be backed up before copying data from original vertex. */ + float D[3] = {0.0f, 0.0f, 0.0f}; + float *vertex_co = ctx->vertex_cos[coarse_vertex_index]; + if (ctx->have_displacement) { + copy_v3_v3(D, vertex_co); + mul_v3_fl(D, inv_num_accumulated); + } + /* Copy custom data and evaluate position. */ + BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co); + /* Apply displacement. */ + add_v3_v3(vertex_co, D); +} + +/* ================================================================================================ + * Initialization. + */ + +static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context, + SubdivForeachContext *foreach_context) +{ + memset(foreach_context, 0, sizeof(*foreach_context)); + /* General information. */ + foreach_context->topology_info = subdiv_mesh_topology_info; + /* Every boundary geometry. Used for displacement and normals averaging. */ + if (subdiv_context->have_displacement) { + foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner; + } + foreach_context->vertex_corner = subdiv_mesh_vertex_corner; +} + +/* ================================================================================================ + * Public entry point. + */ + +void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, + const struct Mesh *coarse_mesh, + float (*vertex_cos)[3], + int num_verts) +{ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + /* Make sure evaluator is up to date with possible new topology, and that + * is is refined for the new positions of coarse vertices. + */ + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) { + /* This could happen in two situations: + * - OpenSubdiv is disabled. + * - Something totally bad happened, and OpenSubdiv rejected our + * topology. + * In either way, we can't safely continue. */ + if (coarse_mesh->totpoly) { + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + return; + } + } + + /* Initialize subdivion mesh creation context. */ + SubdivDeformContext subdiv_context = {0}; + subdiv_context.coarse_mesh = coarse_mesh; + subdiv_context.subdiv = subdiv; + subdiv_context.vertex_cos = vertex_cos; + subdiv_context.num_verts = num_verts; + subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL); + + SubdivForeachContext foreach_context; + setup_foreach_callbacks(&subdiv_context, &foreach_context); + foreach_context.user_data = &subdiv_context; + + /* Dummy mesh rasterization settings. */ + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = 1; + mesh_settings.use_optimal_display = false; + + /* Multi-threaded traversal/evaluation. */ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); + BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); + + // BKE_mesh_validate(result, true, true); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + + /* Free used memory. */ + subdiv_mesh_context_free(&subdiv_context); +} diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index 419371c7a4b..bf5e886dd22 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -61,7 +61,9 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv) return true; } -static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh) +static void set_coarse_positions(Subdiv *subdiv, + const Mesh *mesh, + const float (*coarse_vertex_cos)[3]) { const MVert *mvert = mesh->mvert; const MLoop *mloop = mesh->mloop; @@ -83,8 +85,15 @@ static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh) if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) { continue; } - const MVert *vertex = &mvert[vertex_index]; - subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex->co, manifold_veretx_index, 1); + const float *vertex_co; + if (coarse_vertex_cos != NULL) { + vertex_co = coarse_vertex_cos[vertex_index]; + } + else { + const MVert *vertex = &mvert[vertex_index]; + vertex_co = vertex->co; + } + subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_veretx_index, 1); manifold_veretx_index++; } MEM_freeN(vertex_used_map); @@ -112,7 +121,9 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv, } } -bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh) +bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, + const Mesh *mesh, + const float (*coarse_vertex_cos)[3]) { if (!BKE_subdiv_eval_begin(subdiv)) { return false; @@ -123,7 +134,7 @@ bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh) return false; } /* Set coordinates of base mesh vertices. */ - set_coarse_positions(subdiv, mesh); + set_coarse_positions(subdiv, mesh, coarse_vertex_cos); /* Set face-varyign data to UV maps. */ const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) { diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 1604c2560ff..a30dde6284b 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -482,6 +482,8 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext * } /* Accumulate displacement if needed. */ if (ctx->have_displacement) { + /* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero + * locations as a default calloc(). */ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D); add_v3_v3(subdiv_vert->co, D); } @@ -1164,7 +1166,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, /* Make sure evaluator is up to date with possible new topology, and that * is is refined for the new positions of coarse vertices. */ - if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) { + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our @@ -1175,7 +1177,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, return NULL; } } - /* Initialize subdivion mesh creation context/ */ + /* Initialize subdivion mesh creation context. */ SubdivMeshContext subdiv_context = {0}; subdiv_context.settings = settings; subdiv_context.coarse_mesh = coarse_mesh; @@ -1198,7 +1200,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, if (!subdiv_context.can_evaluate_normals) { result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } - /* Free used memoty. */ + /* Free used memory. */ subdiv_mesh_context_free(&subdiv_context); return result; } diff --git a/source/blender/blenkernel/intern/subdiv_topology.c b/source/blender/blenkernel/intern/subdiv_topology.c new file mode 100644 index 00000000000..455fa2cf28f --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_topology.c @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_subdiv_topology.h" + +#include "BKE_subdiv.h" + +#include "opensubdiv_topology_refiner_capi.h" + +int BKE_subdiv_topology_num_fvar_layers_get(const struct Subdiv *subdiv) +{ + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + return topology_refiner->getNumFVarChannels(topology_refiner); +} diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 83be64e84c9..5c050dde990 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -312,7 +312,7 @@ bool BKE_text_reload(Text *text) } BLI_strncpy(filepath_abs, text->name, FILE_MAX); - BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global()); + BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); if (buffer == NULL) { @@ -352,7 +352,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len); if (buffer == NULL) { - return false; + return NULL; } ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0); @@ -477,7 +477,7 @@ int BKE_text_file_modified_check(Text *text) } BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, BKE_main_blendfile_path_from_global()); + BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { return 2; @@ -511,7 +511,7 @@ void BKE_text_file_modified_ignore(Text *text) } BLI_strncpy(file, text->name, FILE_MAX); - BLI_path_abs(file, BKE_main_blendfile_path_from_global()); + BLI_path_abs(file, ID_BLEND_PATH_FROM_GLOBAL(&text->id)); if (!BLI_exists(file)) { return; @@ -1218,6 +1218,58 @@ void txt_sel_line(Text *text) text->selc = text->sell->len; } +void txt_sel_set(Text *text, int startl, int startc, int endl, int endc) +{ + TextLine *froml, *tol; + int fromllen, tollen; + + /* Support negative indices. */ + if (startl < 0 || endl < 0) { + int end = BLI_listbase_count(&text->lines) - 1; + if (startl < 0) { + startl = end + startl + 1; + } + if (endl < 0) { + endl = end + endl + 1; + } + } + CLAMP_MIN(startl, 0); + CLAMP_MIN(endl, 0); + + froml = BLI_findlink(&text->lines, startl); + if (froml == NULL) { + froml = text->lines.last; + } + if (startl == endl) { + tol = froml; + } + else { + tol = BLI_findlink(&text->lines, endl); + if (tol == NULL) { + tol = text->lines.last; + } + } + + fromllen = BLI_strlen_utf8(froml->line); + tollen = BLI_strlen_utf8(tol->line); + + /* Support negative indices. */ + if (startc < 0) { + startc = fromllen + startc + 1; + } + if (endc < 0) { + endc = tollen + endc + 1; + } + + CLAMP(startc, 0, fromllen); + CLAMP(endc, 0, tollen); + + text->curl = froml; + text->curc = BLI_str_utf8_offset_from_index(froml->line, startc); + text->sell = tol; + text->selc = BLI_str_utf8_offset_from_index(tol->line, endc); +} + /* -------------------------------------------------------------------- */ /** \name Buffer Conversion for Undo/Redo * diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.h index 1373a0da355..e34647676d8 100644 --- a/source/blender/blenlib/BLI_array_ref.h +++ b/source/blender/blenlib/BLI_array_ref.h @@ -21,17 +21,17 @@ * \ingroup bli * * These classes offer a convenient way to work with continuous chunks of memory of a certain type. - * We differentiate ArrayRef and MutableArrayRef. The elements in the former are const while the + * We differentiate #ArrayRef and #MutableArrayRef. The elements in the former are const while the * elements in the other are not. * * Passing array references as parameters has multiple benefits: * - Less templates are used because the function does not have to work with different * container types. - * - It encourages an Struct-of-Arrays data layout which is often benefitial when + * - It encourages an Struct-of-Arrays data layout which is often beneficial when * writing high performance code. Also it makes it easier to reuse code. * - Array references offer convenient ways of slicing and other operations. * - * The instances of ArrayRef and MutableArrayRef are very small and should be passed by value. + * The instances of #ArrayRef and #MutableArrayRef are very small and should be passed by value. * Since array references do not own any memory, it is generally not save to store them. */ @@ -202,7 +202,7 @@ template<typename T> class ArrayRef { /** * Does a linear search to count how often the value is in the array. - * Returns the number of occurences. + * Returns the number of occurrences. */ uint count(const T &value) const { @@ -226,7 +226,7 @@ template<typename T> class ArrayRef { } /** - * Return a reference to the last elemeent in the array. + * Return a reference to the last element in the array. * Asserts that the array is not empty. */ const T &last() const @@ -363,7 +363,7 @@ template<typename T> class MutableArrayRef { /** * Return a continuous part of the array. - * Aserts that the slice stays in the array bounds. + * Asserts that the slice stays in the array bounds. */ MutableArrayRef slice(uint start, uint length) const { diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index bd1cd327d3c..312991e7f15 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -15,7 +15,7 @@ */ #ifndef __BLI_COMPILER_COMPAT_H__ -# define __BLI_COMPILER_COMPAT_H__ +#define __BLI_COMPILER_COMPAT_H__ /** \file * \ingroup bli @@ -23,32 +23,32 @@ * Use to help with cross platform portability. */ -# if defined(_MSC_VER) -# define alloca _alloca -# endif +#if defined(_MSC_VER) +# define alloca _alloca +#endif -# if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) +#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) extern "C++" { /* Some magic to be sure we don't have reference in the type. */ template<typename T> static inline T decltype_helper(T x) { return x; } -# define typeof(x) decltype(decltype_helper(x)) +# define typeof(x) decltype(decltype_helper(x)) } -# endif +#endif /* little macro so inline keyword works */ -# if defined(_MSC_VER) -# define BLI_INLINE static __forceinline -# else -# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) -# endif +#if defined(_MSC_VER) +# define BLI_INLINE static __forceinline +#else +# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) +#endif -# if defined(__GNUC__) -# define BLI_NOINLINE __attribute__((noinline)) -# else -# define BLI_NOINLINE -# endif +#if defined(__GNUC__) +# define BLI_NOINLINE __attribute__((noinline)) +#else +# define BLI_NOINLINE +#endif #endif /* __BLI_COMPILER_COMPAT_H__ */ diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index d78f167a8fd..bdf7588291f 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -50,6 +50,7 @@ int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_copy(const char *path, const char *to) ATTR_NONNULL(); int BLI_rename(const char *from, const char *to) ATTR_NONNULL(); int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL(); +int BLI_delete_soft(const char *path, const char **error_message) ATTR_NONNULL(); #if 0 /* Unused */ int BLI_move(const char *path, const char *to) ATTR_NONNULL(); int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h index 72cd5c7f4ec..b8a87e9d9fa 100644 --- a/source/blender/blenlib/BLI_gsqueue.h +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -26,13 +26,11 @@ typedef struct _GSQueue GSQueue; -GSQueue *BLI_gsqueue_new(size_t elem_size); -bool BLI_gsqueue_is_empty(GSQueue *gq); -int BLI_gsqueue_len(GSQueue *gq); -void BLI_gsqueue_peek(GSQueue *gq, void *r_item); +GSQueue *BLI_gsqueue_new(const size_t elem_size); +bool BLI_gsqueue_is_empty(const GSQueue *gq); +size_t BLI_gsqueue_len(const GSQueue *gq); void BLI_gsqueue_pop(GSQueue *gq, void *r_item); void BLI_gsqueue_push(GSQueue *gq, const void *item); -void BLI_gsqueue_push_back(GSQueue *gq, const void *item); void BLI_gsqueue_free(GSQueue *gq); #endif /* __BLI_GSQUEUE_H__ */ diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash_cxx.h index 78b8ee20b0c..e899f27c9ee 100644 --- a/source/blender/blenlib/BLI_hash_cxx.h +++ b/source/blender/blenlib/BLI_hash_cxx.h @@ -27,6 +27,7 @@ #include <functional> #include <string> #include <utility> +#include <memory> #include "BLI_utildefines.h" #include "BLI_math_base.h" @@ -89,6 +90,13 @@ template<typename T> struct DefaultHash<T *> { } }; +template<typename T> struct DefaultHash<std::unique_ptr<T>> { + uint32_t operator()(const std::unique_ptr<T> &value) const + { + return DefaultHash<T *>{}(value.get()); + } +}; + template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> { uint32_t operator()(const std::pair<T1, T2> &value) const { diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h index e442bd7a99d..c028266ef64 100644 --- a/source/blender/blenlib/BLI_kdtree_impl.h +++ b/source/blender/blenlib/BLI_kdtree_impl.h @@ -21,9 +21,9 @@ #include "BLI_compiler_attrs.h" -#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 -#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) -#define BLI_kdtree_nd_(id) _CONCAT(KDTREE_PREFIX_ID, _##id) +#define _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2 +#define _BLI_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define BLI_kdtree_nd_(id) _BLI_CONCAT(KDTREE_PREFIX_ID, _##id) struct KDTree; typedef struct KDTree KDTree; @@ -93,6 +93,6 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)( const void *user_data), const void *user_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; -#undef _CONCAT_AUX -#undef _CONCAT +#undef _BLI_CONCAT_AUX +#undef _BLI_CONCAT #undef BLI_kdtree_nd_ diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.h index a5358304c77..1edf7653c71 100644 --- a/source/blender/blenlib/BLI_map.h +++ b/source/blender/blenlib/BLI_map.h @@ -142,20 +142,20 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> return (ValueT *)(m_values + offset * sizeof(ValueT)); } - void copy_in(uint offset, const KeyT &key, const ValueT &value) + template<typename ForwardKeyT, typename ForwardValueT> + void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value) { BLI_assert(m_status[offset] != IS_SET); m_status[offset] = IS_SET; - new (this->key(offset)) KeyT(key); - new (this->value(offset)) ValueT(value); + new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key)); + new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value)); } - void move_in(uint offset, KeyT &key, ValueT &value) + template<typename ForwardKeyT> void store_without_value(uint offset, ForwardKeyT &&key) { BLI_assert(m_status[offset] != IS_SET); m_status[offset] = IS_SET; - new (this->key(offset)) KeyT(std::move(key)); - new (this->value(offset)) ValueT(std::move(value)); + new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key)); } void set_dummy(uint offset) @@ -199,17 +199,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> */ void add_new(const KeyT &key, const ValueT &value) { - BLI_assert(!this->contains(key)); - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (key, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, key, value); - m_array.update__empty_to_set(); - return; - } - } - ITER_SLOTS_END(offset); + this->add_new__impl(key, value); + } + void add_new(const KeyT &key, ValueT &&value) + { + this->add_new__impl(key, std::move(value)); + } + void add_new(KeyT &&key, const ValueT &value) + { + this->add_new__impl(std::move(key), value); + } + void add_new(KeyT &&key, ValueT &&value) + { + this->add_new__impl(std::move(key), std::move(value)); } /** @@ -218,19 +220,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> */ bool add(const KeyT &key, const ValueT &value) { - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (key, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, key, value); - m_array.update__empty_to_set(); - return true; - } - else if (item.has_key(offset, key)) { - return false; - } - } - ITER_SLOTS_END(offset); + return this->add__impl(key, value); + } + bool add(const KeyT &key, ValueT &&value) + { + return this->add__impl(key, std::move(value)); + } + bool add(KeyT &&key, const ValueT &value) + { + return this->add__impl(std::move(key), value); + } + bool add(KeyT &&key, ValueT &&value) + { + return this->add__impl(std::move(key), std::move(value)); } /** @@ -285,30 +287,30 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> } /** - * Check if the key exists in the map. - * If it does exist, call the modify function with a reference to the corresponding value. - * If it does not exist, call the create function and insert a new key-value-pair. - * Returns true when a new pair was inserted, otherwise false. + * First, checks if the key exists in the map. + * If it does exist, call the modify function with a pointer to the corresponding value. + * If it does not exist, call the create function with a pointer to where the value should be + * created. + * + * Returns whatever is returned from one of the callback functions. Both callbacks have to return + * the same type. + * + * CreateValueF: Takes a pointer to where the value should be created. + * ModifyValueF: Takes a pointer to the value that should be modified. */ template<typename CreateValueF, typename ModifyValueF> - bool add_or_modify(const KeyT &key, + auto add_or_modify(const KeyT &key, const CreateValueF &create_value, - const ModifyValueF &modify_value) + const ModifyValueF &modify_value) -> decltype(create_value(nullptr)) { - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (key, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, key, create_value()); - m_array.update__empty_to_set(); - return true; - } - else if (item.has_key(offset, key)) { - modify_value(*item.value(offset)); - return false; - } - } - ITER_SLOTS_END(offset); + return this->add_or_modify__impl(key, create_value, modify_value); + } + template<typename CreateValueF, typename ModifyValueF> + auto add_or_modify(KeyT &&key, + const CreateValueF &create_value, + const ModifyValueF &modify_value) -> decltype(create_value(nullptr)) + { + return this->add_or_modify__impl(std::move(key), create_value, modify_value); } /** @@ -316,8 +318,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> */ bool add_override(const KeyT &key, const ValueT &value) { - return this->add_or_modify( - key, [&value]() { return value; }, [&value](ValueT &old_value) { old_value = value; }); + return this->add_override__impl(key, value); + } + bool add_override(const KeyT &key, ValueT &&value) + { + return this->add_override__impl(key, std::move(value)); + } + bool add_override(KeyT &&key, const ValueT &value) + { + return this->add_override__impl(std::move(key), value); + } + bool add_override(KeyT &&key, ValueT &&value) + { + return this->add_override__impl(std::move(key), std::move(value)); } /** @@ -384,19 +397,12 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> template<typename CreateValueF> ValueT &lookup_or_add(const KeyT &key, const CreateValueF &create_value) { - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (key, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, key, create_value()); - m_array.update__empty_to_set(); - return *item.value(offset); - } - else if (item.has_key(offset, key)) { - return *item.value(offset); - } - } - ITER_SLOTS_END(offset); + return this->lookup_or_add__impl(key, create_value); + } + template<typename CreateValueF> + ValueT &lookup_or_add(KeyT &&key, const CreateValueF &create_value) + { + return this->lookup_or_add__impl(std::move(key), create_value); } /** @@ -608,12 +614,106 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> { ITER_SLOTS_BEGIN (key, new_array, , item, offset) { if (item.is_empty(offset)) { - item.move_in(offset, key, value); + item.store(offset, std::move(key), std::move(value)); return; } } ITER_SLOTS_END(offset); } + + template<typename ForwardKeyT, typename ForwardValueT> + bool add_override__impl(ForwardKeyT &&key, ForwardValueT &&value) + { + return this->add_or_modify( + std::forward<ForwardKeyT>(key), + [&](ValueT *dst) { + new (dst) ValueT(std::forward<ForwardValueT>(value)); + return true; + }, + [&](ValueT *old_value) { + *old_value = std::forward<ForwardValueT>(value); + return false; + }); + } + + template<typename ForwardKeyT, typename ForwardValueT> + bool add__impl(ForwardKeyT &&key, ForwardValueT &&value) + { + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (key, m_array, , item, offset) { + if (item.is_empty(offset)) { + item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value)); + m_array.update__empty_to_set(); + return true; + } + else if (item.has_key(offset, key)) { + return false; + } + } + ITER_SLOTS_END(offset); + } + + template<typename ForwardKeyT, typename ForwardValueT> + void add_new__impl(ForwardKeyT &&key, ForwardValueT &&value) + { + BLI_assert(!this->contains(key)); + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (key, m_array, , item, offset) { + if (item.is_empty(offset)) { + item.store(offset, std::forward<ForwardKeyT>(key), std::forward<ForwardValueT>(value)); + m_array.update__empty_to_set(); + return; + } + } + ITER_SLOTS_END(offset); + } + + template<typename ForwardKeyT, typename CreateValueF, typename ModifyValueF> + auto add_or_modify__impl(ForwardKeyT &&key, + const CreateValueF &create_value, + const ModifyValueF &modify_value) -> decltype(create_value(nullptr)) + { + using CreateReturnT = decltype(create_value(nullptr)); + using ModifyReturnT = decltype(modify_value(nullptr)); + BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value), + "Both callbacks should return the same type."); + + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (key, m_array, , item, offset) { + if (item.is_empty(offset)) { + m_array.update__empty_to_set(); + item.store_without_value(offset, std::forward<ForwardKeyT>(key)); + ValueT *value_ptr = item.value(offset); + return create_value(value_ptr); + } + else if (item.has_key(offset, key)) { + ValueT *value_ptr = item.value(offset); + return modify_value(value_ptr); + } + } + ITER_SLOTS_END(offset); + } + + template<typename ForwardKeyT, typename CreateValueF> + ValueT &lookup_or_add__impl(ForwardKeyT &&key, const CreateValueF &create_value) + { + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (key, m_array, , item, offset) { + if (item.is_empty(offset)) { + item.store(offset, std::forward<ForwardKeyT>(key), create_value()); + m_array.update__empty_to_set(); + return *item.value(offset); + } + else if (item.has_key(offset, key)) { + return *item.value(offset); + } + } + ITER_SLOTS_END(offset); + } }; #undef ITER_SLOTS_BEGIN diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 87517ebe060..eec5d214473 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -97,10 +97,10 @@ bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); bool is_poly_convex_v2(const float verts[][2], unsigned int nr); int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); -bool is_quad_flip_v3_first_third_fast(const float v0[3], - const float v1[3], +bool is_quad_flip_v3_first_third_fast(const float v1[3], const float v2[3], - const float v3[3]); + const float v3[3], + const float v4[3]); /********************************* Distance **********************************/ diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h index c5ef26ffb91..8bd8642a4e8 100644 --- a/source/blender/blenlib/BLI_memblock.h +++ b/source/blender/blenlib/BLI_memblock.h @@ -30,16 +30,20 @@ extern "C" { #include "BLI_compiler_attrs.h" +#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */ + struct BLI_memblock; typedef struct BLI_memblock BLI_memblock; typedef void (*MemblockValFreeFP)(void *val); -BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT; +void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1); void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1); +#define BLI_memblock_create(elem_size) BLI_memblock_create_ex(elem_size, BLI_MEM_BLOCK_CHUNK_SIZE) + typedef struct BLI_memblock_iter { void **chunk_list; int cur_index; @@ -53,6 +57,9 @@ typedef struct BLI_memblock_iter { void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL(); void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.h index feb0574338e..dc101add1a7 100644 --- a/source/blender/blenlib/BLI_set.h +++ b/source/blender/blenlib/BLI_set.h @@ -117,20 +117,12 @@ template<typename T, typename Allocator = GuardedAllocator> class Set { return (T *)(m_values + offset * sizeof(T)); } - void copy_in(uint offset, const T &value) + template<typename ForwardT> void store(uint offset, ForwardT &&value) { BLI_assert(m_status[offset] != IS_SET); m_status[offset] = IS_SET; T *dst = this->value(offset); - new (dst) T(value); - } - - void move_in(uint offset, T &value) - { - BLI_assert(m_status[offset] != IS_SET); - m_status[offset] = IS_SET; - T *dst = this->value(offset); - new (dst) T(std::move(value)); + new (dst) T(std::forward<ForwardT>(value)); } void set_dummy(uint offset) @@ -201,17 +193,11 @@ template<typename T, typename Allocator = GuardedAllocator> class Set { */ void add_new(const T &value) { - BLI_assert(!this->contains(value)); - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (value, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, value); - m_array.update__empty_to_set(); - return; - } - } - ITER_SLOTS_END(offset); + this->add_new__impl(value); + } + void add_new(T &&value) + { + this->add_new__impl(std::move(value)); } /** @@ -219,19 +205,11 @@ template<typename T, typename Allocator = GuardedAllocator> class Set { */ bool add(const T &value) { - this->ensure_can_add(); - - ITER_SLOTS_BEGIN (value, m_array, , item, offset) { - if (item.is_empty(offset)) { - item.copy_in(offset, value); - m_array.update__empty_to_set(); - return true; - } - else if (item.has_value(offset, value)) { - return false; - } - } - ITER_SLOTS_END(offset); + return this->add__impl(value); + } + bool add(T &&value) + { + return this->add__impl(std::move(value)); } /** @@ -445,7 +423,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set { { ITER_SLOTS_BEGIN (old_value, new_array, , item, offset) { if (item.is_empty(offset)) { - item.move_in(offset, old_value); + item.store(offset, std::move(old_value)); return; } } @@ -463,6 +441,38 @@ template<typename T, typename Allocator = GuardedAllocator> class Set { } ITER_SLOTS_END(offset); } + + template<typename ForwardT> void add_new__impl(ForwardT &&value) + { + BLI_assert(!this->contains(value)); + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (value, m_array, , item, offset) { + if (item.is_empty(offset)) { + item.store(offset, std::forward<ForwardT>(value)); + m_array.update__empty_to_set(); + return; + } + } + ITER_SLOTS_END(offset); + } + + template<typename ForwardT> bool add__impl(ForwardT &&value) + { + this->ensure_can_add(); + + ITER_SLOTS_BEGIN (value, m_array, , item, offset) { + if (item.is_empty(offset)) { + item.store(offset, std::forward<ForwardT>(value)); + m_array.update__empty_to_set(); + return true; + } + else if (item.has_value(offset, value)) { + return false; + } + } + ITER_SLOTS_END(offset); + } }; #undef ITER_SLOTS_BEGIN diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h index b6250afdee0..08e61915a83 100644 --- a/source/blender/blenlib/BLI_sort.h +++ b/source/blender/blenlib/BLI_sort.h @@ -31,7 +31,7 @@ # define BLI_qsort_r qsort_r #endif -/* Quick sort reentrant */ +/* Quick sort re-entrant */ typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx); void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk) diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack_cxx.h index 4c9f2ed7d44..7915acadfac 100644 --- a/source/blender/blenlib/BLI_stack_cxx.h +++ b/source/blender/blenlib/BLI_stack_cxx.h @@ -73,7 +73,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class St void push(T &&value) { - m_elements.append(std::forward<T>(value)); + m_elements.append(std::move(value)); } /** diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.h index 2daf192f0a7..ba870eb878a 100644 --- a/source/blender/blenlib/BLI_string_map.h +++ b/source/blender/blenlib/BLI_string_map.h @@ -152,20 +152,13 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap { return StringRefNull(start, length); } - void move_in(uint offset, uint32_t hash, uint32_t index, T &value) + template<typename ForwardT> + void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value) { BLI_assert(!this->is_set(offset)); m_hashes[offset] = hash; m_indices[offset] = index; - new (this->value(offset)) T(std::move(value)); - } - - void copy_in(uint offset, uint32_t hash, uint32_t index, const T &value) - { - BLI_assert(!this->is_set(offset)); - m_hashes[offset] = hash; - m_indices[offset] = index; - new (this->value(offset)) T(value); + new (this->value(offset)) T(std::forward<ForwardT>(value)); } }; @@ -189,18 +182,11 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap { */ void add_new(StringRef key, const T &value) { - BLI_assert(!this->contains(key)); - this->ensure_can_add(); - uint32_t hash = this->compute_string_hash(key); - ITER_SLOTS_BEGIN (hash, m_array, , item, offset) { - if (item.is_empty(offset)) { - uint32_t index = this->save_key_in_array(key); - item.copy_in(offset, hash, index, value); - m_array.update__empty_to_set(); - return; - } - } - ITER_SLOTS_END(offset); + this->add_new__impl(key, value); + } + void add_new(StringRef key, T &&value) + { + this->add_new__impl(key, std::move(value)); } /** @@ -407,7 +393,23 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap { { ITER_SLOTS_BEGIN (hash, new_array, , item, offset) { if (item.is_empty(offset)) { - item.move_in(offset, hash, index, value); + item.store(offset, hash, index, std::move(value)); + return; + } + } + ITER_SLOTS_END(offset); + } + + template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value) + { + BLI_assert(!this->contains(key)); + this->ensure_can_add(); + uint32_t hash = this->compute_string_hash(key); + ITER_SLOTS_BEGIN (hash, m_array, , item, offset) { + if (item.is_empty(offset)) { + uint32_t index = this->save_key_in_array(key); + item.store(offset, hash, index, std::forward<ForwardT>(value)); + m_array.update__empty_to_set(); return; } } diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.h index 97357ecd384..46c46a1440f 100644 --- a/source/blender/blenlib/BLI_vector.h +++ b/source/blender/blenlib/BLI_vector.h @@ -50,7 +50,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve Allocator m_allocator; char m_small_buffer[sizeof(T) * N]; -#ifdef DEBUG +#ifndef NDEBUG /* Storing size in debug builds, because it makes debugging much easier sometimes. */ uint m_debug_size; # define UPDATE_VECTOR_SIZE(ptr) (ptr)->m_debug_size = (uint)((ptr)->m_end - (ptr)->m_begin) @@ -419,7 +419,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve { BLI_assert(!this->empty()); m_end--; - T value = *m_end; + T value = std::move(*m_end); destruct(m_end); UPDATE_VECTOR_SIZE(this); return value; @@ -435,7 +435,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve T *element_to_remove = m_begin + index; m_end--; if (element_to_remove < m_end) { - *element_to_remove = *m_end; + *element_to_remove = std::move(*m_end); } destruct(m_end); UPDATE_VECTOR_SIZE(this); @@ -512,6 +512,14 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve return m_end; } + /** + * Get the current capacity of the vector. + */ + uint capacity() const + { + return (uint)(m_capacity_end - m_begin); + } + void print_stats() const { std::cout << "Small Vector at " << (void *)this << ":" << std::endl; @@ -538,11 +546,6 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve } } - uint capacity() const - { - return (uint)(m_capacity_end - m_begin); - } - BLI_NOINLINE void grow(uint min_capacity) { if (this->capacity() >= min_capacity) { diff --git a/source/blender/blenlib/BLI_set_vector.h b/source/blender/blenlib/BLI_vector_set.h index c0b99d568cc..fb21f7ed987 100644 --- a/source/blender/blenlib/BLI_set_vector.h +++ b/source/blender/blenlib/BLI_vector_set.h @@ -14,15 +14,15 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __BLI_SET_VECTOR_H__ -#define __BLI_SET_VECTOR_H__ +#ifndef __BLI_VECTOR_SET_H__ +#define __BLI_VECTOR_SET_H__ /** \file * \ingroup bli * - * A SetVector is a combination of a set and a vector. The elements are stored in a continuous - * array, but every element exists at most once. The insertion order is maintained, as long as - * there are no deletes. The expected time to check if a value is in the SetVector is O(1). + * A VectorSet is a set built on top of a vector. The elements are stored in a continuous array, + * but every element exists at most once. The insertion order is maintained, as long as there are + * no deletes. The expected time to check if a value is in the VectorSet is O(1). */ #include "BLI_hash_cxx.h" @@ -49,7 +49,7 @@ namespace BLI { // clang-format on -template<typename T, typename Allocator = GuardedAllocator> class SetVector { +template<typename T, typename Allocator = GuardedAllocator> class VectorSet { private: static constexpr int32_t IS_EMPTY = -1; static constexpr int32_t IS_DUMMY = -2; @@ -115,19 +115,22 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { Vector<T, 4, Allocator> m_elements; public: - SetVector() = default; + VectorSet() + { + BLI_assert(m_array.slots_usable() <= m_elements.capacity()); + } - SetVector(ArrayRef<T> values) + VectorSet(ArrayRef<T> values) : VectorSet() { this->add_multiple(values); } - SetVector(const std::initializer_list<T> &values) + VectorSet(const std::initializer_list<T> &values) : VectorSet() { this->add_multiple(values); } - SetVector(const Vector<T> &values) + VectorSet(const Vector<T> &values) : VectorSet() { this->add_multiple(values); } @@ -147,15 +150,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { */ void add_new(const T &value) { - BLI_assert(!this->contains(value)); - this->ensure_can_add(); - ITER_SLOTS_BEGIN (value, m_array, , slot) { - if (slot.is_empty()) { - this->add_new_in_slot(slot, value); - return; - } - } - ITER_SLOTS_END; + this->add_new__impl(value); + } + void add_new(T &&value) + { + this->add_new__impl(std::move(value)); } /** @@ -163,17 +162,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { */ bool add(const T &value) { - this->ensure_can_add(); - ITER_SLOTS_BEGIN (value, m_array, , slot) { - if (slot.is_empty()) { - this->add_new_in_slot(slot, value); - return true; - } - else if (slot.has_value(value, m_elements)) { - return false; - } - } - ITER_SLOTS_END; + return this->add__impl(value); + } + bool add(T &&value) + { + return this->add__impl(std::move(value)); } /** @@ -284,16 +277,6 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { return m_array.slots_set(); } - T *begin() - { - return m_elements.begin(); - } - - T *end() - { - return m_elements.end(); - } - const T *begin() const { return m_elements.begin(); @@ -319,6 +302,15 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { return m_elements; } + void print_stats() const + { + std::cout << "VectorSet at " << (void *)this << ":\n"; + std::cout << " Size: " << this->size() << "\n"; + std::cout << " Usable Slots: " << m_array.slots_usable() << "\n"; + std::cout << " Total Slots: " << m_array.slots_total() << "\n"; + std::cout << " Average Collisions: " << this->compute_average_collisions() << "\n"; + } + private: void update_slot_index(T &value, uint old_index, uint new_index) { @@ -332,11 +324,11 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { ITER_SLOTS_END; } - void add_new_in_slot(Slot &slot, const T &value) + template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value) { uint index = m_elements.size(); slot.set_index(index); - m_elements.append(value); + m_elements.append_unchecked(std::forward<ForwardT>(value)); m_array.update__empty_to_set(); } @@ -356,6 +348,7 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { } m_array = std::move(new_array); + m_elements.reserve(m_array.slots_usable()); } void add_after_grow(uint index, ArrayType &new_array) @@ -369,6 +362,59 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { } ITER_SLOTS_END; } + + float compute_average_collisions() const + { + if (m_elements.size() == 0) { + return 0.0f; + } + + uint collisions_sum = 0; + for (const T &value : m_elements) { + collisions_sum += this->count_collisions(value); + } + return (float)collisions_sum / (float)m_elements.size(); + } + + uint count_collisions(const T &value) const + { + uint collisions = 0; + ITER_SLOTS_BEGIN (value, m_array, const, slot) { + if (slot.is_empty() || slot.has_value(value, m_elements)) { + return collisions; + } + collisions++; + } + ITER_SLOTS_END; + } + + template<typename ForwardT> void add_new__impl(ForwardT &&value) + { + BLI_assert(!this->contains(value)); + this->ensure_can_add(); + ITER_SLOTS_BEGIN (value, m_array, , slot) { + if (slot.is_empty()) { + this->add_new_in_slot(slot, std::forward<ForwardT>(value)); + return; + } + } + ITER_SLOTS_END; + } + + template<typename ForwardT> bool add__impl(ForwardT &&value) + { + this->ensure_can_add(); + ITER_SLOTS_BEGIN (value, m_array, , slot) { + if (slot.is_empty()) { + this->add_new_in_slot(slot, std::forward<ForwardT>(value)); + return true; + } + else if (slot.has_value(value, m_elements)) { + return false; + } + } + ITER_SLOTS_END; + } }; #undef ITER_SLOTS_BEGIN @@ -376,4 +422,4 @@ template<typename T, typename Allocator = GuardedAllocator> class SetVector { } // namespace BLI -#endif /* __BLI_SET_VECTOR_H__ */ +#endif /* __BLI_VECTOR_SET_H__ */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index a5950051f90..f3740b5d39f 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -221,7 +221,6 @@ set(SRC BLI_rect.h BLI_scanfill.h BLI_set.h - BLI_set_vector.h BLI_smallhash.h BLI_sort.h BLI_sort_utils.h @@ -248,6 +247,7 @@ set(SRC BLI_utildefines_variadic.h BLI_uvproject.h BLI_vector.h + BLI_vector_set.h BLI_vfontdata.h BLI_voronoi_2d.h BLI_voxel.h diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index ae4f5dcebcf..0fe9fd62198 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -325,7 +325,7 @@ void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdat #include "list_sort_impl.h" #undef SORT_IMPL_FUNC -/* reentrant call */ +/* re-entrant call */ #define SORT_IMPL_USE_THUNK #define SORT_IMPL_FUNC linklist_sort_fn_r #include "list_sort_impl.h" diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c index f26860afe77..f7239f1b9d1 100644 --- a/source/blender/blenlib/intern/BLI_memblock.c +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -37,7 +37,6 @@ #include "BLI_strict_flags.h" /* keep last */ -#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */ #define CHUNK_LIST_SIZE 16 struct BLI_memblock { @@ -61,18 +60,19 @@ struct BLI_memblock { int chunk_len; }; -BLI_memblock *BLI_memblock_create(uint elem_size) +BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) { - BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE); + BLI_assert(elem_size < chunk_size); BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock"); mblk->elem_size = (int)elem_size; mblk->elem_next = 0; mblk->elem_last = -1; - mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE; + mblk->chunk_size = (int)chunk_size; mblk->chunk_len = CHUNK_LIST_SIZE; mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list"); - mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk"); + mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk"); + memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size); mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size; mblk->elem_next_ofs = 0; mblk->chunk_next = 0; @@ -143,8 +143,9 @@ void *BLI_memblock_alloc(BLI_memblock *mblk) } if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) { - mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size, - "BLI_memblock chunk"); + mblk->chunk_list[mblk->chunk_next] = MEM_mallocN_aligned( + (uint)mblk->chunk_size, 32, "BLI_memblock chunk"); + memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size); } } return ptr; @@ -180,3 +181,11 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter) } return ptr; } + +/* Direct access. elem is element index inside the chosen chunk. */ +void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) +{ + BLI_assert(chunk < mblk->chunk_len); + BLI_assert(elem < (mblk->chunk_size / mblk->elem_size)); + return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem; +} diff --git a/source/blender/blenlib/intern/BLI_temporary_allocator.cc b/source/blender/blenlib/intern/BLI_temporary_allocator.cc index e41cf36f66d..b145e65530d 100644 --- a/source/blender/blenlib/intern/BLI_temporary_allocator.cc +++ b/source/blender/blenlib/intern/BLI_temporary_allocator.cc @@ -73,7 +73,7 @@ struct ThreadLocalBuffers { } }; -thread_local ThreadLocalBuffers local_storage; +static thread_local ThreadLocalBuffers local_storage; void *BLI_temporary_allocate(uint size) { diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c index 0443dea9a2e..af987587d90 100644 --- a/source/blender/blenlib/intern/BLI_timer.c +++ b/source/blender/blenlib/intern/BLI_timer.c @@ -42,7 +42,6 @@ typedef struct TimedFunction { typedef struct TimerContainer { ListBase funcs; - bool file_load_cb_registered; } TimerContainer; static TimerContainer GlobalTimer = {{0}}; diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index d5dcd40346f..af4fa9fa54e 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -325,6 +325,18 @@ static bool exists_edge(const CDTVert *a, const CDTVert *b) return false; } +/** Is the vertex v incident on face f? */ +static bool vert_touches_face(const CDTVert *v, const CDTFace *f) +{ + SymEdge *se = v->symedge; + do { + if (se->face == f) { + return true; + } + } while ((se = se->rot) != v->symedge); + return false; +} + /** * Assume s1 and s2 are both SymEdges in a face with > 3 sides, * and one is not the next of the other. @@ -1901,35 +1913,108 @@ static void dissolve_symedge(CDT_state *cdt, SymEdge *se) delete_edge(cdt, se); } -static void remove_non_constraint_edges(CDT_state *cdt, const bool valid_bmesh) +/* Remove all non-constraint edges. */ +static void remove_non_constraint_edges(CDT_state *cdt) +{ + LinkNode *ln; + CDTEdge *e; + SymEdge *se; + + for (ln = cdt->edges; ln; ln = ln->next) { + e = (CDTEdge *)ln->link; + se = &e->symedges[0]; + if (!is_deleted_edge(e) && !is_constrained_edge(e)) { + dissolve_symedge(cdt, se); + } + } +} + +/* + * Remove the non-constraint edges, but leave enough of them so that all of the + * faces that would be bmesh faces (that is, the faces that have some input representative) + * are valid: they can't have holes, they can't have repeated vertices, and they can't have + * repeated edges. + * + * Not essential, but to make the result look more aesthetically nice, + * remove the edges in order of decreasing length, so that it is more likely that the + * final remaining support edges are short, and therefore likely to make a fairly + * direct path from an outer face to an inner hole face. + */ + +/* For sorting edges by decreasing length (squared). */ +struct EdgeToSort { + double len_squared; + CDTEdge *e; +}; + +static int edge_to_sort_cmp(const void *a, const void *b) +{ + const struct EdgeToSort *e1 = a; + const struct EdgeToSort *e2 = b; + + if (e1->len_squared > e2->len_squared) { + return -1; + } + else if (e1->len_squared < e2->len_squared) { + return 1; + } + return 0; +} + +static void remove_non_constraint_edges_leave_valid_bmesh(CDT_state *cdt) { LinkNode *ln; CDTEdge *e; SymEdge *se, *se2; CDTFace *fleft, *fright; bool dissolve; + size_t nedges; + int i, ndissolvable; + const double *co1, *co2; + struct EdgeToSort *sorted_edges; + nedges = 0; + for (ln = cdt->edges; ln; ln = ln->next) { + nedges++; + } + if (nedges == 0) { + return; + } + sorted_edges = BLI_memarena_alloc(cdt->arena, nedges * sizeof(*sorted_edges)); + i = 0; for (ln = cdt->edges; ln; ln = ln->next) { e = (CDTEdge *)ln->link; - dissolve = !is_deleted_edge(e) && !is_constrained_edge(e); - if (dissolve) { - se = &e->symedges[0]; - if (valid_bmesh && !edge_touches_frame(e)) { - fleft = se->face; - fright = sym(se)->face; - if (fleft != cdt->outer_face && fright != cdt->outer_face && - (fleft->input_ids != NULL || fright->input_ids != NULL)) { - /* Is there another symedge with same left and right faces? */ - for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) { - if (sym(se2)->face == fright) { - dissolve = false; - } + if (!is_deleted_edge(e) && !is_constrained_edge(e)) { + sorted_edges[i].e = e; + co1 = e->symedges[0].vert->co; + co2 = e->symedges[1].vert->co; + sorted_edges[i].len_squared = len_squared_v2v2_db(co1, co2); + i++; + } + } + ndissolvable = i; + qsort(sorted_edges, ndissolvable, sizeof(*sorted_edges), edge_to_sort_cmp); + for (i = 0; i < ndissolvable; i++) { + e = sorted_edges[i].e; + se = &e->symedges[0]; + dissolve = true; + if (!edge_touches_frame(e)) { + fleft = se->face; + fright = sym(se)->face; + if (fleft != cdt->outer_face && fright != cdt->outer_face && + (fleft->input_ids != NULL || fright->input_ids != NULL)) { + /* Is there another symedge with same left and right faces? + * Or is there a vertex not part of e touching the same left and right faces? */ + for (se2 = se->next; dissolve && se2 != se; se2 = se2->next) { + if (sym(se2)->face == fright || + (se2->vert != se->next->vert && vert_touches_face(se2->vert, fright))) { + dissolve = false; } } } - if (dissolve) { - dissolve_symedge(cdt, se); - } + } + if (dissolve) { + dissolve_symedge(cdt, se); } } } @@ -2066,8 +2151,11 @@ static void prepare_cdt_for_output(CDT_state *cdt, const CDT_output_type output_ UNUSED_VARS(f); #endif - if (output_type == CDT_CONSTRAINTS || output_type == CDT_CONSTRAINTS_VALID_BMESH) { - remove_non_constraint_edges(cdt, output_type == CDT_CONSTRAINTS_VALID_BMESH); + if (output_type == CDT_CONSTRAINTS) { + remove_non_constraint_edges(cdt); + } + else if (output_type == CDT_CONSTRAINTS_VALID_BMESH) { + remove_non_constraint_edges_leave_valid_bmesh(cdt); } else if (output_type == CDT_FULL || output_type == CDT_INSIDE) { remove_outer_edges(cdt, output_type == CDT_INSIDE); diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c index 14fc4c5bf26..c7631f8991e 100644 --- a/source/blender/blenlib/intern/expr_pylike_eval.c +++ b/source/blender/blenlib/intern/expr_pylike_eval.c @@ -504,7 +504,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void * if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) { UnaryOpFunc func = funcptr; - double result = func(prev_ops[-1].arg.dval); + /* volatile because some compilers overly aggressive optimize this call out. + * see D6012 for details. */ + volatile double result = func(prev_ops[-1].arg.dval); if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { prev_ops[-1].arg.dval = result; @@ -520,7 +522,9 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void * prev_ops[-1].opcode == OPCODE_CONST) { BinaryOpFunc func = funcptr; - double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); + /* volatile because some compilers overly aggressive optimize this call out. + * see D6012 for details. */ + volatile double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { prev_ops[-2].arg.dval = result; diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 1de8744a6a6..3a45989fb63 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -33,16 +33,24 @@ #include "zlib.h" #ifdef WIN32 +# include <windows.h> +# include <shellapi.h> +# include <shobjidl.h> # include <io.h> # include "BLI_winstuff.h" # include "BLI_fileops_types.h" # include "utf_winfunc.h" # include "utfconv.h" #else +# if defined(__APPLE__) +# include <CoreFoundation/CoreFoundation.h> +# include <objc/runtime.h> +# include <objc/message.h> +# endif # include <sys/param.h> # include <dirent.h> # include <unistd.h> -# include <sys/stat.h> +# include <sys/wait.h> #endif #include "MEM_guardedalloc.h" @@ -288,6 +296,64 @@ int BLI_access(const char *filename, int mode) return uaccess(filename, mode); } +static bool delete_soft(const wchar_t *path_16, const char **error_message) +{ + /* Deletes file or directory to recycling bin. The latter moves all contained files and + * directories recursively to the recycling bin as well. */ + IFileOperation *pfo; + IShellItem *pSI; + + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + if (FAILED(hr)) { + *error_message = "Failed to initialize COM"; + goto error_1; + } + + hr = CoCreateInstance( + &CLSID_FileOperation, NULL, CLSCTX_ALL, &IID_IFileOperation, (void **)&pfo); + if (FAILED(hr)) { + *error_message = "Failed to create FileOperation instance"; + goto error_2; + } + + /* Flags for deletion: + * FOF_ALLOWUNDO: Enables moving file to recycling bin. + * FOF_SILENT: Don't show progress dialog box. + * FOF_WANTNUKEWARNING: Show dialog box if file can't be moved to recycling bin. */ + hr = pfo->lpVtbl->SetOperationFlags(pfo, FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING); + + if (FAILED(hr)) { + *error_message = "Failed to set operation flags"; + goto error_2; + } + + hr = SHCreateItemFromParsingName(path_16, NULL, &IID_IShellItem, (void **)&pSI); + if (FAILED(hr)) { + *error_message = "Failed to parse path"; + goto error_2; + } + + hr = pfo->lpVtbl->DeleteItem(pfo, pSI, NULL); + if (FAILED(hr)) { + *error_message = "Failed to prepare delete operation"; + goto error_2; + } + + hr = pfo->lpVtbl->PerformOperations(pfo); + + if (FAILED(hr)) { + *error_message = "Failed to delete file or directory"; + } + +error_2: + pfo->lpVtbl->Release(pfo); + CoUninitialize(); /* Has to be uninitialized when CoInitializeEx returns either S_OK or S_FALSE + */ +error_1: + return FAILED(hr); +} + static bool delete_unique(const char *path, const bool dir) { bool err; @@ -370,6 +436,24 @@ int BLI_delete(const char *file, bool dir, bool recursive) return err; } +/** + * Moves the files or directories to the recycling bin. + */ +int BLI_delete_soft(const char *file, const char **error_message) +{ + int err; + + BLI_assert(!BLI_path_is_rel(file)); + + UTF16_ENCODE(file); + + err = delete_soft(file_16, error_message); + + UTF16_UN_ENCODE(file); + + return err; +} + /* Not used anywhere! */ # if 0 int BLI_move(const char *file, const char *to) @@ -720,6 +804,100 @@ static int delete_single_file(const char *from, const char *UNUSED(to)) return RecursiveOp_Callback_OK; } +# ifdef __APPLE__ +static int delete_soft(const char *file, const char **error_message) +{ + int ret = -1; + + Class NSAutoreleasePoolClass = objc_getClass("NSAutoreleasePool"); + SEL allocSel = sel_registerName("alloc"); + SEL initSel = sel_registerName("init"); + id poolAlloc = ((id(*)(Class, SEL))objc_msgSend)(NSAutoreleasePoolClass, allocSel); + id pool = ((id(*)(id, SEL))objc_msgSend)(poolAlloc, initSel); + + Class NSStringClass = objc_getClass("NSString"); + SEL stringWithUTF8StringSel = sel_registerName("stringWithUTF8String:"); + id pathString = ((id(*)(Class, SEL, const char *))objc_msgSend)( + NSStringClass, stringWithUTF8StringSel, file); + + Class NSFileManagerClass = objc_getClass("NSFileManager"); + SEL defaultManagerSel = sel_registerName("defaultManager"); + id fileManager = ((id(*)(Class, SEL))objc_msgSend)(NSFileManagerClass, defaultManagerSel); + + Class NSURLClass = objc_getClass("NSURL"); + SEL fileURLWithPathSel = sel_registerName("fileURLWithPath:"); + id nsurl = ((id(*)(Class, SEL, id))objc_msgSend)(NSURLClass, fileURLWithPathSel, pathString); + + SEL trashItemAtURLSel = sel_registerName("trashItemAtURL:resultingItemURL:error:"); + BOOL deleteSuccessful = ((BOOL(*)(id, SEL, id, id, id))objc_msgSend)( + fileManager, trashItemAtURLSel, nsurl, nil, nil); + + if (deleteSuccessful) { + ret = 0; + } + else { + *error_message = "The Cocoa API call to delete file or directory failed"; + } + + SEL drainSel = sel_registerName("drain"); + ((void (*)(id, SEL))objc_msgSend)(pool, drainSel); + + return ret; +} +# else +static int delete_soft(const char *file, const char **error_message) +{ + const char *args[5]; + const char *process_failed; + + char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP"); + char *xdg_session_desktop = getenv("XDG_SESSION_DESKTOP"); + + if ((xdg_current_desktop != NULL && strcmp(xdg_current_desktop, "KDE") == 0) || + (xdg_session_desktop != NULL && strcmp(xdg_session_desktop, "KDE") == 0)) { + args[0] = "kioclient5"; + args[1] = "move"; + args[2] = file; + args[3] = "trash:/"; + args[4] = NULL; + process_failed = "kioclient5 reported failure"; + } + else { + args[0] = "gio"; + args[1] = "trash"; + args[2] = file; + args[3] = NULL; + process_failed = "gio reported failure"; + } + + int pid = fork(); + + if (pid != 0) { + /* Parent process */ + int wstatus = 0; + + waitpid(pid, &wstatus, 0); + + if (!WIFEXITED(wstatus)) { + *error_message = + "Blender may not support moving files or directories to trash on your system."; + return -1; + } + else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus)) { + *error_message = process_failed; + return -1; + } + + return 0; + } + + execvp(args[0], (char **)args); + + *error_message = "Forking process failed."; + return -1; /* This should only be reached if execvp fails and stack isn't replaced. */ +} +# endif + FILE *BLI_fopen(const char *filename, const char *mode) { BLI_assert(!BLI_path_is_rel(filename)); @@ -770,7 +948,20 @@ int BLI_delete(const char *file, bool dir, bool recursive) } /** - * Do the two paths denote the same filesystem object? + * Soft deletes the specified file or directory (depending on dir) by moving the files to the + * recycling bin, optionally doing recursive delete of directory contents. + * + * \return zero on success (matching 'remove' behavior). + */ +int BLI_delete_soft(const char *file, const char **error_message) +{ + BLI_assert(!BLI_path_is_rel(file)); + + return delete_soft(file, error_message); +} + +/** + * Do the two paths denote the same file-system object? */ static bool check_the_same(const char *path_a, const char *path_b) { diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c index 6d0fdfacb10..5e1fbf6eade 100644 --- a/source/blender/blenlib/intern/gsqueue.c +++ b/source/blender/blenlib/intern/gsqueue.c @@ -12,9 +12,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. */ /** \file @@ -22,9 +19,6 @@ * * \brief A generic structure queue * (a queue for fixed length generally small) structures. - * - * \note Only use this if you need (first-in-first-out), - * otherwise #BLI_Stack is more efficient (first-in-last-out). */ #include <string.h> @@ -35,148 +29,168 @@ #include "BLI_gsqueue.h" #include "BLI_strict_flags.h" -typedef struct _GSQueueElem GSQueueElem; -struct _GSQueueElem { - GSQueueElem *next; +/* target chunk size: 64kb */ +#define CHUNK_SIZE_DEFAULT (1 << 16) +/* ensure we get at least this many elems per chunk */ +#define CHUNK_ELEM_MIN 32 + +struct QueueChunk { + struct QueueChunk *next; char data[0]; }; struct _GSQueue { - GSQueueElem *head; - GSQueueElem *tail; - size_t elem_size; + struct QueueChunk *chunk_first; /* first active chunk to pop from */ + struct QueueChunk *chunk_last; /* flast active chunk to push onto */ + struct QueueChunk *chunk_free; /* free chunks to reuse */ + size_t chunk_first_index; /* index into 'chunk_first' */ + size_t chunk_last_index; /* index into 'chunk_last' */ + size_t chunk_elem_max; /* number of elements per chunk */ + size_t elem_size; /* memory size of elements */ + size_t totelem; /* total number of elements */ }; -/** - * Create a new GSQueue. - * - * \param elem_size: The size of the structures in the queue. - * \retval The new queue - */ -GSQueue *BLI_gsqueue_new(size_t elem_size) +static void *queue_get_first_elem(GSQueue *queue) { - GSQueue *gq = MEM_mallocN(sizeof(*gq), "gqueue_new"); - gq->head = gq->tail = NULL; - gq->elem_size = elem_size; - - return gq; + return ((char *)(queue)->chunk_first->data) + ((queue)->elem_size * (queue)->chunk_first_index); } -/** - * Query if the queue is empty - */ -bool BLI_gsqueue_is_empty(GSQueue *gq) +static void *queue_get_last_elem(GSQueue *queue) { - return (gq->head == NULL); + return ((char *)(queue)->chunk_last->data) + ((queue)->elem_size * (queue)->chunk_last_index); } /** - * Query number elements in the queue + * \return number of elements per chunk, optimized for slop-space. */ -int BLI_gsqueue_len(GSQueue *gq) +static size_t queue_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size) { - GSQueueElem *elem; - int size = 0; + /* get at least this number of elems per chunk */ + const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN; - for (elem = gq->head; elem; elem = elem->next) { - size++; + BLI_assert((elem_size != 0) && (chunk_size != 0)); + + while (UNLIKELY(chunk_size <= elem_size_min)) { + chunk_size <<= 1; } - return size; + /* account for slop-space */ + chunk_size -= (sizeof(struct QueueChunk) + MEM_SIZE_OVERHEAD); + + return chunk_size / elem_size; } -/** - * Access the item at the head of the queue - * without removing it. - * - * \param r_item: A pointer to an appropriately - * sized structure (the size passed to #BLI_gsqueue_new) - */ -void BLI_gsqueue_peek(GSQueue *gq, void *r_item) +GSQueue *BLI_gsqueue_new(const size_t elem_size) { - memcpy(r_item, &gq->head->data, gq->elem_size); + GSQueue *queue = MEM_callocN(sizeof(*queue), "BLI_gsqueue_new"); + + queue->chunk_elem_max = queue_chunk_elem_max_calc(elem_size, CHUNK_SIZE_DEFAULT); + queue->elem_size = elem_size; + /* force init */ + queue->chunk_last_index = queue->chunk_elem_max - 1; + + return queue; } -/** - * Access the item at the head of the queue - * and remove it. - * - * \param r_item: A pointer to an appropriately - * sized structure (the size passed to #BLI_gsqueue_new). - * Can be NULL if desired. - */ -void BLI_gsqueue_pop(GSQueue *gq, void *r_item) +static void queue_free_chunk(struct QueueChunk *data) { - GSQueueElem *elem = gq->head; - if (elem == gq->tail) { - gq->head = gq->tail = NULL; - } - else { - gq->head = gq->head->next; + while (data) { + struct QueueChunk *data_next = data->next; + MEM_freeN(data); + data = data_next; } +} - if (r_item) { - memcpy(r_item, elem->data, gq->elem_size); - } - MEM_freeN(elem); +/** + * Free the queue's data and the queue itself + */ +void BLI_gsqueue_free(GSQueue *queue) +{ + queue_free_chunk(queue->chunk_first); + queue_free_chunk(queue->chunk_free); + MEM_freeN(queue); } /** - * Push an element onto the tail of the queue. + * Copies the source value onto the end of the queue * - * \param item: A pointer to an appropriately - * sized structure (the size passed to BLI_gsqueue_new). + * \note This copies #GSQueue.elem_size bytes from \a src, + * (the pointer itself is not stored). + * + * \param src: source data to be copied to the queue. */ -void BLI_gsqueue_push(GSQueue *gq, const void *item) +void BLI_gsqueue_push(GSQueue *queue, const void *src) { - GSQueueElem *elem; + queue->chunk_last_index++; + queue->totelem++; + + if (UNLIKELY(queue->chunk_last_index == queue->chunk_elem_max)) { + struct QueueChunk *chunk; + if (queue->chunk_free) { + chunk = queue->chunk_free; + queue->chunk_free = chunk->next; + } + else { + chunk = MEM_mallocN(sizeof(*chunk) + (queue->elem_size * queue->chunk_elem_max), __func__); + } - /* compare: prevent events added double in row */ - if (!BLI_gsqueue_is_empty(gq)) { - if (0 == memcmp(item, gq->head->data, gq->elem_size)) { - return; + chunk->next = NULL; + + if (queue->chunk_last == NULL) { + queue->chunk_first = chunk; + } + else { + queue->chunk_last->next = chunk; } - } - elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push"); - memcpy(elem->data, item, gq->elem_size); - elem->next = NULL; - if (BLI_gsqueue_is_empty(gq)) { - gq->tail = gq->head = elem; - } - else { - gq->tail = gq->tail->next = elem; + queue->chunk_last = chunk; + queue->chunk_last_index = 0; } + + BLI_assert(queue->chunk_last_index < queue->chunk_elem_max); + + /* Return last of queue */ + memcpy(queue_get_last_elem(queue), src, queue->elem_size); } /** - * Push an element back onto the head of the queue (so - * it would be returned from the next call to BLI_gsqueue_pop). + * Retrieves and removes the first element from the queue. + * The value is copies to \a dst, which must be at least \a elem_size bytes. * - * \param item: A pointer to an appropriately - * sized structure (the size passed to BLI_gsqueue_new). + * Does not reduce amount of allocated memory. */ -void BLI_gsqueue_push_back(GSQueue *gq, const void *item) +void BLI_gsqueue_pop(GSQueue *queue, void *dst) { - GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push"); - memcpy(elem->data, item, gq->elem_size); - elem->next = gq->head; + BLI_assert(BLI_gsqueue_is_empty(queue) == false); - if (BLI_gsqueue_is_empty(gq)) { - gq->head = gq->tail = elem; - } - else { - gq->head = elem; + memcpy(dst, queue_get_first_elem(queue), queue->elem_size); + queue->chunk_first_index++; + queue->totelem--; + + if (UNLIKELY(queue->chunk_first_index == queue->chunk_elem_max || queue->totelem == 0)) { + struct QueueChunk *chunk_free = queue->chunk_first; + + queue->chunk_first = queue->chunk_first->next; + queue->chunk_first_index = 0; + if (queue->chunk_first == NULL) { + queue->chunk_last = NULL; + queue->chunk_last_index = queue->chunk_elem_max - 1; + } + + chunk_free->next = queue->chunk_free; + queue->chunk_free = chunk_free; } } +size_t BLI_gsqueue_len(const GSQueue *queue) +{ + return queue->totelem; +} + /** - * Free the queue + * Returns true if the queue is empty, false otherwise */ -void BLI_gsqueue_free(GSQueue *gq) +bool BLI_gsqueue_is_empty(const GSQueue *queue) { - while (gq->head) { - BLI_gsqueue_pop(gq, NULL); - } - MEM_freeN(gq); + return (queue->chunk_first == NULL); } diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 232dc245152..fe5f9f7673f 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -312,7 +312,7 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase) #include "list_sort_impl.h" #undef SORT_IMPL_FUNC -/* reentrant call */ +/* re-entrant call */ #define SORT_IMPL_USE_THUNK #define SORT_IMPL_FUNC listbase_sort_fn_r #include "list_sort_impl.h" diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index e9d196ccdbb..33e272ed7eb 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1146,8 +1146,8 @@ bool invert_m4(float m[4][4]) * \return true on success (i.e. can always find a pivot) and false on failure. * Mark Segal - 1992. * - * \note this is less performant than #EIG_invert_m4_m4 (Eigen), but e.g. - * for non-invertible scale matrices, findinging a partial solution can + * \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g. + * for non-invertible scale matrices, finding a partial solution can * be useful to have a valid local transform center, see T57767. */ bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4]) diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c index a1c3d16a404..235589abdab 100644 --- a/source/blender/blenlib/intern/math_solvers.c +++ b/source/blender/blenlib/intern/math_solvers.c @@ -215,10 +215,10 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta, fdeltav = len_squared_v3(fdelta); if (trace) { - printf("START (%g, %g, %g) %g\n", x[0], x[1], x[2], fdeltav); + printf("START (%g, %g, %g) %g %g\n", x[0], x[1], x[2], fdeltav, epsilon); } - for (int i = 0; i < max_iterations && fdeltav > epsilon; i++) { + for (int i = 0; i == 0 || (i < max_iterations && fdeltav > epsilon); i++) { /* Newton's method step. */ func_jacobian(userdata, x, jacobian); @@ -248,7 +248,7 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta, } /* Line search correction. */ - while (next_fdeltav > fdeltav) { + while (next_fdeltav > fdeltav && next_fdeltav > epsilon) { float g0 = sqrtf(fdeltav), g1 = sqrtf(next_fdeltav); float g01 = -g0 / len_v3(step); float det = 2.0f * (g1 - g0 - g01); diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 08c3653153e..c9b0eb3ed5e 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -907,7 +907,7 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const return 0; } - axis_dominant_v3_to_m3(mat_2d, n); + axis_dominant_v3_to_m3_negate(mat_2d, n); } /* STEP 1: COUNT POLYS */ diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c index 225015db00d..4ae87fff535 100644 --- a/source/blender/blenlib/intern/sort.c +++ b/source/blender/blenlib/intern/sort.c @@ -90,7 +90,7 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk } /** - * Quick sort reentrant. + * Quick sort re-entrant. */ void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk) { diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c index 76aef3761ae..301675c026e 100644 --- a/source/blender/blenlib/intern/stack.c +++ b/source/blender/blenlib/intern/stack.c @@ -36,10 +36,6 @@ /* ensure we get at least this many elems per chunk */ #define CHUNK_ELEM_MIN 32 -/* Gets the last element in the stack */ -#define CHUNK_LAST_ELEM(_stack) \ - ((void)0, (((char *)(_stack)->chunk_curr->data) + ((_stack)->elem_size * (_stack)->chunk_index))) - struct StackChunk { struct StackChunk *next; char data[0]; @@ -56,6 +52,11 @@ struct BLI_Stack { #endif }; +static void *stack_get_last_elem(BLI_Stack *stack) +{ + return ((char *)(stack)->chunk_curr->data) + ((stack)->elem_size * (stack)->chunk_index); +} + /** * \return number of elements per chunk, optimized for slop-space. */ @@ -148,7 +149,7 @@ void *BLI_stack_push_r(BLI_Stack *stack) #endif /* Return end of stack */ - return CHUNK_LAST_ELEM(stack); + return stack_get_last_elem(stack); } /** @@ -175,7 +176,7 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst) { BLI_assert(BLI_stack_is_empty(stack) == false); - memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size); + memcpy(dst, stack_get_last_elem(stack), stack->elem_size); BLI_stack_discard(stack); } @@ -220,7 +221,7 @@ void *BLI_stack_peek(BLI_Stack *stack) { BLI_assert(BLI_stack_is_empty(stack) == false); - return CHUNK_LAST_ELEM(stack); + return stack_get_last_elem(stack); } /** diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 8d921b062dc..fd5de717a24 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -209,7 +209,6 @@ int BLI_exists(const char *name) BLI_stat_t st; wchar_t *tmp_16 = alloc_utf16_from_8(name, 1); int len, res; - unsigned int old_error_mode; len = wcslen(tmp_16); /* in Windows #stat doesn't recognize dir ending on a slash @@ -230,14 +229,8 @@ int BLI_exists(const char *name) tmp_16[3] = L'\0'; } - /* change error mode so user does not get a "no disk in drive" popup - * when looking for a file on an empty CD/DVD drive */ - old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); - res = BLI_wstat(tmp_16, &st); - SetErrorMode(old_error_mode); - free(tmp_16); if (res == -1) { return (0); diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 2f6c88c128a..6cdaec97d9a 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -1064,22 +1064,28 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings * chunk_size = settings->min_iter_per_thread; } else { - /* Basic heuristic to avoid threading on low amount of items. We could make that limit - * configurable in settings too... */ - if (tot_items > 0 && tot_items < 256) { - chunk_size = tot_items; - } - /* NOTE: The idea here is to compensate for rather measurable threading + /* Multiplier used in heuristics below to define "optimal" chunk size. + * The idea here is to increase the chunk size to compensate for a rather measurable threading * overhead caused by fetching tasks. With too many CPU threads we are starting - * to spend too much time in those overheads. */ - else if (num_tasks > 32) { - chunk_size = 128; - } - else if (num_tasks > 16) { - chunk_size = 64; - } - else { - chunk_size = 32; + * to spend too much time in those overheads. + * First values are: 1 if num_tasks < 16; + * else 2 if num_tasks < 32; + * else 3 if num_tasks < 48; + * else 4 if num_tasks < 64; + * etc. + * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like: + * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3) + */ + const int num_tasks_factor = max_ii(1, num_tasks >> 3); + + /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just + * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */ + chunk_size = 32 * num_tasks_factor; + + /* Basic heuristic to avoid threading on low amount of items. + * We could make that limit configurable in settings too. */ + if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) { + chunk_size = tot_items; } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6bebcc88e41..2c5134a7dc5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -24,15 +24,12 @@ #include "zlib.h" #include <limits.h> -#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE -#include <stdlib.h> // for getenv atoi -#include <stddef.h> // for offsetof -#include <fcntl.h> // for open -#include <string.h> // for strrchr strncmp strstr -#include <math.h> // for fabs -#include <stdarg.h> /* for va_start/end */ -#include <time.h> /* for gmtime */ -#include <ctype.h> /* for isdigit */ +#include <stdlib.h> /* for atoi. */ +#include <stddef.h> /* for offsetof. */ +#include <fcntl.h> /* for open flags (O_BINARY, O_RDONLY). */ +#include <stdarg.h> /* for va_start/end. */ +#include <time.h> /* for gmtime. */ +#include <ctype.h> /* for isdigit. */ #include "BLI_utildefines.h" #ifndef WIN32 @@ -96,8 +93,6 @@ #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" -#include "RNA_access.h" - #include "MEM_guardedalloc.h" #include "BLI_endian_switch.h" @@ -180,7 +175,7 @@ * - read associated 'direct data' * - link direct data (internal and to LibBlock) * - read #FileGlobal - * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``) + * - read #USER data, only when indicated (file is `~/.config/blender/X.XX/config/userpref.blend`) * - free file * - per Library (per #Main) * - read file @@ -2663,6 +2658,7 @@ static void direct_link_id(FileData *fd, ID *id) * function are still in a clear tag state. * (glowering at certain nodetree fake data-lock here...). */ id->tag = 0; + id->flag &= ~LIB_INDIRECT_WEAK_LINK; /* Link direct data of overrides. */ if (id->override_library) { @@ -2834,6 +2830,12 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) if (pf) { pf->data = newpackedadr(fd, pf->data); + if (pf->data == NULL) { + /* We cannot allow a PackedFile with a NULL data field, + * the whole code assumes this is not possible. See T70315. */ + printf("%s: NULL packedfile data, cleaning up...\n", __func__); + MEM_SAFE_FREE(pf); + } } return pf; @@ -4378,7 +4380,7 @@ static void direct_link_curve(FileData *fd, Curve *cu) switch_endian_knots(nu); } } - cu->bb = NULL; + cu->texflag &= ~CU_AUTOSPACE_EVALUATED; } /** \} */ @@ -5045,7 +5047,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) direct_link_customdata(fd, &mesh->ldata, mesh->totloop); direct_link_customdata(fd, &mesh->pdata, mesh->totpoly); - mesh->bb = NULL; + mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; mesh->edit_mesh = NULL; BKE_mesh_runtime_reset(mesh); @@ -5749,8 +5751,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) } /* runtime only */ - csmd->delta_cache = NULL; - csmd->delta_cache_num = 0; + csmd->delta_cache.deltas = NULL; + csmd->delta_cache.totverts = 0; } else if (md->type == eModifierType_MeshSequenceCache) { MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md; @@ -7188,6 +7190,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) rv3d->render_engine = NULL; rv3d->sms = NULL; rv3d->smooth_timer = NULL; + + rv3d->rflag &= ~(RV3D_NAVIGATING | RV3D_PAINTING); } } } @@ -7286,13 +7290,6 @@ static void direct_link_area(FileData *fd, ScrArea *area) } v3d->shading.prev_type = OB_SOLID; - if (v3d->fx_settings.dof) { - v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof); - } - if (v3d->fx_settings.ssao) { - v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao); - } - direct_link_view3dshading(fd, &v3d->shading); blo_do_versions_view3d_split_250(v3d, &sl->regionbase); @@ -7899,6 +7896,45 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map) BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map); } +static int lib_link_main_data_restore_cb(void *user_data, + ID *UNUSED(id_self), + ID **id_pointer, + int cb_flag) +{ + if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) { + return IDWALK_RET_NOP; + } + + /* Special ugly case here, thanks again for those non-IDs IDs... */ + /* We probably need to add more cases here (hint: nodetrees), + * but will wait for changes from D5559 to get in first. */ + if (GS((*id_pointer)->name) == ID_GR) { + Collection *collection = (Collection *)*id_pointer; + if (collection->flag & COLLECTION_IS_MASTER) { + return IDWALK_RET_NOP; + } + } + + struct IDNameLib_Map *id_map = user_data; + + /* Note: Handling of usercount here is really bad, defining its own system... + * Will have to be refactored at some point, but that is not top priority task for now. + * And all usercounts are properly recomputed at the end of the undo management code anyway. */ + *id_pointer = restore_pointer_by_name( + id_map, *id_pointer, (cb_flag & IDWALK_CB_USER_ONE) ? USER_REAL : USER_IGNORE); + + return IDWALK_RET_NOP; +} + +static void lib_link_main_data_restore(struct IDNameLib_Map *id_map, Main *newmain) +{ + ID *id; + FOREACH_MAIN_ID_BEGIN (newmain, id) { + BKE_library_foreach_ID_link(newmain, id, lib_link_main_data_restore_cb, id_map, IDWALK_NOP); + } + FOREACH_MAIN_ID_END; +} + static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer) { bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); @@ -8218,11 +8254,24 @@ void blo_lib_link_restore(Main *oldmain, /* keep cursor location through undo */ memcpy(&win->scene->cursor, &oldscene->cursor, sizeof(win->scene->cursor)); + /* Note: even though that function seems to redo part of what is done by + * `lib_link_workspace_layout_restore()` above, it seems to have a slightly different scope: + * while the former updates the whole UI pointers from Main db (going over all layouts of + * all workspaces), that one only focuses one current active screen, takes care of + * potential local view, and needs window's scene pointer to be final... */ lib_link_window_scene_data_restore(win, win->scene, cur_view_layer); BLI_assert(win->screen == NULL); } + /* Restore all ID pointers in Main database itself + * (especially IDProperties might point to some word-space of other 'weirdly unchanged' ID + * pointers, see T69146). + * Note that this will re-apply again a few pointers in workspaces or so, + * but since we are remapping final ones already set above, + * that is just some minor harmless double-processing. */ + lib_link_main_data_restore(id_map, newmain); + /* update IDs stored in all possible clipboards */ lib_link_clipboard_restore(id_map); @@ -9110,7 +9159,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a return bhead; } -static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id) +static BHead *read_libblock(FileData *fd, + Main *main, + BHead *bhead, + const int tag, + const bool placeholder_set_indirect_extern, + ID **r_id) { /* this routine reads a libblock and its direct data. Use link functions to connect it all */ @@ -9230,7 +9284,16 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const int ta /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_LINK_PLACEHOLDER) { /* That way, we know which data-lock needs do_versions (required currently for linking). */ - id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; + id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW; + + if (placeholder_set_indirect_extern) { + if (id->flag & LIB_INDIRECT_WEAK_LINK) { + id->tag |= LIB_TAG_INDIRECT; + } + else { + id->tag |= LIB_TAG_EXTERN; + } + } return blo_bhead_next(fd, bhead); } @@ -9793,8 +9856,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) * to the file format definition. So we can use the entry at the * end of mainlist, added in direct_link_library. */ Main *libmain = mainlist.last; - bhead = read_libblock( - fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_EXTERN, NULL); + bhead = read_libblock(fd, libmain, bhead, 0, true, NULL); } break; /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ @@ -9807,7 +9869,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) bhead = blo_bhead_next(fd, bhead); } else { - bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL); + bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, false, NULL); } } } @@ -10055,7 +10117,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) if (id == NULL) { /* ID has not been read yet, add placeholder to the main of the * library it belongs to, so that it will be read later. */ - read_libblock(fd, libmain, bhead, LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_INDIRECT, NULL); + read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL); // commented because this can print way too much // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name); @@ -10063,6 +10125,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) libmain->curlib->parent = mainvar->curlib; } else { + /* Convert any previously read weak link to regular link + * to signal that we want to read this data-block. */ + if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { + id->flag &= ~LIB_INDIRECT_WEAK_LINK; + } + /* "id" is either a placeholder or real ID that is already in the * main of the library (A) it belongs to. However it might have been * put there by another library (C) which only updated its own @@ -10104,9 +10172,15 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) ID *id = is_yet_read(fd, mainvar, bhead); if (id == NULL) { - read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, NULL); + read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL); } else { + /* Convert any previously read weak link to regular link + * to signal that we want to read this data-block. */ + if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { + id->flag &= ~LIB_INDIRECT_WEAK_LINK; + } + /* this is actually only needed on UI call? when ID was already read before, * and another append happens which invokes same ID... * in that case the lookup table needs this entry */ @@ -11256,6 +11330,7 @@ static void add_loose_objects_to_scene(Main *mainvar, BKE_scene_object_base_flag_sync_from_base(base); ob->id.tag &= ~LIB_TAG_INDIRECT; + ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK; ob->id.tag |= LIB_TAG_EXTERN; } } @@ -11348,6 +11423,7 @@ static void add_collections_to_scene(Main *mainvar, /* Those are kept for safety and consistency, but should not be needed anymore? */ collection->id.tag &= ~LIB_TAG_INDIRECT; + collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK; collection->id.tag |= LIB_TAG_EXTERN; } } @@ -11372,7 +11448,7 @@ static ID *link_named_part( if (id == NULL) { /* not read yet */ const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN; - read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, &id); + read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id); if (id) { /* sort by name in list */ @@ -11388,6 +11464,7 @@ static ID *link_named_part( oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) { id->tag &= ~LIB_TAG_INDIRECT; + id->flag &= ~LIB_INDIRECT_WEAK_LINK; id->tag |= LIB_TAG_EXTERN; } } @@ -11426,7 +11503,7 @@ int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const unsigned int if (BKE_idcode_is_valid(bhead->code) && BKE_idcode_is_linkable(bhead->code) && (id_types_mask == 0 || (BKE_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) { - read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, &id); + read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, &id); num_directly_linked++; } @@ -11712,7 +11789,7 @@ static int has_linked_ids_to_read(Main *mainvar) while (a--) { for (ID *id = lbarray[a]->first; id; id = id->next) { - if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { + if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) { return true; } } @@ -11743,11 +11820,12 @@ static void read_library_linked_id( } id->tag &= ~LIB_TAG_ID_LINK_PLACEHOLDER; + id->flag &= ~LIB_INDIRECT_WEAK_LINK; if (bhead) { id->tag |= LIB_TAG_NEED_EXPAND; // printf("read lib block %s\n", id->name); - read_libblock(fd, mainvar, bhead, id->tag, r_id); + read_libblock(fd, mainvar, bhead, id->tag, false, r_id); } else { blo_reportf_wrap(reports, @@ -11781,7 +11859,7 @@ static void read_library_linked_ids(FileData *basefd, while (id) { ID *id_next = id->next; - if (id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) { + if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) { BLI_remlink(lbarray[a], id); /* When playing with lib renaming and such, you may end with cases where @@ -11817,6 +11895,28 @@ static void read_library_linked_ids(FileData *basefd, BLI_ghash_free(loaded_ids, NULL, NULL); } +static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, Main *mainvar) +{ + /* Any remaining weak links at this point have been lost, silently drop + * those by setting them to NULL pointers. */ + ListBase *lbarray[MAX_LIBARRAY]; + int a = set_listbasepointers(mainvar, lbarray); + + while (a--) { + ID *id = lbarray[a]->first; + + while (id) { + ID *id_next = id->next; + if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && (id->flag & LIB_INDIRECT_WEAK_LINK)) { + /* printf("Dropping weak link to %s\n", id->name); */ + change_link_placeholder_to_real_ID_pointer(mainlist, basefd, id, NULL); + BLI_freelinkN(lbarray[a], id); + } + id = id_next; + } + } +} + static FileData *read_library_file_data(FileData *basefd, ListBase *mainlist, Main *mainl, @@ -11943,6 +12043,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) Main *main_newid = BKE_main_new(); for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) { + /* Drop weak links for which no data-block was found. */ + read_library_clear_weak_links(basefd, mainlist, mainptr); + /* Do versioning for newly added linked data-locks. If no data-locks * were read from a library versionfile will still be zero and we can * skip it. */ diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 0a3e592bb15..d8e4f3d97a5 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -1673,15 +1673,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) } for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene) { - Sequence *seq; - SEQ_BEGIN (scene->ed, seq) { - if (seq->sat == 0.0f) { - seq->sat = 1.0f; - } + Sequence *seq; + SEQ_BEGIN (scene->ed, seq) { + if (seq->sat == 0.0f) { + seq->sat = 1.0f; } - SEQ_END; } + SEQ_END; } /* GSOC 2010 Sculpt - New settings for Brush */ @@ -1696,7 +1694,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) /* will have no effect */ if (brush->alpha == 0) { - brush->alpha = 0.5f; + brush->alpha = 1.0f; } /* bad radius */ diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 38c19fc647a..a3dc177262e 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1746,7 +1746,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) { for (Brush *br = bmain->brushes.first; br; br = br->id.next) { br->falloff_angle = DEG2RADF(80); - br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_FLAG_UNUSED_6 | BRUSH_GRAB_ACTIVE_VERTEX | + /* These flags are used for new feautres. They are not related to falloff_angle */ + br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_ORIGINAL_PLANE | BRUSH_GRAB_ACTIVE_VERTEX | BRUSH_SCENE_SPACING | BRUSH_FRONTFACE_FALLOFF); } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 2b88365f0fd..5328d3cb13c 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -585,13 +585,18 @@ static void do_versions_fix_annotations(bGPdata *gpd) } } -static void do_versions_remove_region(ListBase *regionbase, int regiontype) +static void do_versions_remove_region(ListBase *regionbase, ARegion *ar) +{ + BLI_freelinkN(regionbase, ar); +} + +static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiontype) { ARegion *ar, *ar_next; for (ar = regionbase->first; ar; ar = ar_next) { ar_next = ar->next; if (ar->regiontype == regiontype) { - BLI_freelinkN(regionbase, ar); + do_versions_remove_region(regionbase, ar); } } } @@ -1267,6 +1272,22 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) ma->blend_method = MA_BM_BLEND; } } + + { + /* Update all ruler layers to set new flag. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + bGPdata *gpd = scene->gpd; + if (gpd == NULL) { + continue; + } + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (STREQ(gpl->info, "RulerData3D")) { + gpl->flag |= GP_LAYER_IS_RULER; + break; + } + } + } + } } } @@ -3360,7 +3381,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; /* Remove multiple footers that were added by mistake. */ - do_versions_remove_region(regionbase, RGN_TYPE_FOOTER); + do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER); /* Add footer. */ ARegion *ar = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text"); @@ -3822,7 +3843,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_PROPS); - ARegion *ar_execute = do_versions_find_region_or_null(regionbase, RGN_TYPE_EXECUTE); /* Reinsert UI region so that it spawns entire area width */ BLI_remlink(regionbase, ar_ui); @@ -3839,15 +3859,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) BLI_freelinkN(regionbase, ar_toolprops); } - if (!ar_execute) { - ARegion *ar_main = do_versions_find_region(regionbase, RGN_TYPE_WINDOW); - ar_execute = MEM_callocN(sizeof(ARegion), "versioning execute region for file"); - BLI_insertlinkbefore(regionbase, ar_main, ar_execute); - ar_execute->regiontype = RGN_TYPE_EXECUTE; - ar_execute->alignment = RGN_ALIGN_BOTTOM; - ar_execute->flag |= RGN_FLAG_DYNAMIC_SIZE; - } - if (sfile->params) { sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; } @@ -3897,8 +3908,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - { - /* Versioning code until next subversion bump goes here. */ + if (!MAIN_VERSION_ATLEAST(bmain, 281, 15)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_NODE_X) { + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; + } + } if (!DNA_struct_elem_find( fd->filesdna, "LayerCollection", "short", "local_collections_bits")) { @@ -3910,5 +3925,55 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + + for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) { + for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other; + sl_other = sl_other->next) { + if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) { + View3D *v3d_other = (View3D *)sl_other; + + if (v3d->shading.prop == v3d_other->shading.prop) { + v3d_other->shading.prop = NULL; + } + } + } + } + } + else if (sl->spacetype == SPACE_FILE) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS); + ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + + if (ar_tools) { + ARegion *ar_next = ar_tools->next; + + /* We temporarily had two tools regions, get rid of the second one. */ + if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) { + do_versions_remove_region(regionbase, ar_next); + } + + BLI_remlink(regionbase, ar_tools); + BLI_insertlinkafter(regionbase, ar_header, ar_tools); + } + else { + ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region"); + BLI_insertlinkafter(regionbase, ar_header, ar_tools); + ar_tools->alignment = RGN_ALIGN_LEFT; + } + } + } + } + } + } + + { + /* Versioning code until next subversion bump goes here. */ } } diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index 52d62725ef8..2c4ba4a1102 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -813,10 +813,10 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size); bNode *maximumNode = NULL; - if (mapping->flag & TEXMAP_CLIP_MAX) { + if (mapping->flag & TEXMAP_CLIP_MIN) { maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM; - if (mapping->flag & TEXMAP_CLIP_MIN) { + if (mapping->flag & TEXMAP_CLIP_MAX) { maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f; } else { @@ -824,7 +824,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) } maximumNode->locy = node->locy; bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1); - copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->max); + copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->min); bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector"); LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) { @@ -834,7 +834,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) nodeRemLink(ntree, link); } } - if (!(mapping->flag & TEXMAP_CLIP_MIN)) { + if (!(mapping->flag & TEXMAP_CLIP_MAX)) { bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0); nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA); } @@ -843,13 +843,13 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) } bNode *minimumNode = NULL; - if (mapping->flag & TEXMAP_CLIP_MIN) { + if (mapping->flag & TEXMAP_CLIP_MAX) { minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM; minimumNode->locx = node->locx + node->width + 20.0f; minimumNode->locy = node->locy; bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1); - copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->min); + copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->max); bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector"); bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector"); @@ -878,7 +878,6 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) AnimData *animData = BKE_animdata_from_id(&ntree->id); if (animData && animData->action) { char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name); - for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) { if (STRPREFIX(fcu->rna_path, nodePath) && !BLI_str_endswith(fcu->rna_path, "default_value")) { @@ -893,11 +892,11 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) else if (BLI_str_endswith(old_fcu_rna_path, "scale")) { fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value"); } - else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "min")) { + else if (minimumNode && BLI_str_endswith(old_fcu_rna_path, "max")) { fcu->rna_path = BLI_sprintfN( "nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value"); } - else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "max")) { + else if (maximumNode && BLI_str_endswith(old_fcu_rna_path, "min")) { fcu->rna_path = BLI_sprintfN( "nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value"); } @@ -1093,12 +1092,13 @@ static void update_voronoi_node_crackle(bNodeTree *ntree) } } -/* The coloring property of the Voronoi node was removed. Previously, +/** + * The coloring property of the Voronoi node was removed. Previously, * if the coloring enum was set to Intensity (0), the voronoi distance * was returned in all outputs, otherwise, the Cell ID was returned. * Since we remapped the Fac output in update_voronoi_node_fac_output, * then to fix this, we relink the Color output to the Distance - * output if coloring was set to 0, and the otherway around otherwise. + * output if coloring was set to 0, and the other way around otherwise. */ static void update_voronoi_node_coloring(bNodeTree *ntree) { diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 87c8869622a..c9fb8b6990b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -41,11 +41,13 @@ #include "DNA_light_types.h" #include "BKE_appdir.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_workspace.h" @@ -285,6 +287,10 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) CURVEMAP_SLOPE_POSITIVE); } + if (ts->sculpt) { + ts->sculpt->paint.symmetry_flags |= PAINT_SYMMETRY_FEATHER; + } + /* Correct default startup UV's. */ Mesh *me = BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2); if (me && (me->totloop == 24) && (me->mloopuv != NULL)) { @@ -352,6 +358,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) scene->audio.flag &= ~AUDIO_SYNC; scene->flag &= ~SCE_FRAME_DROP; } + + /* Change default selection mode for Grease Pencil. */ + if (app_template && STREQ(app_template, "2D_Animation")) { + ToolSettings *ts = scene->toolsettings; + ts->gpencil_selectmode_edit = GP_SELECTMODE_STROKE; + } } /* Objects */ @@ -407,7 +419,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) { /* Enable for UV sculpt (other brush types will be created as needed), * without this the grab brush will be active but not selectable from the list. */ - Brush *brush = BLI_findstring(&bmain->brushes, "Grab", offsetof(ID, name) + 2); + const char *brush_name = "Grab"; + Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); if (brush) { brush->ob_mode |= OB_MODE_EDIT; } @@ -415,13 +428,103 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { brush->blur_kernel_radius = 2; + + /* Use full strength for all non-sculpt brushes, + * when painting we want to use full color/weight always. + * + * Note that sculpt is an exception, + * it's values are overwritten by #BKE_brush_sculpt_reset below. */ + brush->alpha = 1.0; } { /* Change the spacing of the Smear brush to 3.0% */ - Brush *brush = BLI_findstring(&bmain->brushes, "Smear", offsetof(ID, name) + 2); + const char *brush_name; + Brush *brush; + + brush_name = "Smear"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); if (brush) { brush->spacing = 3.0; } + + brush_name = "Draw Sharp"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP; + } + + brush_name = "Elastic Deform"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM; + } + + brush_name = "Pose"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_POSE; + } + + brush_name = "Simplify"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY; + } + + /* Use the same tool icon color in the brush cursor */ + for (brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->ob_mode & OB_MODE_SCULPT) { + BLI_assert(brush->sculpt_tool != 0); + BKE_brush_sculpt_reset(brush); + } + } + } + + if (app_template && STREQ(app_template, "2D_Animation")) { + /* Update Grease Pencil brushes. */ + Brush *brush; + + /* Pencil brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil"); + + /* Pen brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen"); + + /* Pen Soft brush. */ + brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft"); + if (brush) { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + } + + /* Ink Pen brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen"); + + /* Ink Pen Rough brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough"); + + /* Marker Bold brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold"); + + /* Marker Chisel brush. */ + rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel"); + + /* Remove useless Fill Area.001 brush. */ + brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2); + if (brush) { + BKE_id_delete(bmain, brush); + } + + /* Reset all grease pencil brushes. */ + Scene *scene = bmain->scenes.first; + BKE_brush_gpencil_presets(bmain, scene->toolsettings); } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 62bd605a2c2..1b30c7371a2 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -1705,19 +1705,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) /* add default radius values to old curve points */ for (cu = bmain->curves.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (!bezt->radius) { - bezt->radius = 1.0; - } + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (!bezt->radius) { + bezt->radius = 1.0; } } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (!bp->radius) { - bp->radius = 1.0; - } + } + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (!bp->radius) { + bp->radius = 1.0; } } } @@ -2515,17 +2513,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) for (cu = bmain->curves.first; cu; cu = cu->id.next) { for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu) { - nu->radius_interp = 3; - - /* resolu and resolv are now used differently for surfaces - * rather than using the resolution to define the entire number of divisions, - * use it for the number of divisions per segment - */ - if (nu->pntsv > 1) { - nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f)); - nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f)); - } + nu->radius_interp = 3; + + /* resolu and resolv are now used differently for surfaces + * rather than using the resolution to define the entire number of divisions, + * use it for the number of divisions per segment + */ + if (nu->pntsv > 1) { + nu->resolu = MAX2(1, (int)(((float)nu->resolu / (float)nu->pntsu) + 0.5f)); + nu->resolv = MAX2(1, (int)(((float)nu->resolv / (float)nu->pntsv) + 0.5f)); } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 739dc32d1fe..e1ee020940e 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -29,6 +29,8 @@ #include "DNA_curve_types.h" #include "DNA_windowmanager_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_anim_types.h" #include "BKE_addon.h" #include "BKE_colorband.h" @@ -145,12 +147,18 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_outliner.active); } + if (!USER_VERSION_ATLEAST(281, 14)) { + FROM_DEFAULT_V4_UCHAR(space_file.execution_buts); + FROM_DEFAULT_V4_UCHAR(tui.icon_folder); + FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before); + FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after); + copy_v4_v4_uchar(btheme->space_nla.nla_track, btheme->space_nla.header); + } + /** * Include next version bump. */ { - FROM_DEFAULT_V4_UCHAR(space_file.execution_buts); - FROM_DEFAULT_V4_UCHAR(tui.icon_folder); } #undef FROM_DEFAULT_V4_UCHAR @@ -615,6 +623,24 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) BKE_addon_remove_safe(&userdef->addons, "io_scene_x3d"); } + if (!USER_VERSION_ATLEAST(281, 12)) { + userdef->render_display_type = USER_RENDER_DISPLAY_WINDOW; + userdef->filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW; + } + + if (!USER_VERSION_ATLEAST(281, 13)) { + userdef->auto_smoothing_new = FCURVE_SMOOTH_CONT_ACCEL; + + if (userdef->file_space_data.display_type == FILE_DEFAULTDISPLAY) { + memcpy( + &userdef->file_space_data, &U_default.file_space_data, sizeof(userdef->file_space_data)); + } + } + + if (!USER_VERSION_ATLEAST(282, 1)) { + userdef->file_space_data.filter_id = U_default.file_space_data.filter_id; + } + /** * Include next version bump. */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 95b5f91056a..3fe35f7b993 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -26,35 +26,36 @@ * FILE FORMAT * =========== * - * IFF-style structure (but not IFF compatible!) + * IFF-style structure (but not IFF compatible!) * - * start file: + * Start file: * <pre> - * BLENDER_V100 12 bytes (version 1.00) - * V = big endian, v = little endian - * _ = 4 byte pointer, - = 8 byte pointer + * `BLENDER_V100` `12` bytes (version 1.00 is just an example). + * `V` = big endian, `v` = little endian. + * `_` = 4 byte pointer, `-` = 8 byte pointer. * </pre> * * data-blocks: (also see struct #BHead). * <pre> - * <bh.code> 4 chars - * <bh.len> int, len data after BHead - * <bh.old> void, old pointer - * <bh.SDNAnr> int - * <bh.nr> int, in case of array: number of structs - * data - * ... - * ... + * `bh.code` `char[4]` see `BLO_blend_defs.h` for a list of known types. + * `bh.len` `int32` length data after #BHead in bytes. + * `bh.old` `void *` old pointer (the address at the time of writing the file). + * `bh.SDNAnr` `int32` struct index of structs stored in #DNA1 data. + * `bh.nr` `int32` in case of array: number of structs. + * data + * ... + * ... * </pre> * * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again - * and compared with StructDNA . + * and compared with #StructDNA. + * WRITE * ===== * * Preferred writing order: (not really a must, but why would you do it random?) - * Any case: direct data is ALWAYS after the lib block + * Any case: direct data is ALWAYS after the lib block. * * (Local file data) * - for each LibBlock @@ -2860,12 +2861,6 @@ static void write_area_regions(WriteData *wd, ScrArea *area) writestruct(wd, DATA, View3D, 1, v3d->localvd); } - if (v3d->fx_settings.ssao) { - writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao); - } - if (v3d->fx_settings.dof) { - writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof); - } write_view3dshading(wd, &v3d->shading); } else if (sl->spacetype == SPACE_GRAPH) { @@ -3644,7 +3639,9 @@ static void write_libraries(WriteData *wd, Main *main) found_one = false; while (!found_one && tot--) { for (id = lbarray[tot]->first; id; id = id->next) { - if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { + if (id->us > 0 && + ((id->tag & LIB_TAG_EXTERN) || + ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) { found_one = true; break; } @@ -3674,7 +3671,9 @@ static void write_libraries(WriteData *wd, Main *main) /* Write link placeholders for all direct linked IDs. */ while (a--) { for (id = lbarray[a]->first; id; id = id->next) { - if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { + if (id->us > 0 && + ((id->tag & LIB_TAG_EXTERN) || + ((id->tag & LIB_TAG_INDIRECT) && (id->flag & LIB_INDIRECT_WEAK_LINK)))) { if (!BKE_idcode_is_linkable(GS(id->name))) { printf( "ERROR: write file: data-block '%s' from lib '%s' is not linkable " diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt index 1b46efb1bb5..0361137f5b1 100644 --- a/source/blender/blentranslation/msgfmt/CMakeLists.txt +++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt @@ -32,6 +32,10 @@ set(SRC add_cc_flags_custom_test(msgfmt) +if(APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") +endif() + add_executable(msgfmt ${SRC}) target_link_libraries(msgfmt bf_blenlib) diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 599871a505a..00954eb400c 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -99,6 +99,8 @@ set(SRC intern/bmesh_mesh.h intern/bmesh_mesh_conv.c intern/bmesh_mesh_conv.h + intern/bmesh_mesh_duplicate.c + intern/bmesh_mesh_duplicate.h intern/bmesh_mesh_validate.c intern/bmesh_mesh_validate.h intern/bmesh_mods.c diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index b7356a89314..bdb719e0d7a 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -216,6 +216,7 @@ extern "C" { #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" #include "intern/bmesh_mesh_conv.h" +#include "intern/bmesh_mesh_duplicate.h" #include "intern/bmesh_mesh_validate.h" #include "intern/bmesh_mods.h" #include "intern/bmesh_operators.h" diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.c b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c new file mode 100644 index 00000000000..51f9d2eab1d --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.c @@ -0,0 +1,139 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bmesh + * + * Duplicate geometry from one mesh from another. + */ + +#include "DNA_object_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_alloca.h" +#include "BLI_math_vector.h" + +#include "bmesh.h" +#include "intern/bmesh_private.h" /* for element checking */ + +static BMVert *bm_vert_copy(BMesh *bm_src, BMesh *bm_dst, BMVert *v_src) +{ + BMVert *v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD); + BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); + return v_dst; +} + +static BMEdge *bm_edge_copy_with_arrays(BMesh *bm_src, + BMesh *bm_dst, + BMEdge *e_src, + BMVert **verts_dst) +{ + BMVert *e_dst_v1 = verts_dst[BM_elem_index_get(e_src->v1)]; + BMVert *e_dst_v2 = verts_dst[BM_elem_index_get(e_src->v2)]; + BMEdge *e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD); + BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); + return e_dst; +} + +static BMFace *bm_face_copy_with_arrays( + BMesh *bm_src, BMesh *bm_dst, BMFace *f_src, BMVert **verts_dst, BMEdge **edges_dst + +) +{ + BMFace *f_dst; + BMVert **vtar = BLI_array_alloca(vtar, f_src->len); + BMEdge **edar = BLI_array_alloca(edar, f_src->len); + BMLoop *l_iter_src, *l_iter_dst, *l_first_src; + int i; + + l_first_src = BM_FACE_FIRST_LOOP(f_src); + + /* Lookup verts & edges. */ + l_iter_src = l_first_src; + i = 0; + do { + vtar[i] = verts_dst[BM_elem_index_get(l_iter_src->v)]; + edar[i] = edges_dst[BM_elem_index_get(l_iter_src->e)]; + i++; + } while ((l_iter_src = l_iter_src->next) != l_first_src); + + /* Create new face. */ + f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD); + + /* Copy attributes. */ + BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); + + /* Copy per-loop custom data. */ + l_iter_src = l_first_src; + l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); + do { + BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); + } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src); + + return f_dst; +} + +/** + * Geometry must be completely isolated. + */ +void BM_mesh_copy_arrays(BMesh *bm_src, + BMesh *bm_dst, + BMVert **verts_src, + uint verts_src_len, + BMEdge **edges_src, + uint edges_src_len, + BMFace **faces_src, + uint faces_src_len) +{ + /* Vertices. */ + BMVert **verts_dst = MEM_mallocN(sizeof(*verts_dst) * verts_src_len, __func__); + for (uint i = 0; i < verts_src_len; i++) { + BMVert *v_src = verts_src[i]; + BM_elem_index_set(v_src, i); /* set_dirty! */ + + BMVert *v_dst = bm_vert_copy(bm_src, bm_dst, v_src); + BM_elem_index_set(v_dst, i); /* set_ok */ + verts_dst[i] = v_dst; + } + bm_src->elem_index_dirty |= BM_VERT; + bm_dst->elem_index_dirty &= ~BM_VERT; + + /* Edges. */ + BMEdge **edges_dst = MEM_mallocN(sizeof(*edges_dst) * edges_src_len, __func__); + for (uint i = 0; i < edges_src_len; i++) { + BMEdge *e_src = edges_src[i]; + BM_elem_index_set(e_src, i); /* set_dirty! */ + + BMEdge *e_dst = bm_edge_copy_with_arrays(bm_src, bm_dst, e_src, verts_dst); + BM_elem_index_set(e_dst, i); + edges_dst[i] = e_dst; + } + bm_src->elem_index_dirty |= BM_EDGE; + bm_dst->elem_index_dirty &= ~BM_EDGE; + + /* Faces. */ + for (uint i = 0; i < faces_src_len; i++) { + BMFace *f_src = faces_src[i]; + BMFace *f_dst = bm_face_copy_with_arrays(bm_src, bm_dst, f_src, verts_dst, edges_dst); + BM_elem_index_set(f_dst, i); + } + bm_dst->elem_index_dirty &= ~BM_FACE; + + /* Cleanup. */ + MEM_freeN(verts_dst); + MEM_freeN(edges_dst); +} diff --git a/source/blender/bmesh/intern/bmesh_mesh_duplicate.h b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h new file mode 100644 index 00000000000..17d4071b69f --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mesh_duplicate.h @@ -0,0 +1,33 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __BMESH_MESH_DUPLICATE_H__ +#define __BMESH_MESH_DUPLICATE_H__ + +/** \file + * \ingroup bmesh + */ + +void BM_mesh_copy_arrays(BMesh *bm_src, + BMesh *bm_dst, + BMVert **verts_src, + uint verts_src_len, + BMEdge **edges_src, + uint edges_src_len, + BMFace **faces_src, + uint faces_src_len); + +#endif /* __BMESH_MESH_DUPLICATE_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index 219bec15e5b..cebfd4df75b 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -2808,6 +2808,91 @@ int BM_mesh_calc_edge_groups(BMesh *bm, return group_curr; } +int BM_mesh_calc_edge_groups_as_arrays( + BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int (**r_groups)[3]) +{ + int(*groups)[3] = MEM_mallocN(sizeof(*groups) * bm->totvert, __func__); + STACK_DECLARE(groups); + STACK_INIT(groups, bm->totvert); + + /* Clear all selected vertices */ + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + BMVert **stack = MEM_mallocN(sizeof(*stack) * bm->totvert, __func__); + STACK_DECLARE(stack); + STACK_INIT(stack, bm->totvert); + + STACK_DECLARE(verts); + STACK_INIT(verts, bm->totvert); + + STACK_DECLARE(edges); + STACK_INIT(edges, bm->totedge); + + STACK_DECLARE(faces); + STACK_INIT(faces, bm->totface); + + BMIter iter; + BMVert *v_stack_init; + BM_ITER_MESH (v_stack_init, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v_stack_init, BM_ELEM_TAG)) { + continue; + } + + const uint verts_init = STACK_SIZE(verts); + const uint edges_init = STACK_SIZE(edges); + const uint faces_init = STACK_SIZE(faces); + + /* Initialize stack. */ + BM_elem_flag_enable(v_stack_init, BM_ELEM_TAG); + STACK_PUSH(verts, v_stack_init); + + if (v_stack_init->e != NULL) { + BMVert *v_iter = v_stack_init; + do { + BMEdge *e_iter, *e_first; + e_iter = e_first = v_iter->e; + do { + if (!BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { + BM_elem_flag_enable(e_iter, BM_ELEM_TAG); + STACK_PUSH(edges, e_iter); + + if (e_iter->l != NULL) { + BMLoop *l_iter, *l_first; + l_iter = l_first = e_iter->l; + do { + if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) { + BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG); + STACK_PUSH(faces, l_iter->f); + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + + BMVert *v_other = BM_edge_other_vert(e_iter, v_iter); + if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_other, BM_ELEM_TAG); + STACK_PUSH(verts, v_other); + + STACK_PUSH(stack, v_other); + } + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_iter)) != e_first); + } while ((v_iter = STACK_POP(stack))); + } + + int *g = STACK_PUSH_RET(groups); + g[0] = STACK_SIZE(verts) - verts_init; + g[1] = STACK_SIZE(edges) - edges_init; + g[2] = STACK_SIZE(faces) - faces_init; + } + + MEM_freeN(stack); + + /* Reduce alloc to required size. */ + groups = MEM_reallocN(groups, sizeof(*groups) * STACK_SIZE(groups)); + *r_groups = groups; + return STACK_SIZE(groups); +} + float bmesh_subd_falloff_calc(const int falloff, float val) { switch (falloff) { diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index 3a864fbb5dd..134e0b99691 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -249,6 +249,13 @@ int BM_mesh_calc_edge_groups(BMesh *bm, void *user_data, const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); +int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm, + BMVert **verts, + BMEdge **edges, + BMFace **faces, + int (**r_groups)[3]) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(1, 2, 3, 4, 5); + /* not really any good place to put this */ float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 5403043efb4..bad5036f6cf 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -400,7 +400,7 @@ static void bridge_loop_pair(BMesh *bm, f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL); if (v_b != v_b_next) { - BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; + BMVert *v_arr[4] = {v_b, v_b_next, v_a_next, v_a}; f = BM_face_exists(v_arr, 4); if (f == NULL) { /* copy if loop data if its is missing on one ring */ @@ -425,7 +425,7 @@ static void bridge_loop_pair(BMesh *bm, } } else { - BMVert *v_arr[3] = {v_a, v_b, v_a_next}; + BMVert *v_arr[3] = {v_b, v_a_next, v_a}; f = BM_face_exists(v_arr, 3); if (f == NULL) { /* fan-fill a triangle */ diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index ff7dcc388b3..64687ac154c 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1507,7 +1507,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); + BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index 6422904c83c..ffdcf179491 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -650,6 +650,8 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas BMEdge *e; int i; + BM_mesh_elem_table_ensure(bm, BM_VERT | BM_EDGE); + /* Store all intersections in this array. */ struct EDBMSplitElem(*pair_iter)[2], (*pair_array)[2] = NULL; BLI_Stack *pair_stack = BLI_stack_new(sizeof(*pair_array), __func__); diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 79593f07383..47325c4dece 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -104,7 +104,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve) fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED); fcu->array_index = 0; - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; for (unsigned int j = 0; j < curve->getKeyCount(); j++) { BezTriple bez; diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp index bf32ec9148c..f944a77196c 100644 --- a/source/blender/collada/BCAnimationCurve.cpp +++ b/source/blender/collada/BCAnimationCurve.cpp @@ -383,7 +383,7 @@ void BCAnimationCurve::adjust_range(const int frame_index) void BCAnimationCurve::add_value(const float val, const int frame_index) { FCurve *fcu = get_edit_fcurve(); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; insert_vert_fcurve(fcu, frame_index, val, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NOFLAGS); if (fcu->totvert == 1) { diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp index 8735d71ec40..a9783a9b9c4 100644 --- a/source/blender/collada/BlenderContext.cpp +++ b/source/blender/collada/BlenderContext.cpp @@ -21,6 +21,8 @@ #include <vector> #include "BlenderContext.h" +#include "ExportSettings.h" + #include "BKE_scene.h" bool bc_is_base_node(LinkNode *export_set, Object *ob, ViewLayer *view_layer) diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index 71201c8a55c..6e31e17fb26 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -107,7 +107,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) /* make absolute source path */ BLI_strncpy(source_path, image->name, sizeof(source_path)); - BLI_path_abs(source_path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id)); BLI_cleanup_path(NULL, source_path); if (use_copies) { diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index a97b5e0eca1..7e834045795 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -314,7 +314,7 @@ std::string get_joint_sid(Bone *bone) { return translate_id(bone->name); } -std::string get_joint_sid(EditBone *bone) +static std::string get_joint_sid(EditBone *bone) { return translate_id(bone->name); } diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index dd5611c4bef..b688840cb09 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -1149,7 +1149,7 @@ void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a) /** * Returns name of Active UV Layer or empty String if no active UV Layer defined */ -std::string bc_get_active_uvlayer_name(Mesh *me) +static std::string bc_get_active_uvlayer_name(Mesh *me) { int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (num_layers) { @@ -1165,7 +1165,7 @@ std::string bc_get_active_uvlayer_name(Mesh *me) * Returns name of Active UV Layer or empty String if no active UV Layer defined. * Assuming the Object is of type MESH */ -std::string bc_get_active_uvlayer_name(Object *ob) +static std::string bc_get_active_uvlayer_name(Object *ob) { Mesh *me = (Mesh *)ob->data; return bc_get_active_uvlayer_name(me); @@ -1174,7 +1174,7 @@ std::string bc_get_active_uvlayer_name(Object *ob) /** * Returns UV Layer name or empty string if layer index is out of range */ -std::string bc_get_uvlayer_name(Mesh *me, int layer) +static std::string bc_get_uvlayer_name(Mesh *me, int layer) { int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); if (num_layers && layer < num_layers) { @@ -1206,7 +1206,7 @@ static bNodeTree *prepare_material_nodetree(Material *ma) return ma->nodetree; } -bNode *bc_add_node( +static bNode *bc_add_node( bContext *C, bNodeTree *ntree, int node_type, int locx, int locy, std::string label) { bNode *node = nodeAddStaticNode(C, ntree, node_type); @@ -1221,7 +1221,7 @@ bNode *bc_add_node( return node; } -bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy) +static bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy) { return bc_add_node(C, ntree, node_type, locx, locy, ""); } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 2a8914c8cd9..f0685b169fa 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -566,6 +566,7 @@ if(WITH_OPENIMAGEDENOISE) add_definitions(-DOIDN_STATIC_LIB) list(APPEND INC_SYS ${OPENIMAGEDENOISE_INCLUDE_DIRS} + ${TBB_INCLUDE_DIRS} ) endif() diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index e44dddbcf54..d5a93d21b99 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -179,14 +179,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce /* Evaluation ----------------------------------- */ +bool DEG_is_evaluating(struct Depsgraph *depsgraph); + bool DEG_is_active(const struct Depsgraph *depsgraph); void DEG_make_active(struct Depsgraph *depsgraph); void DEG_make_inactive(struct Depsgraph *depsgraph); /* Evaluation Debug ------------------------------ */ -bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph); - void DEG_debug_print_begin(struct Depsgraph *depsgraph); void DEG_debug_print_eval(struct Depsgraph *depsgraph, diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 37dfaf2c3e2..e24fa9e8996 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -74,6 +74,13 @@ void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct ViewLayer *view_layer, struct bNodeTree *nodetree); +void DEG_graph_build_from_ids(struct Depsgraph *graph, + struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + struct ID **ids, + const int num_ids); + /* Tag relations from the given graph for update. */ void DEG_graph_tag_relations_update(struct Depsgraph *graph); diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 82f7f33411a..fb456611b15 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -236,9 +236,21 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, /* Starts traversal from given component of the given ID, invokes callback for every other * component which is directly on indirectly dependent on the source one. */ +enum { + /* Ignore transform solvers which depends on multiple inputs and affects final transform. + * Is used for cases like snapping objects which are part of a rigid body simulation: + * without this there will be "false-positive" dependencies between transform components of + * objects: + * + * object 1 transform before solver ---> solver ------> object 1 final transform + * object 2 transform before solver -----^ \------> object 2 final transform + */ + DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS, +}; void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, const ID *id, eDepsObjectComponentType source_component_type, + int flags, DEGForeachIDComponentCallback callback, void *user_data); diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 4cbdd169980..4ca7240abd1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -74,6 +74,10 @@ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuild { } +DepsgraphBuilder::~DepsgraphBuilder() +{ +} + bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) { /* Simple check: enabled bases are always part of dependency graph. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 040bb6cfeea..97e12e9ceb2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -35,11 +35,13 @@ class DepsgraphBuilderCache; class DepsgraphBuilder { public: - bool need_pull_base_into_graph(Base *base); + virtual ~DepsgraphBuilder(); - bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan); - bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan); - bool check_pchan_has_bbone_segments(Object *object, const char *bone_name); + virtual bool need_pull_base_into_graph(Base *base); + + virtual bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan); + virtual bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan); + virtual bool check_pchan_has_bbone_segments(Object *object, const char *bone_name); protected: /* NOTE: The builder does NOT take ownership over any of those resources. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 88f2f041354..d0e40d49527 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -527,6 +527,9 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { + if (object->proxy != NULL) { + object->proxy->proxy_from = object; + } const bool has_object = built_map_.checkIsBuiltAndTag(object); /* Skip rest of components if the ID node was already there. */ if (has_object) { @@ -609,12 +612,8 @@ void DepsgraphNodeBuilder::build_object(int base_index, build_particle_systems(object, is_visible); } /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - if (object->proxy_group != NULL) { - build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); - } + build_object_proxy_from(object, is_visible); + build_object_proxy_group(object, is_visible); /* Object dupligroup. */ if (object->instance_collection != NULL) { const bool is_current_parent_collection_visible = is_parent_collection_visible_; @@ -653,6 +652,22 @@ void DepsgraphNodeBuilder::build_object_flags(int base_index, is_from_set)); } +void DepsgraphNodeBuilder::build_object_proxy_from(Object *object, bool is_visible) +{ + if (object->proxy_from == NULL) { + return; + } + build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); +} + +void DepsgraphNodeBuilder::build_object_proxy_group(Object *object, bool is_visible) +{ + if (object->proxy_group == NULL) { + return; + } + build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); +} + void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible) { if (object->data == NULL) { @@ -900,19 +915,17 @@ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index { /* Create data node for this driver */ ID *id_cow = get_cow_id(id); - ChannelDriver *driver_orig = fcurve->driver; /* TODO(sergey): ideally we could pass the COW of fcu, but since it * has not yet been allocated at this point we can't. As a workaround * the animation systems allocates an array so we can do a fast lookup * with the driver index. */ - ensure_operation_node( - id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig), - fcurve->rna_path ? fcurve->rna_path : "", - fcurve->array_index); + ensure_operation_node(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, fcurve), + fcurve->rna_path ? fcurve->rna_path : "", + fcurve->array_index); build_driver_variables(id, fcurve); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 65f3521b556..865f60432c1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -93,8 +93,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { return (T *)cow->id.orig_id; } - void begin_build(); - void end_build(); + virtual void begin_build(); + virtual void end_build(); IDNode *add_id_node(ID *id); IDNode *find_id_node(ID *id); @@ -145,71 +145,75 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { OperationNode *find_operation_node( ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1); - void build_id(ID *id); + virtual void build_id(ID *id); - void build_scene_render(Scene *scene, ViewLayer *view_layer); - void build_scene_parameters(Scene *scene); - void build_scene_compositor(Scene *scene); + virtual void build_scene_render(Scene *scene, ViewLayer *view_layer); + virtual void build_scene_parameters(Scene *scene); + virtual void build_scene_compositor(Scene *scene); - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state); - void build_collection(LayerCollection *from_layer_collection, Collection *collection); - void build_object(int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state, - bool is_visible); - void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); - void build_object_data(Object *object, bool is_object_visible); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object, bool is_object_visible); - void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_transform(Object *object); - void build_object_constraints(Object *object); - void build_object_pointcache(Object *object); - void build_pose_constraints(Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object, bool is_object_visible); - void build_particle_settings(ParticleSettings *part); - void build_animdata(ID *id); - void build_animdata_nlastrip_targets(ListBase *strips); - void build_animation_images(ID *id); - void build_action(bAction *action); - void build_driver(ID *id, FCurve *fcurve, int driver_index); - void build_driver_variables(ID *id, FCurve *fcurve); - void build_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); - void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); - void build_rig(Object *object, bool is_object_visible); - void build_proxy_rig(Object *object); - void build_armature(bArmature *armature); - void build_shapekeys(Key *key); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_materials(Material **materials, int num_materials); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_world(World *world); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); - void build_sound(bSound *sound); - void build_scene_sequencer(Scene *scene); - void build_scene_audio(Scene *scene); - void build_scene_speakers(Scene *scene, ViewLayer *view_layer); + virtual void build_layer_collections(ListBase *lb); + virtual void build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state); + virtual void build_collection(LayerCollection *from_layer_collection, Collection *collection); + virtual void build_object(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state, + bool is_visible); + virtual void build_object_proxy_from(Object *object, bool is_object_visible); + virtual void build_object_proxy_group(Object *object, bool is_object_visible); + virtual void build_object_flags(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state); + virtual void build_object_data(Object *object, bool is_object_visible); + virtual void build_object_data_camera(Object *object); + virtual void build_object_data_geometry(Object *object, bool is_object_visible); + virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible); + virtual void build_object_data_light(Object *object); + virtual void build_object_data_lightprobe(Object *object); + virtual void build_object_data_speaker(Object *object); + virtual void build_object_transform(Object *object); + virtual void build_object_constraints(Object *object); + virtual void build_object_pointcache(Object *object); + virtual void build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index, + bool is_object_visible); + virtual void build_rigidbody(Scene *scene); + virtual void build_particle_systems(Object *object, bool is_object_visible); + virtual void build_particle_settings(ParticleSettings *part); + virtual void build_animdata(ID *id); + virtual void build_animdata_nlastrip_targets(ListBase *strips); + virtual void build_animation_images(ID *id); + virtual void build_action(bAction *action); + virtual void build_driver(ID *id, FCurve *fcurve, int driver_index); + virtual void build_driver_variables(ID *id, FCurve *fcurve); + virtual void build_driver_id_property(ID *id, const char *rna_path); + virtual void build_parameters(ID *id); + virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + virtual void build_rig(Object *object, bool is_object_visible); + virtual void build_proxy_rig(Object *object); + virtual void build_armature(bArmature *armature); + virtual void build_shapekeys(Key *key); + virtual void build_camera(Camera *camera); + virtual void build_light(Light *lamp); + virtual void build_nodetree(bNodeTree *ntree); + virtual void build_material(Material *ma); + virtual void build_materials(Material **materials, int num_materials); + virtual void build_texture(Tex *tex); + virtual void build_image(Image *image); + virtual void build_world(World *world); + virtual void build_gpencil(bGPdata *gpd); + virtual void build_cachefile(CacheFile *cache_file); + virtual void build_mask(Mask *mask); + virtual void build_movieclip(MovieClip *clip); + virtual void build_lightprobe(LightProbe *probe); + virtual void build_speaker(Speaker *speaker); + virtual void build_sound(bSound *sound); + virtual void build_scene_sequencer(Scene *scene); + virtual void build_scene_audio(Scene *scene); + virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer); /* Per-ID information about what was already in the dependency graph. * Allows to re-use certain values, to speed up following evaluation. */ @@ -259,7 +263,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { /* NOTE: Collection are possibly built recursively, so be careful when * setting the current state. */ Collection *collection_; - /* Accumulated flag over the hierarchy opf currently building collections. + /* Accumulated flag over the hierarchy of currently building collections. * Denotes whether all the hierarchy from parent of collection_ to the * very root is visible (aka not restricted.). */ bool is_parent_collection_visible_; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 61e9b83273b..f1e7278ffdb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -657,20 +657,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) build_particle_systems(object); } /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - /* Object is linked here (comes from the library). */ - build_object(NULL, object->proxy_from); - ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); - ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); - } - if (object->proxy_group != NULL && object->proxy_group != object->proxy) { - /* Object is local here (local in .blend file, users interacts with it). */ - build_object(NULL, object->proxy_group); - OperationKey proxy_group_eval_key( - &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); - add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform"); - } + build_object_proxy_from(object); + build_object_proxy_group(object); /* Object dupligroup. */ if (object->instance_collection != NULL) { build_collection(NULL, object, object->instance_collection); @@ -685,6 +673,31 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) build_parameters(&object->id); } +void DepsgraphRelationBuilder::build_object_proxy_from(Object *object) +{ + if (object->proxy_from == NULL) { + return; + } + /* Object is linked here (comes from the library). */ + build_object(NULL, object->proxy_from); + ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); + ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); + add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); +} + +void DepsgraphRelationBuilder::build_object_proxy_group(Object *object) +{ + if (object->proxy_group == NULL || object->proxy_group == object->proxy) { + return; + } + /* Object is local here (local in .blend file, users interacts with it). */ + build_object(NULL, object->proxy_group); + OperationKey proxy_group_eval_key( + &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + OperationKey transform_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(proxy_group_eval_key, transform_eval_key, "Proxy Group Transform"); +} + void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) { if (base == NULL) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index e58ef989ac9..c6a0014577f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -191,93 +191,95 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks); void add_special_eval_flag(ID *object, uint32_t flag); - void build_id(ID *id); - - void build_scene_render(Scene *scene, ViewLayer *view_layer); - void build_scene_parameters(Scene *scene); - void build_scene_compositor(Scene *scene); - - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state); - void build_collection(LayerCollection *from_layer_collection, - Object *object, - Collection *collection); - void build_object(Base *base, Object *object); - void build_object_flags(Base *base, Object *object); - void build_object_data(Object *object); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object); - void build_object_data_geometry_datablock(ID *obdata); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_parent(Object *object); - void build_object_pointcache(Object *object); - void build_constraints(ID *id, - NodeType component_type, - const char *component_subdata, - ListBase *constraints, - RootPChanMap *root_map); - void build_animdata(ID *id); - void build_animdata_curves(ID *id); - void build_animdata_curves_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *curves); - void build_animdata_nlastrip_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *strips); - void build_animdata_drivers(ID *id); - void build_animation_images(ID *id); - void build_action(bAction *action); - void build_driver(ID *id, FCurve *fcurve); - void build_driver_data(ID *id, FCurve *fcurve); - void build_driver_variables(ID *id, FCurve *fcurve); - void build_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_world(World *world); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object); - void build_particle_settings(ParticleSettings *part); - void build_particle_system_visualization_object(Object *object, - ParticleSystem *psys, - Object *draw_object); - void build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_splineik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_rig(Object *object); - void build_proxy_rig(Object *object); - void build_shapekeys(Key *key); - void build_armature(bArmature *armature); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_materials(Material **materials, int num_materials); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); - void build_sound(bSound *sound); - void build_scene_sequencer(Scene *scene); - void build_scene_audio(Scene *scene); - void build_scene_speakers(Scene *scene, ViewLayer *view_layer); - - void build_nested_datablock(ID *owner, ID *id); - void build_nested_nodetree(ID *owner, bNodeTree *ntree); - void build_nested_shapekey(ID *owner, Key *key); + virtual void build_id(ID *id); + + virtual void build_scene_render(Scene *scene, ViewLayer *view_layer); + virtual void build_scene_parameters(Scene *scene); + virtual void build_scene_compositor(Scene *scene); + + virtual void build_layer_collections(ListBase *lb); + virtual void build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state); + virtual void build_collection(LayerCollection *from_layer_collection, + Object *object, + Collection *collection); + virtual void build_object(Base *base, Object *object); + virtual void build_object_proxy_from(Object *object); + virtual void build_object_proxy_group(Object *object); + virtual void build_object_flags(Base *base, Object *object); + virtual void build_object_data(Object *object); + virtual void build_object_data_camera(Object *object); + virtual void build_object_data_geometry(Object *object); + virtual void build_object_data_geometry_datablock(ID *obdata); + virtual void build_object_data_light(Object *object); + virtual void build_object_data_lightprobe(Object *object); + virtual void build_object_data_speaker(Object *object); + virtual void build_object_parent(Object *object); + virtual void build_object_pointcache(Object *object); + virtual void build_constraints(ID *id, + NodeType component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map); + virtual void build_animdata(ID *id); + virtual void build_animdata_curves(ID *id); + virtual void build_animdata_curves_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *curves); + virtual void build_animdata_nlastrip_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *strips); + virtual void build_animdata_drivers(ID *id); + virtual void build_animation_images(ID *id); + virtual void build_action(bAction *action); + virtual void build_driver(ID *id, FCurve *fcurve); + virtual void build_driver_data(ID *id, FCurve *fcurve); + virtual void build_driver_variables(ID *id, FCurve *fcurve); + virtual void build_driver_id_property(ID *id, const char *rna_path); + virtual void build_parameters(ID *id); + virtual void build_world(World *world); + virtual void build_rigidbody(Scene *scene); + virtual void build_particle_systems(Object *object); + virtual void build_particle_settings(ParticleSettings *part); + virtual void build_particle_system_visualization_object(Object *object, + ParticleSystem *psys, + Object *draw_object); + virtual void build_ik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + virtual void build_splineik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + virtual void build_rig(Object *object); + virtual void build_proxy_rig(Object *object); + virtual void build_shapekeys(Key *key); + virtual void build_armature(bArmature *armature); + virtual void build_camera(Camera *camera); + virtual void build_light(Light *lamp); + virtual void build_nodetree(bNodeTree *ntree); + virtual void build_material(Material *ma); + virtual void build_materials(Material **materials, int num_materials); + virtual void build_texture(Tex *tex); + virtual void build_image(Image *image); + virtual void build_gpencil(bGPdata *gpd); + virtual void build_cachefile(CacheFile *cache_file); + virtual void build_mask(Mask *mask); + virtual void build_movieclip(MovieClip *clip); + virtual void build_lightprobe(LightProbe *probe); + virtual void build_speaker(Speaker *speaker); + virtual void build_sound(bSound *sound); + virtual void build_scene_sequencer(Scene *scene); + virtual void build_scene_audio(Scene *scene); + virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer); + + virtual void build_nested_datablock(ID *owner, ID *id); + virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree); + virtual void build_nested_shapekey(ID *owner, Key *key); void add_particle_collision_relations(const OperationKey &key, Object *object, @@ -290,8 +292,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { bool add_absorption, const char *name); - void build_copy_on_write_relations(); - void build_copy_on_write_relations(IDNode *id_node); + virtual void build_copy_on_write_relations(); + virtual void build_copy_on_write_relations(IDNode *id_node); template<typename KeyType> OperationNode *find_operation_node(const KeyType &key); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index e53ac40f196..180499519f6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -280,7 +280,11 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) || RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) || RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) || - RNA_struct_is_a(ptr->type, &RNA_GPencilLayer)) { + RNA_struct_is_a(ptr->type, &RNA_GPencilLayer) || + RNA_struct_is_a(ptr->type, &RNA_LatticePoint) || + RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) || + RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) || + RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement)) { /* When modifier is used as FROM operation this is likely referencing to * the property (for example, modifier's influence). * But when it's used as TO operation, this is geometry component. */ diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index dcdea87fe1a..8f9595d2476 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -76,7 +76,7 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati ctime(BKE_scene_frame_get(scene)), scene_cow(NULL), is_active(false), - debug_is_evaluating(false), + is_evaluating(false), is_render_pipeline_depsgraph(false) { BLI_spin_init(&lock); @@ -334,6 +334,12 @@ void DEG_graph_free(Depsgraph *graph) OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } +bool DEG_is_evaluating(struct Depsgraph *depsgraph) +{ + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + return deg_graph->is_evaluating; +} + bool DEG_is_active(const struct Depsgraph *depsgraph) { if (depsgraph == NULL) { diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 30ae4edde34..43829f4e045 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -198,7 +198,7 @@ struct Depsgraph { int debug_flags; string debug_name; - bool debug_is_evaluating; + bool is_evaluating; /* Is set to truth for dependency graph which are used for post-processing (compositor and * sequencer). diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 968ed8ef403..f67ab381c79 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -59,6 +59,7 @@ extern "C" { #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" +#include "intern/depsgraph_registry.h" #include "intern/depsgraph_type.h" /* ****************** */ @@ -323,6 +324,147 @@ void DEG_graph_build_for_compositor_preview( } } +/* Optimized builders for dependency graph built from a given set of IDs. + * + * General notes: + * + * - We pull in all bases if their objects are in the set of IDs. This allows to have proper + * visibility and other flags assigned to the objects. + * All other bases (the ones which points to object which is outside of the set of IDs) are + * completely ignored. + * + * - Proxy groups pointing to objects which are outside of the IDs set are also ignored. + * This way we avoid high-poly character body pulled into the dependency graph when it's coming + * from a library into an animation file and the dependency graph constructed for a proxy rig. */ + +namespace DEG { +namespace { + +class DepsgraphFromIDsFilter { + public: + DepsgraphFromIDsFilter(ID **ids, const int num_ids) + { + for (int i = 0; i < num_ids; ++i) { + ids_.insert(ids[0]); + } + } + + bool contains(ID *id) + { + return ids_.find(id) != ids_.end(); + } + + protected: + set<ID *> ids_; +}; + +class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder { + public: + DepsgraphFromIDsNodeBuilder( + Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids) + : DepsgraphNodeBuilder(bmain, graph, cache), filter_(ids, num_ids) + { + } + + virtual bool need_pull_base_into_graph(Base *base) override + { + if (!filter_.contains(&base->object->id)) { + return false; + } + return DepsgraphNodeBuilder::need_pull_base_into_graph(base); + } + + virtual void build_object_proxy_group(Object *object, bool is_visible) override + { + if (object->proxy_group == NULL) { + return; + } + if (!filter_.contains(&object->proxy_group->id)) { + return; + } + DepsgraphNodeBuilder::build_object_proxy_group(object, is_visible); + } + + protected: + DepsgraphFromIDsFilter filter_; +}; + +class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder { + public: + DepsgraphFromIDsRelationBuilder( + Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache, ID **ids, const int num_ids) + : DepsgraphRelationBuilder(bmain, graph, cache), filter_(ids, num_ids) + { + } + + virtual bool need_pull_base_into_graph(Base *base) override + { + if (!filter_.contains(&base->object->id)) { + return false; + } + return DepsgraphRelationBuilder::need_pull_base_into_graph(base); + } + + virtual void build_object_proxy_group(Object *object) override + { + if (object->proxy_group == NULL) { + return; + } + if (!filter_.contains(&object->proxy_group->id)) { + return; + } + DepsgraphRelationBuilder::build_object_proxy_group(object); + } + + protected: + DepsgraphFromIDsFilter filter_; +}; + +} // namespace +} // namespace DEG + +void DEG_graph_build_from_ids(Depsgraph *graph, + Main *bmain, + Scene *scene, + ViewLayer *view_layer, + ID **ids, + const int num_ids) +{ + double start_time = 0.0; + if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { + start_time = PIL_check_seconds_timer(); + } + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + /* Perform sanity checks. */ + BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); + BLI_assert(deg_graph->scene == scene); + BLI_assert(deg_graph->view_layer == view_layer); + DEG::DepsgraphBuilderCache builder_cache; + /* Generate all the nodes in the graph first */ + DEG::DepsgraphFromIDsNodeBuilder node_builder(bmain, deg_graph, &builder_cache, ids, num_ids); + node_builder.begin_build(); + node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + for (int i = 0; i < num_ids; ++i) { + node_builder.build_id(ids[i]); + } + node_builder.end_build(); + /* Hook up relationships between operations - to determine evaluation order. */ + DEG::DepsgraphFromIDsRelationBuilder relation_builder( + bmain, deg_graph, &builder_cache, ids, num_ids); + relation_builder.begin_build(); + relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + for (int i = 0; i < num_ids; ++i) { + relation_builder.build_id(ids[i]); + } + relation_builder.build_copy_on_write_relations(); + /* Finalize building. */ + graph_build_finalize_common(deg_graph, bmain); + /* Finish statistics. */ + if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { + printf("Depsgraph built in %f seconds.\n", PIL_check_seconds_timer() - start_time); + } +} + /* Tag graph relations for update. */ void DEG_graph_tag_relations_update(Depsgraph *graph) { @@ -356,12 +498,7 @@ void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, Vie void DEG_relations_tag_update(Main *bmain) { DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__); - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(bmain, scene, view_layer, false); - if (depsgraph != NULL) { - DEG_graph_tag_relations_update(depsgraph); - } - } + for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { + DEG_graph_tag_relations_update(reinterpret_cast<Depsgraph *>(depsgraph)); } } diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index d079c958e04..bb60db5209c 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -246,12 +246,6 @@ void DEG_stats_simple(const Depsgraph *graph, } } -bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph) -{ - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); - return deg_graph->debug_is_evaluating; -} - static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph) { const char *name = DEG_debug_name_get(depsgraph); diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index b2b7d2a9d00..665a32b886c 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -73,7 +73,7 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime) /* Update time on primary timesource. */ DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); tsrc->cfra = ctime; - tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME); + deg_graph->need_update_time = true; DEG::deg_graph_flush_updates(bmain, deg_graph); /* Update time in scene. */ if (deg_graph->scene_cow) { diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index 33cb1ba7416..b7a40fb69bd 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -68,9 +68,20 @@ void deg_foreach_clear_flags(const Depsgraph *graph) } } +bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags) +{ + if (flags & DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS) { + if (op_node->opcode == OperationCode::RIGIDBODY_SIM) { + return false; + } + } + return true; +} + void deg_foreach_dependent_operation(const Depsgraph *graph, const ID *id, eDepsObjectComponentType source_component_type, + int flags, DEGForeachOperation callback, void *user_data) { @@ -91,6 +102,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph, continue; } for (OperationNode *op_node : comp_node->operations) { + if (!deg_foreach_needs_visit(op_node, flags)) { + continue; + } queue.push_back(op_node); op_node->scheduled = true; op_node->owner->custom_flags |= DEG_NODE_VISITED; @@ -108,7 +122,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph, /* Schedule outgoing operation nodes. */ if (op_node->outlinks.size() == 1) { OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to; - if (to_node->scheduled == false) { + if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) { to_node->scheduled = true; op_node = to_node; } @@ -119,7 +133,7 @@ void deg_foreach_dependent_operation(const Depsgraph *graph, else { for (Relation *rel : op_node->outlinks) { OperationNode *to_node = (OperationNode *)rel->to; - if (to_node->scheduled == false) { + if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) { queue.push_front(to_node); to_node->scheduled = true; } @@ -150,6 +164,7 @@ void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user void deg_foreach_dependent_ID_component(const Depsgraph *graph, const ID *id, eDepsObjectComponentType source_component_type, + int flags, DEGForeachIDComponentCallback callback, void *user_data) { @@ -157,7 +172,7 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph, data.callback = callback; data.user_data = user_data; deg_foreach_dependent_operation( - graph, id, source_component_type, deg_foreach_dependent_component_callback, &data); + graph, id, source_component_type, flags, deg_foreach_dependent_component_callback, &data); } struct ForeachIDData { @@ -185,7 +200,7 @@ void deg_foreach_dependent_ID(const Depsgraph *graph, data.callback = callback; data.user_data = user_data; deg_foreach_dependent_operation( - graph, id, DEG_OB_COMP_ANY, deg_foreach_dependent_ID_callback, &data); + graph, id, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data); } void deg_foreach_ancestor_ID(const Depsgraph *graph, @@ -278,11 +293,12 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, const ID *id, eDepsObjectComponentType source_component_type, + int flags, DEGForeachIDComponentCallback callback, void *user_data) { DEG::deg_foreach_dependent_ID_component( - (const DEG::Depsgraph *)depsgraph, id, source_component_type, callback, user_data); + (const DEG::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data); } void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 251857b58c9..db469612f76 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -146,11 +146,13 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) *temp_dupli_object = *dob->ob; temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI; temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits; + temp_dupli_object->runtime.local_collections_bits = + dupli_parent->runtime.local_collections_bits; temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt); copy_v4_v4(temp_dupli_object->color, dupli_parent->color); /* Duplicated elements shouldn't care whether their original collection is visible or not. */ - temp_dupli_object->base_flag |= BASE_VISIBLE; + temp_dupli_object->base_flag |= BASE_VISIBLE_DEPSGRAPH; int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode); if ((ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) == 0) { diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 2fdce0e30a5..ce5917110d6 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -367,7 +367,7 @@ static void graph_id_tag_update_single_flag(Main *bmain, eUpdateSource update_source) { if (tag == ID_RECALC_EDITORS) { - if (graph != NULL) { + if (graph != NULL && graph->is_active) { depsgraph_update_editors_tag(bmain, graph, id); } return; @@ -462,7 +462,8 @@ const char *update_source_as_string(eUpdateSource source) int deg_recalc_flags_for_legacy_zero() { - return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE); + return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE | + ID_RECALC_TIME | ID_RECALC_EDITORS); } int deg_recalc_flags_effective(Depsgraph *graph, int flags) @@ -510,6 +511,14 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti * to evaluation though) with `do_time=true`. This means early output checks should be aware of * this. */ for (DEG::IDNode *id_node : graph->id_nodes) { + const ID_Type id_type = GS(id_node->id_orig->name); + if (id_type == ID_OB) { + Object *object_orig = reinterpret_cast<Object *>(id_node->id_orig); + if (object_orig->proxy != NULL) { + object_orig->proxy->proxy_from = object_orig; + } + } + if (!id_node->visible_components_mask) { /* ID has no components which affects anything visible. * No need bother with it to tag or anything. */ @@ -536,7 +545,6 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph, const bool do_ti * other type of cache). * * TODO(sergey): Need to generalize this somehow. */ - const ID_Type id_type = GS(id_node->id_orig->name); if (id_type == ID_OB) { flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; } @@ -614,6 +622,12 @@ void graph_id_tag_update( Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; + if (graph != NULL && graph->is_evaluating) { + if (debug_flags & G_DEBUG_DEPSGRAPH) { + printf("ID tagged for update during dependency graph evaluation."); + } + return; + } if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) { printf("%s: id=%s flags=%s source=%s\n", __func__, @@ -808,24 +822,6 @@ static void deg_graph_clear_id_recalc_flags(ID *id) } } -static void deg_graph_clear_id_node_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - /* TODO: we clear original ID recalc flags here, but this may not work - * correctly when there are multiple depsgraph with others still using - * the recalc flag. */ - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(data_v); - DEG::IDNode *id_node = deg_graph->id_nodes[i]; - - id_node->is_user_modified = false; - - deg_graph_clear_id_recalc_flags(id_node->id_cow); - if (deg_graph->is_active) { - deg_graph_clear_id_recalc_flags(id_node->id_orig); - } -} - void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) { DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); @@ -835,10 +831,15 @@ void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) return; } /* Go over all ID nodes nodes, clearing tags. */ - const int num_id_nodes = deg_graph->id_nodes.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_id_nodes, deg_graph, deg_graph_clear_id_node_func, &settings); + for (DEG::IDNode *id_node : deg_graph->id_nodes) { + /* TODO: we clear original ID recalc flags here, but this may not work + * correctly when there are multiple depsgraph with others still using + * the recalc flag. */ + id_node->is_user_modified = false; + deg_graph_clear_id_recalc_flags(id_node->id_cow); + if (deg_graph->is_active) { + deg_graph_clear_id_recalc_flags(id_node->id_orig); + } + } memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated)); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index b2415c9e89d..d6b3c54a149 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -91,10 +91,6 @@ static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) BLI_task_pool_delayed_push_end(pool, thread_id); } -struct CalculatePendingData { - Depsgraph *graph; -}; - static bool check_operation_node_visible(OperationNode *op_node) { const ComponentNode *comp_node = op_node->owner; @@ -106,13 +102,8 @@ static bool check_operation_node_visible(OperationNode *op_node) return comp_node->affects_directly_visible; } -static void calculate_pending_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) +static void calculate_pending_parents_for_node(OperationNode *node) { - CalculatePendingData *data = (CalculatePendingData *)data_v; - Depsgraph *graph = data->graph; - OperationNode *node = graph->operations[i]; /* Update counters, applies for both visible and invisible IDs. */ node->num_links_pending = 0; node->scheduled = false; @@ -134,7 +125,7 @@ static void calculate_pending_func(void *__restrict data_v, if (!check_operation_node_visible(from)) { continue; } - /* No need to vait for operation which is up to date. */ + /* No need to wait for operation which is up to date. */ if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { continue; } @@ -145,13 +136,9 @@ static void calculate_pending_func(void *__restrict data_v, static void calculate_pending_parents(Depsgraph *graph) { - const int num_operations = graph->operations.size(); - CalculatePendingData data; - data.graph = graph; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, &settings); + for (OperationNode *node : graph->operations) { + calculate_pending_parents_for_node(node); + } } static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph) @@ -221,7 +208,7 @@ static void schedule_node( static void schedule_graph(TaskPool *pool, Depsgraph *graph) { for (OperationNode *node : graph->operations) { - schedule_node(pool, graph, node, false, 0); + schedule_node(pool, graph, node, false, -1); } } @@ -270,7 +257,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph) } const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; - graph->debug_is_evaluating = true; + graph->is_evaluating = true; depsgraph_ensure_view_layer(graph); /* Set up evaluation state. */ DepsgraphEvalState state; @@ -311,7 +298,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph) if (need_free_scheduler) { BLI_task_scheduler_free(task_scheduler); } - graph->debug_is_evaluating = false; + graph->is_evaluating = false; if (do_time_debug) { printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 1f9c12f604d..73a0823f84b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -755,6 +755,25 @@ void update_animation_data_after_copy(const ID *id_orig, ID *id_cow) update_nla_tracks_orig_pointers(&anim_data_orig->nla_tracks, &anim_data_cow->nla_tracks); } +/* Some builders (like motion path one) will ignore proxies from being built. This code makes it so + * proxy and proxy_group pointers never point to an original objects, preventing evaluation code + * from assign evaluated pointer to an original proxy->proxy_from. */ +void update_proxy_pointers_after_copy(const Depsgraph * /*depsgraph*/, + const Object * /*object_orig*/, + Object *object_cow) +{ + if (object_cow->proxy != NULL) { + if ((object_cow->proxy->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { + object_cow->proxy = NULL; + } + } + if (object_cow->proxy_group != NULL) { + if ((object_cow->proxy_group->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { + object_cow->proxy_group = NULL; + } + } +} + /* Do some special treatment of data transfer from original ID to it's * CoW complementary part. * @@ -788,6 +807,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, } update_particles_after_copy(depsgraph, object_orig, object_cow); update_modifiers_orig_pointers(object_orig, object_cow); + update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow); break; } case ID_SCE: { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 2479373b687..96e2974a7ab 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -87,15 +87,6 @@ typedef std::deque<OperationNode *> FlushQueue; namespace { -void flush_init_operation_node_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - node->scheduled = false; -} - void flush_init_id_node_func(void *__restrict data_v, const int i, const TaskParallelTLS *__restrict /*tls*/) @@ -110,13 +101,10 @@ void flush_init_id_node_func(void *__restrict data_v, BLI_INLINE void flush_prepare(Depsgraph *graph) { - { - const int num_operations = graph->operations.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, graph, flush_init_operation_node_func, &settings); + for (OperationNode *node : graph->operations) { + node->scheduled = false; } + { const int num_id_nodes = graph->id_nodes.size(); TaskParallelSettings settings; @@ -351,9 +339,6 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) BLI_assert(bmain != NULL); BLI_assert(graph != NULL); /* Nothing to update, early out. */ - if (BLI_gset_len(graph->entry_tags) == 0 && !graph->need_update_time) { - return; - } if (graph->need_update_time) { const Scene *scene_orig = graph->scene; const float ctime = BKE_scene_frame_get(scene_orig); @@ -361,6 +346,9 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) graph->ctime = ctime; time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME); } + if (BLI_gset_len(graph->entry_tags) == 0) { + return; + } /* Reset all flags, get ready for the flush. */ flush_prepare(graph); /* Starting from the tagged "entry" nodes, flush outwards. */ @@ -395,27 +383,13 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) invalidate_tagged_evaluated_data(graph); } -static void graph_clear_operation_func(void *__restrict data_v, - const int i, - const TaskParallelTLS *__restrict /*tls*/) -{ - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - /* Clear node's "pending update" settings. */ - node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | - DEPSOP_FLAG_USER_MODIFIED); -} - /* Clear tags from all operation nodes. */ void deg_graph_clear_tags(Depsgraph *graph) { /* Go over all operation nodes, clearing tags. */ - { - const int num_operations = graph->operations.size(); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, graph, graph_clear_operation_func, &settings); + for (OperationNode *node : graph->operations) { + node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | + DEPSOP_FLAG_USER_MODIFIED); } /* Clear any entry tags which haven't been flushed. */ BLI_gset_clear(graph->entry_tags, NULL); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 179ce21b71d..38e538c4e65 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -314,6 +314,7 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl SRC) +data_to_c_simple(modes/shaders/edit_mesh_skin_root_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC) data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC) diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index f548bd15bf4..0dd1a4fd686 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -72,7 +72,6 @@ static struct { typedef struct BASIC_PrivateData { DRWShadingGroup *depth_shgrp; DRWShadingGroup *depth_shgrp_cull; - DRWShadingGroup *depth_shgrp_hair; } BASIC_PrivateData; /* Transient data */ /* Functions */ @@ -162,7 +161,8 @@ static void basic_cache_populate(void *vedata, Object *ob) } } - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 7df1c299454..d59d1f56e92 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -29,6 +29,7 @@ #include "eevee_private.h" #include "GPU_texture.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 19f3983998e..4b0af273f7f 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -51,7 +51,6 @@ static struct { struct GPUTexture *planar_pool_placeholder; struct GPUTexture *depth_placeholder; struct GPUTexture *depth_array_placeholder; - struct GPUTexture *cube_face_minmaxz; struct GPUVertFormat *format_probe_display_cube; struct GPUVertFormat *format_probe_display_planar; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 712bcc43f52..701d73461fc 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -48,6 +48,9 @@ static struct { char *frag_shader_lib; char *vert_shader_str; char *vert_shadow_shader_str; + char *vert_background_shader_str; + char *vert_volume_shader_str; + char *geom_volume_shader_str; char *volume_shader_lib; struct GPUShader *default_prepass_sh; @@ -565,6 +568,15 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, e_data.vert_shadow_shader_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); + e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_background_vert_glsl); + + e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_vert_glsl); + + e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_volumetric_geom_glsl); + e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, @@ -637,7 +649,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor wo, engine, options, - datatoc_background_vert_glsl, + e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define PROBE_CAPTURE\n", @@ -657,7 +669,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor wo, engine, options, - datatoc_background_vert_glsl, + e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define WORLD_BACKGROUND\n", @@ -680,8 +692,8 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * wo, engine, options, - datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, + e_data.vert_volume_shader_str, + e_data.geom_volume_shader_str, e_data.volume_shader_lib, defines, true); @@ -741,8 +753,8 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material ma, engine, options, - datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, + e_data.vert_volume_shader_str, + e_data.geom_volume_shader_str, e_data.volume_shader_lib, defines, true); @@ -1338,6 +1350,24 @@ static void material_transparent(Material *ma, const float *spec_p = &ma->spec; const float *rough_p = &ma->roughness; + const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); + + DRWState cur_state; + DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK | + DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL | + DRW_STATE_BLEND_CUSTOM); + + /* Depth prepass */ + if (use_prepass) { + *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + + cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; + + DRW_shgroup_state_disable(*shgrp_depth, all_state); + DRW_shgroup_state_enable(*shgrp_depth, cur_state); + } + if (ma->use_nodes && ma->nodetree) { static float error_col[3] = {1.0f, 0.0f, 1.0f}; static float compile_col[3] = {0.5f, 0.5f, 0.5f}; @@ -1394,30 +1424,13 @@ static void material_transparent(Material *ma, DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1); } - const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0); - - DRWState all_state = (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL | - DRW_STATE_BLEND_CUSTOM); - - DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; /* Disable other blend modes and use the one we want. */ DRW_shgroup_state_disable(*shgrp, all_state); DRW_shgroup_state_enable(*shgrp, cur_state); - - /* Depth prepass */ - if (use_prepass) { - *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); - - cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; - - DRW_shgroup_state_disable(*shgrp_depth, all_state); - DRW_shgroup_state_enable(*shgrp_depth, cur_state); - } } /* Return correct material or &defmaterial if slot is empty. */ @@ -1441,7 +1454,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, Scene *scene = draw_ctx->scene; GHash *material_hash = stl->g_data->material_hash; - bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); /* First get materials for this mesh. */ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { @@ -1574,7 +1588,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Shadow Pass */ struct GPUMaterial *gpumat; - switch (ma_array[i]->blend_shadow) { + const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree); + char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID; + switch (blend_shadow) { case MA_BS_SOLID: EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob); *cast_shadow = true; @@ -1734,6 +1750,9 @@ void EEVEE_materials_free(void) MEM_SAFE_FREE(e_data.frag_shader_lib); MEM_SAFE_FREE(e_data.vert_shader_str); MEM_SAFE_FREE(e_data.vert_shadow_shader_str); + MEM_SAFE_FREE(e_data.vert_background_shader_str); + MEM_SAFE_FREE(e_data.vert_volume_shader_str); + MEM_SAFE_FREE(e_data.geom_volume_shader_str); MEM_SAFE_FREE(e_data.volume_shader_lib); DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh); DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh); diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 924b3d3b19b..48e9b5bcc13 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -33,6 +33,7 @@ #include "eevee_private.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_state.h" static struct { @@ -40,7 +41,6 @@ static struct { struct GPUShader *gtao_sh; struct GPUShader *gtao_layer_sh; struct GPUShader *gtao_debug_sh; - struct GPUTexture *src_depth; struct GPUTexture *dummy_horizon_tx; } e_data = {NULL}; /* Engine data */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 2daf2388d63..591ca31017c 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -46,7 +46,6 @@ static struct { /* These are just references, not actually allocated */ struct GPUTexture *depth_src; - struct GPUTexture *color_src; } e_data = {{NULL}}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 257ec6bc8f0..46fc6e07c1c 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -163,7 +163,7 @@ void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata, return; } - /* Grrr needed for correctness but not 99% of the time not needed. + /* Unfortunately needed for correctness but not 99% of the time not needed. * TODO detect when needed? */ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 30ad8482f76..8376b8c67b8 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -356,7 +356,7 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if (!DRW_pass_is_empty(psl->sss_translucency_ps)) { - /* We sample the shadowmaps using normal sampler. We need to disable Comparison mode. + /* We sample the shadow-maps using normal sampler. We need to disable Comparison mode. * TODO(fclem) avoid this by using sampler objects.*/ GPU_texture_bind(sldata->shadow_cube_pool, 0); GPU_texture_compare_mode(sldata->shadow_cube_pool, false); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 726082c0f02..aaa351a1922 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -54,7 +54,6 @@ static struct { struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; - GPUTexture *color_src; GPUTexture *depth_src; GPUTexture *dummy_density; @@ -255,7 +254,7 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (DRW_view_is_persp_get(NULL)) { float sample_distribution = scene_eval->eevee.volumetric_sample_distribution; - sample_distribution = 4.0f * (1.00001f - sample_distribution); + sample_distribution = 4.0f * (max_ff(1.0f - sample_distribution, 1e-2f)); const float clip_start = common_data->view_vecs[0][2]; /* Negate */ @@ -413,7 +412,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps); - BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); + BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, &texcosize); /* TODO(fclem) remove those "unnecessary" UBOs */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); @@ -632,7 +631,7 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) int tex_transmit = GPU_texture_opengl_bindcode(txl->volume_transmit_history); /* TODO(fclem) Encapsulate these GL calls into DRWManager. */ glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - /* Subtility here! we need to tell the GL that the texture is layered (GL_TRUE) + /* Subtlety here! we need to tell the GL that the texture is layered (GL_TRUE) * in order to bind the full 3D texture and not just a 2D slice. */ glBindImageTexture(0, tex_scatter, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F); glBindImageTexture(1, tex_transmit, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R11F_G11F_B10F); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 98012aea303..f10d98e68bd 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -140,6 +140,10 @@ float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } +float min_v4(vec4 v) +{ + return min(min(v.x, v.y), min(v.z, v.w)); +} float max_v2(vec2 v) { return max(v.x, v.y); @@ -148,6 +152,10 @@ float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); } +float max_v4(vec4 v) +{ + return max(max(v.x, v.y), max(v.z, v.w)); +} float sum(vec2 v) { @@ -918,14 +926,15 @@ void main() Closure cl = nodetree_exec(); float holdout = 1.0 - saturate(cl.holdout); + float transmit = saturate(avg(cl.transmittance)); + float alpha = 1.0 - transmit; # ifdef USE_ALPHA_BLEND vec2 uvs = gl_FragCoord.xy * volCoordScale.zw; vec3 vol_transmit, vol_scatter; volumetric_resolve(uvs, gl_FragCoord.z, vol_transmit, vol_scatter); - float transmit = saturate(avg(cl.transmittance)); - outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, (1.0 - transmit) * holdout); + outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout); outTransmittance = vec4(cl.transmittance, transmit * holdout); # else outRadiance = vec4(cl.radiance, holdout); @@ -953,6 +962,16 @@ void main() outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac; # endif + +# ifndef USE_ALPHA_BLEND + float alpha_div = 1.0 / max(1e-8, alpha); + outRadiance.rgb *= alpha_div; + outRadiance.a = 1.0; + ssrData.rgb *= alpha_div; +# ifdef USE_SSS + sssAlbedo.rgb *= alpha_div; +# endif +# endif } # endif /* MESH_SHADER && !SHADOW_SHADER */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl index 86f53522bc6..6531ceb8dbe 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -70,6 +70,18 @@ float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector) #define scube(x) shadows_cube_data[x] #define scascade(x) shadows_cascade_data[x] +float shadow_cube_radial_depth(vec3 cubevec, float tex_id, int shadow_id) +{ + float depth = sample_cube(sssShadowCubes, cubevec, tex_id).r; + /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */ + const float depth_bias = 3.1e-5; + depth = saturate(depth - depth_bias); + + depth = linear_depth(true, depth, sd(shadow_id).sh_far, sd(shadow_id).sh_near); + depth *= length(cubevec / max_v3(abs(cubevec))); + return depth; +} + vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale) { int shadow_id = int(ld.l_shadowid); @@ -79,12 +91,12 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f /* We use the full l_vector.xyz so that the spread is minimize * if the shading point is further away from the light source */ /* TODO(fclem) do something better than this. */ - // vec3 T, B; - // make_orthonormal_basis(L.xyz / L.w, T, B); - // rand.xy *= data.sh_blur; - // W = W + T * rand.x + B * rand.y; + vec3 T, B; + make_orthonormal_basis(L.xyz / L.w, T, B); - float s, dist; + vec3 n; + vec4 depths; + float d, dist; int data_id = int(sd(shadow_id).sh_data_index); if (ld.l_type == SUN) { vec4 view_z = vec4(dot(W - cameraPos, cameraForward)); @@ -105,20 +117,62 @@ vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, f return vec3(0.0); } - float tex_id = scascade(data_id).sh_tex_index; - s = sample_cascade(sssShadowCascades, shpos.xy, tex_id + id).r; - s *= range; + float tex_id = scascade(data_id).sh_tex_index + id; + + /* Assume cascades have same height and width. */ + vec2 ofs = vec2(1.0, 0.0) / float(textureSize(sssShadowCascades, 0).x); + d = sample_cascade(sssShadowCascades, shpos.xy, tex_id).r; + depths.x = sample_cascade(sssShadowCascades, shpos.xy + ofs.xy, tex_id).r; + depths.y = sample_cascade(sssShadowCascades, shpos.xy + ofs.yx, tex_id).r; + depths.z = sample_cascade(sssShadowCascades, shpos.xy - ofs.xy, tex_id).r; + depths.w = sample_cascade(sssShadowCascades, shpos.xy - ofs.yx, tex_id).r; + + /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */ + float depth_bias = 3.1e-5; + depths = saturate(depths - depth_bias); + d = saturate(d - depth_bias); + + /* Size of a texel in world space. + * FIXME This is only correct if l_right is the same right vector used for shadowmap creation. + * This won't work if the shadow matrix is rotated (soft shadows). + * TODO precompute */ + float unit_world_in_uv_space = length(mat3(scascade(data_id).shadowmat[int(id)]) * ld.l_right); + float dx_scale = 2.0 * ofs.x / unit_world_in_uv_space; + + d *= range; + depths *= range; + + /* This is the normal of the occluder in world space. */ + // vec3 T = ld.l_forward * dx + ld.l_right * dx_scale; + // vec3 B = ld.l_forward * dy + ld.l_up * dx_scale; + // n = normalize(cross(T, B)); } else { + float ofs = 1.0 / float(textureSize(sssShadowCubes, 0).x); + vec3 cubevec = transform_point(scube(data_id).shadowmat, W); dist = length(cubevec); cubevec /= dist; /* tex_id == data_id for cube shadowmap */ float tex_id = float(data_id); - s = sample_cube(sssShadowCubes, cubevec, tex_id).r; - s = length(cubevec / max_v3(abs(cubevec))) * - linear_depth(true, s, sd(shadow_id).sh_far, sd(shadow_id).sh_near); + d = shadow_cube_radial_depth(cubevec, tex_id, shadow_id); + /* NOTE: The offset is irregular in respect to cubeface uvs. But it has + * a much more uniform behavior than biasing based on face derivatives. */ + depths.x = shadow_cube_radial_depth(cubevec + T * ofs, tex_id, shadow_id); + depths.y = shadow_cube_radial_depth(cubevec + B * ofs, tex_id, shadow_id); + depths.z = shadow_cube_radial_depth(cubevec - T * ofs, tex_id, shadow_id); + depths.w = shadow_cube_radial_depth(cubevec - B * ofs, tex_id, shadow_id); } + + float dx = depths.x - depths.z; + float dy = depths.y - depths.w; + + float s = min(d, min_v4(depths)); + + /* To avoid light leak from depth discontinuity and shadowmap aliasing. */ + float slope_bias = (abs(dx) + abs(dy)) * 0.5; + s -= slope_bias; + float delta = dist - s; float power = light_translucent_power_with_falloff(ld, N, l_vector); diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index b1c78cae54f..6427f02ed25 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -70,7 +70,6 @@ vec2 cubeFaceCoordEEVEE(vec3 P, float face, sampler2DArrayShadow tex) vec4 sample_cube(sampler2DArray tex, vec3 cubevec, float cube) { /* Manual Shadow Cube Layer indexing. */ - /* TODO Shadow Cube Array. */ float face = cubeFaceIndexEEVEE(cubevec); vec2 uv = cubeFaceCoordEEVEE(cubevec, face, tex); diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index f6646ca575e..704e16b2907 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -28,6 +28,8 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "BKE_object.h" + #include "ED_screen.h" #include "GPU_matrix.h" @@ -156,7 +158,8 @@ static void external_cache_populate(void *vedata, Object *ob) { EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl; - if (!DRW_object_is_renderable(ob)) { + if (!(DRW_object_is_renderable(ob) && + DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { return; } diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 33e6d73eeeb..f9df1342bf8 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -50,10 +50,6 @@ static bool gpencil_has_noninstanced_object(Object *ob_instance) if (ob->type != OB_GPENCIL) { continue; } - /* object must be visible (invisible objects don't create VBO data) */ - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - continue; - } /* is not duplicated and the name is equals */ if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { if (STREQ(ob->id.name, ob_instance->id.name)) { diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index fbaf35890f1..af315597e68 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -37,7 +37,6 @@ #include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_view3d_types.h" -#include "DNA_gpencil_modifier_types.h" /* If builtin shaders are needed */ #include "GPU_shader.h" @@ -135,24 +134,24 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, GpencilBatchCache *cache, bGPdata *gpd) { - if (!cache->is_dirty) { + if ((!cache->is_dirty) || (gpd == NULL)) { return; } Object *ob = cache_ob->ob; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool main_onion = draw_ctx->v3d != NULL ? - (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : - true; + const bool main_onion = stl->storage->is_main_onion; const bool playing = stl->storage->is_playing; - const bool overlay = draw_ctx->v3d != NULL ? - (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : - true; + const bool overlay = stl->storage->is_main_overlay; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion && !playing && gpencil_onion_active(gpd); const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + /* Onion skinning. */ + const int step = gpd->gstep; + const int mode = gpd->onion_mode; + const short onion_keytype = gpd->onion_keytype; + cache_ob->tot_vertex = 0; cache_ob->tot_triangles = 0; int idx_eval = 0; @@ -165,7 +164,33 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, continue; } - /* if multiedit or onion skin need to count all frames of the layer */ + /* Relative onion mode needs to find the frame range before. */ + int frame_from = -9999; + int frame_to = 9999; + if ((is_onion) && (mode == GP_ONION_MODE_RELATIVE)) { + /* 1) Found first Frame. */ + int idx = 0; + if (gpl->actframe) { + for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) { + idx++; + frame_from = gf->framenum; + if (idx >= step) { + break; + } + } + /* 2) Found last Frame. */ + idx = 0; + for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) { + idx++; + frame_to = gf->framenum; + if (idx >= gpd->gstep_next) { + break; + } + } + } + } + + /* If multiedit or onion skin need to count all frames of the layer. */ if ((is_multiedit) || (is_onion)) { init_gpf = gpl->frames.first; } @@ -179,9 +204,46 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - cache_ob->tot_vertex += gps->totpoints + 3; - cache_ob->tot_triangles += gps->totpoints - 1; + if (!is_onion) { + if ((!is_multiedit) || + ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) { + cache_ob->tot_vertex += gps->totpoints + 3; + cache_ob->tot_triangles += gps->totpoints - 1; + } + } + else { + bool select = ((is_multiedit) && + ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT))); + + if (!select) { + /* Only selected frames. */ + if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) { + continue; + } + /* Verify keyframe type. */ + if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) { + continue; + } + /* Absolute range. */ + if (mode == GP_ONION_MODE_ABSOLUTE) { + if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) { + continue; + } + } + /* Relative range. */ + if (mode == GP_ONION_MODE_RELATIVE) { + if ((gpf->framenum < frame_from) || (gpf->framenum > frame_to)) { + continue; + } + } + } + + cache_ob->tot_vertex += gps->totpoints + 3; + cache_ob->tot_triangles += gps->totpoints - 1; + } } + + /* If not multiframe nor Onion skin, don't need follow counting. */ if ((!is_multiedit) && (!is_onion)) { break; } @@ -194,23 +256,6 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl, cache->b_point.tot_vertex = cache_ob->tot_vertex; cache->b_edit.tot_vertex = cache_ob->tot_vertex; cache->b_edlin.tot_vertex = cache_ob->tot_vertex; - - /* some modifiers can change the number of points */ - int factor = 0; - GpencilModifierData *md; - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - /* only modifiers that change size */ - if (mti && mti->getDuplicationFactor) { - factor = mti->getDuplicationFactor(md); - - cache->b_fill.tot_vertex *= factor; - cache->b_stroke.tot_vertex *= factor; - cache->b_point.tot_vertex *= factor; - cache->b_edit.tot_vertex *= factor; - cache->b_edlin.tot_vertex *= factor; - } - } } /* Helper for doing all the checks on whether a stroke can be drawn */ @@ -414,10 +459,12 @@ static void set_wireframe_color(Object *ob, } /* create shading group for filling */ -static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata, +static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data, + GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, + float (*obmat)[4], bGPdata *gpd, bGPDlayer *gpl, MaterialGPencilStyle *gp_style, @@ -431,6 +478,8 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata, /* e_data.gpencil_fill_sh */ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat); + DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1); /* set style type */ @@ -540,7 +589,7 @@ static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_Data *vedata, } else { /* if no texture defined, need a blank texture to avoid errors in draw manager */ - DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture); + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); stl->shgroups[id].texture_clamp = 0; DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1); } @@ -560,10 +609,12 @@ bool gpencil_onion_active(bGPdata *gpd) } /* create shading group for strokes */ -DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata, +DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data, + GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, + float (*obmat)[4], bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, @@ -585,6 +636,8 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata, DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat); + /* avoid wrong values */ if ((gpd) && (gpd->pixfactor == 0.0f)) { gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; @@ -716,17 +769,19 @@ DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_Data *vedata, } else { /* if no texture defined, need a blank texture to avoid errors in draw manager */ - DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture); + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); } return grp; } /* create shading group for points */ -static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata, +static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data, + GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, + float (*obmat)[4], bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, @@ -747,6 +802,8 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata, DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1); DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat); + /* avoid wrong values */ if ((gpd) && (gpd->pixfactor == 0.0f)) { gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; @@ -885,7 +942,7 @@ static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_Data *vedata, } else { /* if no texture defined, need a blank texture to avoid errors in draw manager */ - DRW_shgroup_uniform_texture(grp, "myTexture", stl->g_data->gpencil_blank_texture); + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); } return grp; @@ -1071,7 +1128,7 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache, */ const bool show_points = (show_sculpt_points) || (is_weight_paint) || (GPENCIL_EDIT_MODE(gpd) && - ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0)); + (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE)); if (cache->is_dirty) { if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && @@ -1144,7 +1201,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache, const bool playing = stl->storage->is_playing; const bool is_render = (bool)stl->storage->is_render; const bool is_mat_preview = (bool)stl->storage->is_mat_preview; - const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true; + const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : + true; /* Get evaluation context */ /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files @@ -1168,6 +1226,12 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache, continue; } + /* Copy color to temp fields. */ + if ((is_multiedit) && (gp_style)) { + copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); + } + /* be sure recalc all cache in source stroke to avoid recalculation when frame change * and improve fps */ gpencil_recalc_geometry_caches( @@ -1185,7 +1249,8 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache, } } - if ((gpl->actframe->framenum == gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) { + if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) || + (overlay_multiedit)) { /* hide any blend layer */ if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) { /* fill */ @@ -1216,12 +1281,14 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache, if (!stl->g_data->shgrps_edit_line) { stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, psl->edit_pass); + DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_line, "gpModelMatrix", ob->obmat); } if (!stl->g_data->shgrps_edit_point) { stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->edit_pass); const float *viewport_size = DRW_viewport_size_get(); DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1); + DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_point, "gpModelMatrix", ob->obmat); } gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps); @@ -1304,19 +1371,19 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, int idx; float fac = 1.0f; int step = 0; - int mode = 0; bool colflag = false; - bGPDframe *gpf_loop = NULL; + const int mode = gpd->onion_mode; + bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ? + gpl->frames.first : + NULL; int last = gpf->framenum; - colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL; + colflag = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0; const short onion_keytype = gpd->onion_keytype; - /* ------------------------------- * 1) Draw Previous Frames First * ------------------------------- */ step = gpd->gstep; - mode = gpd->onion_mode; if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) { copy_v3_v3(color, gpd->gcolor_prev); @@ -1365,7 +1432,7 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, } /* if loop option, save the frame to use later */ - if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) { + if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) { gpf_loop = gf; } @@ -1376,7 +1443,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, * 2) Now draw next frames * ------------------------------- */ step = gpd->gstep_next; - mode = gpd->onion_mode; if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) { copy_v3_v3(color, gpd->gcolor_next); @@ -1555,6 +1621,9 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol); } + static float unit_mat[4][4] = { + {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; + /* drawing strokes */ /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) @@ -1575,10 +1644,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, if (gpd->runtime.sbuffer_used > 1) { if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, + unit_mat, gpd, NULL, NULL, @@ -1599,10 +1670,12 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, } else { stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, + unit_mat, gpd, NULL, NULL, @@ -1662,6 +1735,8 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass); const float *viewport_size = DRW_viewport_size_get(); DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1); + DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat); + /* Disable stencil for this type */ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd); @@ -1671,7 +1746,7 @@ void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, } /* create all missing batches */ -static void gpencil_create_batches(GpencilBatchCache *cache) +static void gpencil_batches_ensure(GpencilBatchCache *cache) { if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) { cache->b_point.batch = GPU_batch_create_ex( @@ -1722,8 +1797,8 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, const bool overlay = draw_ctx->v3d != NULL ? (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true; - const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion && + const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; + const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion && overlay && gpencil_onion_active(gpd); int start_stroke = 0; @@ -1785,10 +1860,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, case eGpencilBatchGroupType_Stroke: { const int len = elm->vertex_idx - start_stroke; - shgrp = gpencil_shgroup_stroke_create(vedata, + shgrp = gpencil_shgroup_stroke_create(e_data, + vedata, stroke_pass, e_data->gpencil_stroke_sh, ob, + obmat, gpd, gpl, gps, @@ -1797,32 +1874,37 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, elm->onion, scale, cache_ob->shading_type); - if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_obmat(shgrp, cache->b_stroke.batch, obmat, start_stroke, len); - } - stl->storage->shgroup_id++; - start_stroke = elm->vertex_idx; /* set stencil mask id */ if (gpencil_is_stencil_required(gp_style)) { + if (stencil_id == 1) { + /* Clear previous stencils. */ + DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0); + } DRW_shgroup_stencil_mask(shgrp, stencil_id); stencil_id++; } else { /* Disable stencil for this type */ DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - /* set stencil mask id as not used */ - DRW_shgroup_stencil_mask(shgrp, 0x0); } + + if ((do_onion) || (elm->onion == false)) { + DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len); + } + stl->storage->shgroup_id++; + start_stroke = elm->vertex_idx; break; } case eGpencilBatchGroupType_Point: { const int len = elm->vertex_idx - start_point; - shgrp = gpencil_shgroup_point_create(vedata, + shgrp = gpencil_shgroup_point_create(e_data, + vedata, stroke_pass, e_data->gpencil_point_sh, ob, + obmat, gpd, gpl, gps, @@ -1832,49 +1914,50 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, scale, cache_ob->shading_type); + /* Disable stencil for this type */ + DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); + if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_obmat(shgrp, cache->b_point.batch, obmat, start_point, len); + DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len); } stl->storage->shgroup_id++; start_point = elm->vertex_idx; - - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - /* set stencil mask id as not used */ - DRW_shgroup_stencil_mask(shgrp, 0x0); break; } case eGpencilBatchGroupType_Fill: { const int len = elm->vertex_idx - start_fill; - shgrp = gpencil_shgroup_fill_create(vedata, + shgrp = gpencil_shgroup_fill_create(e_data, + vedata, stroke_pass, e_data->gpencil_fill_sh, ob, + obmat, gpd, gpl, gp_style, stl->storage->shgroup_id, cache_ob->shading_type); + /* Disable stencil for this type */ + DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); + if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_obmat(shgrp, cache->b_fill.batch, obmat, start_fill, len); + DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len); } stl->storage->shgroup_id++; start_fill = elm->vertex_idx; - - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - /* set stencil mask id as not used */ - DRW_shgroup_stencil_mask(shgrp, 0x0); break; } case eGpencilBatchGroupType_Edit: { if (stl->g_data->shgrps_edit_point) { const int len = elm->vertex_idx - start_edit; + + shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point); + DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat); /* use always the same group */ - DRW_shgroup_call_range_obmat( - stl->g_data->shgrps_edit_point, cache->b_edit.batch, obmat, start_edit, len); + DRW_shgroup_call_range( + stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len); start_edit = elm->vertex_idx; } @@ -1883,9 +1966,12 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data, case eGpencilBatchGroupType_Edlin: { if (stl->g_data->shgrps_edit_line) { const int len = elm->vertex_idx - start_edlin; + + shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line); + DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat); /* use always the same group */ - DRW_shgroup_call_range_obmat( - stl->g_data->shgrps_edit_line, cache->b_edlin.batch, obmat, start_edlin, len); + DRW_shgroup_call_range( + stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len); start_edlin = elm->vertex_idx; } @@ -1963,7 +2049,7 @@ void gpencil_populate_multiedit(GPENCIL_e_data *e_data, } /* create batchs and shading groups */ - gpencil_create_batches(cache); + gpencil_batches_ensure(cache); gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); cache->is_dirty = false; @@ -1992,13 +2078,9 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data, bGPdata *gpd_eval = (bGPdata *)ob->data; bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id); - const bool main_onion = draw_ctx->v3d != NULL ? - (draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : - true; + const bool main_onion = stl->storage->is_main_onion; const bool playing = stl->storage->is_playing; - const bool overlay = draw_ctx->v3d != NULL ? - (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : - true; + const bool overlay = stl->storage->is_main_overlay; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion && !playing && gpencil_onion_active(gpd); @@ -2086,7 +2168,7 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data, } /* create batchs and shading groups */ - gpencil_create_batches(cache); + gpencil_batches_ensure(cache); gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); cache->is_dirty = false; diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index d03f975ca37..051c2837727 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -24,11 +24,13 @@ #include "BKE_gpencil.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_shader_fx.h" #include "DNA_gpencil_types.h" +#include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "draw_mode_engines.h" @@ -61,6 +63,8 @@ extern char datatoc_gpencil_edit_point_geom_glsl[]; extern char datatoc_gpencil_edit_point_frag_glsl[]; extern char datatoc_gpencil_blend_frag_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; + extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; @@ -111,7 +115,7 @@ static void GPENCIL_create_framebuffers(void *vedata) const float *viewport_size = DRW_viewport_size_get(); const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - /* create multiframe framebuffer for AA */ + /* create multisample framebuffer for AA */ if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) && (stl->storage->multisamples > 0)) { gpencil_multisample_ensure(vedata, size[0], size[1]); @@ -176,6 +180,12 @@ static void GPENCIL_create_framebuffers(void *vedata) static void GPENCIL_create_shaders(void) { + /* blank texture used if no texture defined for fill shader */ + if (!e_data.gpencil_blank_texture) { + float rect[1][1][4] = {{{0.0f}}}; + e_data.gpencil_blank_texture = DRW_texture_create_2d( + 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect); + } /* normal fill shader */ if (!e_data.gpencil_fill_sh) { e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({ @@ -221,7 +231,12 @@ static void GPENCIL_create_shaders(void) /* used for edit lines for edit modes */ if (!e_data.gpencil_line_sh) { - e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR); + e_data.gpencil_line_sh = DRW_shader_create_with_lib( + datatoc_gpencil_edit_point_vert_glsl, + NULL, + datatoc_gpu_shader_3D_smooth_color_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } /* used to filling during drawing */ @@ -279,16 +294,56 @@ static void GPENCIL_engine_free(void) DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh); DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh); + DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture); + /* effects */ GPENCIL_delete_fx_shaders(&e_data); } +/* Helper: Check if the main overlay and onion switches are enabled in any screen. + * + * This is required to generate the onion skin and limit the times the cache is updated because the + * cache is generated only in the first screen and if the first screen has the onion disabled the + * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate + * the cache all the times. + */ +static void gpencil_check_screen_switches(const DRWContextState *draw_ctx, + GPENCIL_StorageList *stl) +{ + stl->storage->is_main_overlay = false; + stl->storage->is_main_onion = false; + /* Check if main onion switch is enabled in any screen. */ + Main *bmain = CTX_data_main(draw_ctx->evil_C); + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa && sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = sa->spacedata.first; + if (v3d == NULL) { + continue; + } + if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) { + stl->storage->is_main_overlay = true; + } + if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) { + stl->storage->is_main_onion = true; + } + } + /* If found, don't need loop more. */ + if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) { + return; + } + } + } +} + void GPENCIL_cache_init(void *vedata) { GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; @@ -299,6 +354,7 @@ void GPENCIL_cache_init(void *vedata) ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); + const View3DCursor *cursor = &scene->cursor; /* Special handling for when active object is GP object (e.g. for draw mode) */ Object *obact = draw_ctx->obact; @@ -330,17 +386,11 @@ void GPENCIL_cache_init(void *vedata) stl->g_data->shgrps_edit_point = NULL; /* reset textures */ - stl->g_data->gpencil_blank_texture = NULL; stl->g_data->batch_buffer_stroke = NULL; stl->g_data->batch_buffer_fill = NULL; stl->g_data->batch_buffer_ctrlpoint = NULL; stl->g_data->batch_grid = NULL; - /* blank texture used if no texture defined for fill shader */ - float rect[1][1][4] = {{{0.0f}}}; - stl->g_data->gpencil_blank_texture = DRW_texture_create_2d( - 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect); - if (!stl->shgroups) { /* Alloc maximum size because count strokes is very slow and can be very complex due onion * skinning. @@ -380,10 +430,15 @@ void GPENCIL_cache_init(void *vedata) stl->storage->reset_cache = true; } stl->storage->is_playing = playing; + + /* Found if main overlay and onion switches are enabled in any screen. */ + gpencil_check_screen_switches(draw_ctx, stl); } else { stl->storage->is_playing = false; stl->storage->reset_cache = false; + stl->storage->is_main_overlay = false; + stl->storage->is_main_onion = false; } /* save render state */ stl->storage->is_render = DRW_state_is_image_render(); @@ -530,11 +585,42 @@ void GPENCIL_cache_init(void *vedata) } /* grid pass */ - if (v3d) { + if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) { psl->grid_pass = DRW_pass_create("GPencil Grid Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass); + + /* define grid orientation */ + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_VIEW: { + /* align always to view */ + invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat); + /* copy ob location */ + copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); + break; + } + case GP_LOCKAXIS_CURSOR: { + float scale[3] = {1.0f, 1.0f, 1.0f}; + loc_eul_size_to_mat4( + stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale); + break; + } + default: { + copy_m4_m4(stl->storage->grid_matrix, obact->obmat); + break; + } + } + + /* Move the origin to Object or Cursor */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(stl->storage->grid_matrix[3], cursor->location); + } + else { + copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); + } + DRW_shgroup_uniform_mat4( + stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix); } /* blend layers pass */ @@ -605,8 +691,6 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; - const View3DCursor *cursor = &scene->cursor; - float grid_matrix[4][4]; if (ob->type == OB_GPENCIL && ob->data) { bGPdata *gpd = (bGPdata *)ob->data; @@ -667,36 +751,7 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) { stl->g_data->batch_grid = gpencil_get_grid(ob); - - /* define grid orientation */ - switch (ts->gp_sculpt.lock_axis) { - case GP_LOCKAXIS_VIEW: { - /* align always to view */ - invert_m4_m4(grid_matrix, draw_ctx->rv3d->viewmat); - /* copy ob location */ - copy_v3_v3(grid_matrix[3], ob->obmat[3]); - break; - } - case GP_LOCKAXIS_CURSOR: { - float scale[3] = {1.0f, 1.0f, 1.0f}; - loc_eul_size_to_mat4(grid_matrix, cursor->location, cursor->rotation_euler, scale); - break; - } - default: { - copy_m4_m4(grid_matrix, ob->obmat); - break; - } - } - - /* Move the origin to Object or Cursor */ - if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { - copy_v3_v3(grid_matrix[3], cursor->location); - } - else { - copy_v3_v3(grid_matrix[3], ob->obmat[3]); - } - - DRW_shgroup_call_obmat(stl->g_data->shgrps_grid, stl->g_data->batch_grid, grid_matrix); + DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL); } } } @@ -781,8 +836,6 @@ void DRW_gpencil_free_runtime_data(void *ved) GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; /* free gpu data */ - DRW_TEXTURE_FREE_SAFE(stl->g_data->gpencil_blank_texture); - GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke); MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke); @@ -834,76 +887,13 @@ static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl, const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi)); - DRWShadingGroup *shgrp = init_shgrp; - DRWShadingGroup *from_shgrp = init_shgrp; - DRWShadingGroup *to_shgrp = init_shgrp; - int stencil_tot = 0; - bool do_last = true; - if (do_antialiasing) { MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); } - /* Loop all shading groups to separate by stencil groups. */ - while ((shgrp) && (shgrp != end_shgrp)) { - do_last = true; - /* Count number of groups using stencil. */ - if (DRW_shgroup_stencil_mask_get(shgrp) != 0) { - stencil_tot++; - } - - /* Draw stencil group and clear stencil bit. This is required because the number of - * shading groups can be greater than the limit of 255 stencil values. - * Only count as stencil if the shading group has an stencil value assigned. This reduces - * the number of clears because Dots, Fills and some Line strokes don't need stencil. - */ - if (stencil_tot == 255) { - DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : - psl->stroke_pass_2d, - from_shgrp, - to_shgrp); - /* Clear Stencil and prepare for next group. */ - if (do_antialiasing) { - GPU_framebuffer_clear_stencil(fbl->multisample_fb, 0x0); - } - else { - GPU_framebuffer_clear_stencil(fb, 0x0); - } - - /* Set new init group and reset. */ - do_last = false; - - shgrp = DRW_shgroup_get_next(shgrp); - if (shgrp) { - from_shgrp = to_shgrp = shgrp; - stencil_tot = 0; - if (shgrp != end_shgrp) { - continue; - } - else { - do_last = true; - break; - } - } - else { - /* No more groups. */ - break; - } - } - - /* Still below stencil group limit. */ - shgrp = DRW_shgroup_get_next(shgrp); - if (shgrp) { - to_shgrp = shgrp; - } - } - - /* Draw last pending groups. */ - if (do_last) { - DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d, - from_shgrp, - to_shgrp); - } + DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d, + init_shgrp, + end_shgrp); if (do_antialiasing) { MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 79bcffac512..36bc205f41a 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -143,6 +143,8 @@ typedef struct GPENCIL_Storage { bool is_playing; bool is_render; bool is_mat_preview; + bool is_main_overlay; + bool is_main_onion; bool background_ready; int is_xray; bool is_ontop; @@ -153,6 +155,7 @@ typedef struct GPENCIL_Storage { int do_select_outline; float select_color[4]; short multisamples; + float grid_matrix[4][4]; short framebuffer_flag; /* flag what framebuffer need to create */ @@ -265,9 +268,6 @@ typedef struct g_data { /* grid geometry */ GPUBatch *batch_grid; - /* textures */ - struct GPUTexture *gpencil_blank_texture; - /* runtime pointers texture */ struct GPUTexture *input_depth_tx; struct GPUTexture *input_color_tx; @@ -297,6 +297,9 @@ typedef enum eGPsession_Flag { } eGPsession_Flag; typedef struct GPENCIL_e_data { + /* textures */ + struct GPUTexture *gpencil_blank_texture; + /* general drawing shaders */ struct GPUShader *gpencil_fill_sh; struct GPUShader *gpencil_stroke_sh; @@ -386,10 +389,12 @@ typedef struct GpencilBatchCache { } GpencilBatchCache; /* general drawing functions */ -struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_Data *vedata, +struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data, + struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader, struct Object *ob, + float (*obmat)[4], struct bGPdata *gpd, struct bGPDlayer *gpl, struct bGPDstroke *gps, diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index aa0abe0341a..ba00fc18757 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -73,7 +73,7 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra * because there is no viewport. So we need to manually create one * NOTE : use 32 bit format for precision in render mode. */ - /* create multiframe framebuffer for AA */ + /* create multisample framebuffer for AA */ if (U.gpencil_multisamples > 0) { int rect_w = (int)viewport_size[0]; int rect_h = (int)viewport_size[1]; @@ -308,6 +308,9 @@ void GPENCIL_render_to_image(void *vedata, DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache); GPENCIL_cache_finish(vedata); + + DRW_render_instance_buffer_finish(); + GPENCIL_draw_scene(vedata); /* combined data */ diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl index a1cfb2ae4ae..f75322f90e2 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl @@ -1,4 +1,6 @@ +uniform mat4 gpModelMatrix; + in vec3 pos; in vec4 color; in float size; @@ -8,7 +10,7 @@ out float finalThickness; void main() { - gl_Position = point_object_to_ndc(pos); + gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); finalColor = color; finalThickness = size; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl index eb452f4c660..263dc570423 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl @@ -1,4 +1,6 @@ +uniform mat4 gpModelMatrix; + in vec3 pos; in vec4 color; in vec2 texCoord; @@ -8,7 +10,7 @@ out vec2 texCoord_interp; void main(void) { - gl_Position = point_object_to_ndc(pos); + gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); finalColor = color; texCoord_interp = texCoord; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl index ef8b361373f..87963c66858 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl @@ -6,6 +6,7 @@ uniform float pixfactor; uniform int viewport_xray; uniform int shading_type[2]; uniform vec4 wire_color; +uniform mat4 gpModelMatrix; in vec3 pos; in vec4 color; @@ -30,8 +31,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor); void main() { - gl_Position = point_object_to_ndc(pos); - finalprev_pos = point_object_to_ndc(prev_pos); + gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); + finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz); finalColor = color; if (keep_size == TRUE) { diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl index c7089f357f9..582b9a7f249 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl @@ -6,6 +6,7 @@ uniform float pixfactor; uniform int viewport_xray; uniform int shading_type[2]; uniform vec4 wire_color; +uniform mat4 gpModelMatrix; in vec3 pos; in vec4 color; @@ -28,7 +29,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor); void main(void) { - gl_Position = point_object_to_ndc(pos); + gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); finalColor = color; if (keep_size == TRUE) { diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c index 927956dad19..f1d008c29c7 100644 --- a/source/blender/draw/engines/select/select_draw_utils.c +++ b/source/blender/draw/engines/select/select_draw_utils.c @@ -49,8 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3]) BoundBox *bb; BMEditMesh *em = BKE_editmesh_from_object(obj); if (em) { - /* Use Object Texture Space. */ - bb = BKE_mesh_texspace_get(em->mesh_eval_cage, NULL, NULL, NULL); + bb = BKE_editmesh_cage_boundbox_get(em); } else { bb = BKE_object_boundbox_get(obj); @@ -63,10 +62,10 @@ short select_id_get_object_select_mode(Scene *scene, Object *ob) { short r_select_mode = 0; if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) { - /* In order to sample flat colors for vertex weights / texturepaint / vertexpaint + /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint * we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up * a shgroup with select_id_flat. - * Note this is not working correctly for vertexpaint (yet), but has been discussed + * Note this is not working correctly for vertex-paint (yet), but has been discussed * in T66645 and there is a solution by @mano-wii in P1032. * So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */ Mesh *me_orig = DEG_get_original_object(ob)->data; @@ -129,7 +128,11 @@ static void draw_select_id_edit_mesh(SELECTID_StorageList *stl, } else { if (ob->dt >= OB_SOLID) { +#ifdef USE_CAGE_OCCLUSION + struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); +#else struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me); +#endif DRWShadingGroup *face_shgrp = stl->g_data->shgrp_face_unif; DRW_shgroup_call_no_cull(face_shgrp, geom_faces, ob); } diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 5dc20a589f0..abfa57dd218 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -252,7 +252,11 @@ static void select_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); } else if (ob->dt >= OB_SOLID) { +#ifdef USE_CAGE_OCCLUSION + struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); +#else struct GPUBatch *geom_faces = DRW_mesh_batch_cache_get_surface(me); +#endif DRW_shgroup_call_obmat(stl->g_data->shgrp_depth_only, geom_faces, ob->obmat); } diff --git a/source/blender/draw/engines/select/select_private.h b/source/blender/draw/engines/select/select_private.h index 642cd6ffc56..1e99a49252e 100644 --- a/source/blender/draw/engines/select/select_private.h +++ b/source/blender/draw/engines/select/select_private.h @@ -23,6 +23,8 @@ #ifndef __SELECT_PRIVATE_H__ #define __SELECT_PRIVATE_H__ +#define USE_CAGE_OCCLUSION + #include "DRW_render.h" /* GPUViewport.storage diff --git a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl index a6d7c4b393b..3ac220aee59 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl @@ -1,5 +1,5 @@ vec3 background_color(WorldData world_data, float y) { return mix(world_data.background_color_low, world_data.background_color_high, y).xyz + - bayer_dither_noise(); + (world_data.background_dither_factor * bayer_dither_noise()); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 16df56b393a..f60eca24821 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -16,5 +16,6 @@ struct WorldData { float background_alpha; float curvature_ridge; float curvature_valley; - int pad[3]; + float background_dither_factor; + int pad[2]; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl index 505b4822ad6..abd8c1f6579 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl @@ -1,5 +1,6 @@ -uniform int object_id = 0; + layout(location = 0) out uint objectId; + uniform float ImageTransparencyCutoff = 0.1; #ifdef V3D_SHADING_TEXTURE_COLOR uniform sampler2D image; @@ -10,11 +11,10 @@ in vec2 uv_interp; void main() { #ifdef V3D_SHADING_TEXTURE_COLOR - vec4 diffuse_color = texture(image, uv_interp); - if (diffuse_color.a < ImageTransparencyCutoff) { + if (texture(image, uv_interp).a < ImageTransparencyCutoff) { discard; } #endif - objectId = uint(object_id); + objectId = uint(resource_id + 1) & 0xFFu; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index 3333dfeff38..f799ce41cb2 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -8,8 +8,7 @@ uniform float alpha = 0.5; uniform vec2 invertedViewportSize; uniform vec4 viewvecs[3]; -uniform vec3 materialDiffuseColor; -uniform vec3 materialSpecularColor; +uniform vec4 materialColorAndMetal; uniform float materialRoughness; uniform float shadowMultiplier = 0.5; @@ -42,17 +41,17 @@ layout(location = 1) out void main() { - vec4 diffuse_color; + vec4 base_color; #if defined(V3D_SHADING_TEXTURE_COLOR) - diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); - if (diffuse_color.a < ImageTransparencyCutoff) { + base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); + if (base_color.a < ImageTransparencyCutoff) { discard; } #elif defined(V3D_SHADING_VERTEX_COLOR) - diffuse_color = vec4(vertexColor, 1.0); + base_color.rgb = vertexColor; #else - diffuse_color = vec4(materialDiffuseColor, 1.0); + base_color.rgb = materialColorAndMetal.rgb; #endif /* V3D_SHADING_TEXTURE_COLOR */ vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; @@ -64,7 +63,7 @@ void main() /* -------- SHADING --------- */ #ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = diffuse_color.rgb; + vec3 shaded_color = base_color.rgb; #elif defined(V3D_LIGHTING_MATCAP) bool flipped = world_data.matcap_orientation != 0; @@ -75,11 +74,20 @@ void main() # else vec3 matcap_specular = vec3(0.0); # endif - vec3 shaded_color = matcap_diffuse * diffuse_color.rgb + matcap_specular; + vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular; #elif defined(V3D_LIGHTING_STUDIO) +# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT + float metallic = materialColorAndMetal.a; + vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic); + vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic); +# else + vec3 specular_color = vec3(0.0); + vec3 diffuse_color = base_color.rgb; +# endif + vec3 shaded_color = get_world_lighting( - world_data, diffuse_color.rgb, materialSpecularColor, materialRoughness, nor, I_vs); + world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs); #endif #ifdef V3D_SHADING_SHADOW diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index c673b2484de..b5f95f2dcf8 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -1,7 +1,5 @@ -uniform int object_id = 0; -uniform vec3 materialDiffuseColor; -uniform float materialMetallic; +uniform vec4 materialColorAndMetal; uniform float materialRoughness; uniform sampler2D image; @@ -48,7 +46,7 @@ void main() # elif defined(V3D_SHADING_VERTEX_COLOR) color.rgb = vertexColor; # else - color.rgb = materialDiffuseColor; + color.rgb = materialColorAndMetal.rgb; # endif # ifdef V3D_LIGHTING_MATCAP @@ -56,7 +54,7 @@ void main() metallic = float(gl_FrontFacing); roughness = 0.0; # else - metallic = materialMetallic; + metallic = materialColorAndMetal.a; roughness = materialRoughness; # endif @@ -64,7 +62,7 @@ void main() /* Add some variation to the hairs to avoid uniform look. */ float hair_variation = hair_rand * 0.1; color = clamp(color - hair_variation, 0.0, 1.0); - metallic = clamp(materialMetallic - hair_variation, 0.0, 1.0); + metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0); roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0); # endif @@ -73,7 +71,7 @@ void main() #endif /* MATDATA_PASS_ENABLED */ #ifdef OBJECT_ID_PASS_ENABLED - objectId = uint(object_id); + objectId = uint(resource_id + 1) & 0xFFu; #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 7eb12dbdeb9..04dd9ab85bb 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -25,6 +25,10 @@ out vec2 uv_interp; out vec3 vertexColor; #endif +#ifdef OBJECT_ID_PASS_ENABLED +RESOURCE_ID_VARYING +#endif + /* From http://libnoise.sourceforge.net/noisegen/index.html */ float integer_noise(int n) { @@ -91,12 +95,18 @@ void main() #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED - normal_viewport = normal_object_to_view(nor); # ifndef HAIR_SHADER + normal_viewport = normal_object_to_view(nor); normal_viewport = normalize(normal_viewport); +# else + normal_viewport = normal_world_to_view(nor); # endif #endif +#ifdef OBJECT_ID_PASS_ENABLED + PASS_RESOURCE_ID +#endif + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 4a9b0ae3b7d..c38d8fe06bc 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -1,6 +1,4 @@ -uniform vec3 OrcoTexCoFactors[2]; - uniform sampler2D depthBuffer; uniform sampler3D densityTexture; @@ -215,14 +213,14 @@ void main() vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0); vs_ray_dir /= abs(vs_ray_dir.z); - /* TODO(fclem) Precompute the matrix/ */ - vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0; - ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir; + vec3 ls_ray_dir = point_view_to_object(vs_ray_ori + vs_ray_dir); vec3 ls_ray_ori = point_view_to_object(vs_ray_ori); vec3 ls_ray_end = point_view_to_object(vs_ray_end); - ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0; - ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0; + ls_ray_dir = (OrcoTexCoFactors[0].xyz + ls_ray_dir * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0; + ls_ray_ori = (OrcoTexCoFactors[0].xyz + ls_ray_ori * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0; + ls_ray_end = (OrcoTexCoFactors[0].xyz + ls_ray_end * OrcoTexCoFactors[1].xyz) * 2.0 - 1.0; + ls_ray_dir -= ls_ray_ori; /* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl index 6f0bb56fafd..3542a1a91fc 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl @@ -1,10 +1,11 @@ -uniform vec3 OrcoTexCoFactors[2]; uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ in vec3 pos; +RESOURCE_ID_VARYING + #ifdef VOLUME_SLICE in vec3 uvs; @@ -27,6 +28,8 @@ void main() #else vec3 final_pos = pos; #endif - final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1]; + final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0].xyz) / OrcoTexCoFactors[1].xyz; gl_Position = point_object_to_ndc(final_pos); + + PASS_RESOURCE_ID } diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 743a1fc42b6..3e63f05ca64 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -111,6 +111,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) zero_v3(wd->background_color_low); zero_v3(wd->background_color_high); } + wd->background_dither_factor = workbench_background_dither_factor(wpd); studiolight_update_world(wpd, wpd->studio_light, wd); diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 262ea7110a4..2e8b952f234 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -78,12 +78,10 @@ static struct { struct GPUTexture *object_id_tx; /* ref only, not alloced */ struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *metallic_buffer_tx; /* ref only, not alloced */ struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ SceneDisplay display; /* world light direction for shadows */ - int next_object_id; struct GPUUniformBuffer *sampling_ubo; struct GPUTexture *jitter_tx; @@ -147,6 +145,7 @@ static char *workbench_build_prepass_frag(void) { DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl); @@ -330,7 +329,6 @@ static struct GPUTexture *create_jitter_texture(int num_samples) static void workbench_init_object_data(DrawData *dd) { WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; - data->object_id = ((e_data.next_object_id++) & 0xff) + 1; data->shadow_bbox_dirty = true; } @@ -379,11 +377,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) workbench_effect_info_init(stl->effects); } - if (!e_data.next_object_id) { + if (!e_data.shadow_pass_sh) { WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache)); memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache)); - e_data.next_object_id = 1; #ifdef DEBUG_SHADOW_VOLUME const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; #else @@ -868,18 +865,11 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; WORKBENCH_MaterialData *material; - WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( - &ob->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_ObjectData), - &workbench_init_object_data, - NULL); WORKBENCH_MaterialData material_template; const bool is_ghost = (ob->dtx & OB_DRAWXRAY); /* Solid */ workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; material_template.iuser = iuser; @@ -899,8 +889,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedat shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); workbench_material_copy(material, &material_template); DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1); - workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, true, interp); + workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, interp); BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material); } return material; @@ -943,8 +932,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass, shader); DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, true, interp); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, interp); } } } @@ -956,7 +944,8 @@ static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); WORKBENCH_MaterialData *material; /* Force workbench to render active object textured when in texture paint mode */ diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c index 06442060623..772d859392b 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c @@ -139,7 +139,7 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata) /* reset complete drawing when navigating. */ if (effect_info->jitter_index != 0) { - if (rv3d && rv3d->rflag & RV3D_NAVIGATING) { + if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) { effect_info->jitter_index = 0; } } diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 1cbc60ef858..d731b167c06 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -63,8 +63,6 @@ static struct { struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */ struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ - - int next_object_id; } e_data = {{{{NULL}}}}; /* Shaders */ @@ -98,6 +96,18 @@ static char *workbench_build_forward_vert(bool is_hair) return str; } +static char *workbench_build_forward_outline_frag(void) +{ + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl); + + char *str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + static char *workbench_build_forward_transparent_accum_frag(void) { DynStr *ds = BLI_dynstr_new(); @@ -129,12 +139,6 @@ static char *workbench_build_forward_composite_frag(void) return str; } -static void workbench_init_object_data(DrawData *dd) -{ - WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; - data->object_id = ((e_data.next_object_id++) & 0xff) + 1; -} - WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_Data *vedata, Object *ob, Material *mat, @@ -149,18 +153,11 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; WORKBENCH_MaterialData *material; - WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( - &ob->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_ObjectData), - &workbench_init_object_data, - NULL); WORKBENCH_MaterialData material_template; DRWShadingGroup *grp; /* Solid */ workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1; material_template.color_type = color_type; material_template.ima = ima; material_template.iuser = iuser; @@ -205,7 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); } - workbench_material_shgroup_uniform(wpd, grp, material, ob, false, false, interp); + workbench_material_shgroup_uniform(wpd, grp, material, ob, false, interp); material->shgrp = grp; /* Depth */ @@ -219,8 +216,6 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh, psl->object_outline_pass); } - material->object_id = engine_object_data->object_id; - DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1); if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES); } @@ -292,26 +287,30 @@ void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUSh char *defines_texture = workbench_material_build_defines(wpd, true, false, false); char *defines_hair = workbench_material_build_defines(wpd, false, true, false); char *forward_vert = workbench_build_forward_vert(false); + char *forward_frag = workbench_build_forward_outline_frag(); char *forward_hair_vert = workbench_build_forward_vert(true); + const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n"; + sh_data->object_outline_sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, NULL}, + .frag = (const char *[]){forward_frag, NULL}, + .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL}, }); sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_texture, NULL}, + .frag = (const char *[]){forward_frag, NULL}, + .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL}, }); sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL}, - .frag = (const char *[]){datatoc_workbench_forward_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_hair, NULL}, + .frag = (const char *[]){forward_frag, NULL}, + .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL}, }); MEM_freeN(forward_hair_vert); MEM_freeN(forward_vert); + MEM_freeN(forward_frag); MEM_freeN(defines); MEM_freeN(defines_texture); MEM_freeN(defines_hair); @@ -527,7 +526,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O DRWShadingGroup *shgrp = DRW_shgroup_hair_create( ob, psys, md, psl->transparent_accum_pass, shader); DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp); + workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, interp); DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3); /* Hairs have lots of layer and can rapidly become the most prominent surface. * So lower their alpha artificially. */ @@ -551,7 +550,6 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; shgrp = DRW_shgroup_hair_create( ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh); - DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); } } } @@ -562,7 +560,8 @@ static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data * const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); WORKBENCH_MaterialData *material; /* Force workbench to render active object textured when in texture paint mode */ @@ -637,7 +636,8 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) WORKBENCH_MaterialData *material; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index e050877187e..0f9551a8cc9 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -44,20 +44,15 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, WORKBENCH_MaterialData *data, int color_type) { - copy_v3_fl3(data->diffuse_color, 0.8f, 0.8f, 0.8f); - copy_v3_v3(data->base_color, data->diffuse_color); - copy_v3_fl3(data->specular_color, 0.05f, 0.05f, 0.05f); /* Dielectric: 5% reflective. */ data->metallic = 0.0f; data->roughness = 0.632455532f; /* sqrtf(0.4f); */ data->alpha = wpd->shading.xray_alpha; if (color_type == V3D_SHADING_SINGLE_COLOR) { - copy_v3_v3(data->diffuse_color, wpd->shading.single_color); - copy_v3_v3(data->base_color, data->diffuse_color); + copy_v3_v3(data->base_color, wpd->shading.single_color); } else if (color_type == V3D_SHADING_ERROR_COLOR) { - copy_v3_fl3(data->diffuse_color, 0.8, 0.0, 0.8); - copy_v3_v3(data->base_color, data->diffuse_color); + copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8); } else if (color_type == V3D_SHADING_RANDOM_COLOR) { uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); @@ -67,30 +62,24 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, float hue = BLI_hash_int_01(hash); float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; - hsv_to_rgb_v(hsv, data->diffuse_color); - copy_v3_v3(data->base_color, data->diffuse_color); + hsv_to_rgb_v(hsv, data->base_color); } else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) { - copy_v3_v3(data->diffuse_color, ob->color); - copy_v3_v3(data->base_color, data->diffuse_color); data->alpha *= ob->color[3]; + copy_v3_v3(data->base_color, ob->color); } else { /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */ if (mat) { data->alpha *= mat->a; + copy_v3_v3(data->base_color, &mat->r); if (workbench_is_specular_highlight_enabled(wpd)) { - copy_v3_v3(data->base_color, &mat->r); - mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic); - mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic); - add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic)); data->metallic = mat->metallic; data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ } - else { - copy_v3_v3(data->base_color, &mat->r); - copy_v3_v3(data->diffuse_color, &mat->r); - } + } + else { + copy_v3_fl(data->base_color, 0.8f); } } } @@ -160,34 +149,40 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, return str; } -uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost) +uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost) { - uint input[4]; - uint result; - float *color = material_template->diffuse_color; - input[0] = (uint)(color[0] * 512); - input[1] = (uint)(color[1] * 512); - input[2] = (uint)(color[2] * 512); - input[3] = material_template->object_id; - result = BLI_ghashutil_uinthash_v4_murmur(input); - - color = material_template->specular_color; - input[0] = (uint)(color[0] * 512); - input[1] = (uint)(color[1] * 512); - input[2] = (uint)(color[2] * 512); - input[3] = (uint)(material_template->roughness * 512); - result += BLI_ghashutil_uinthash_v4_murmur(input); - - result += BLI_ghashutil_uinthash((uint)(material_template->alpha * 512)); - result += BLI_ghashutil_uinthash((uint)is_ghost); - result += BLI_ghashutil_uinthash(material_template->color_type); - - /* add texture reference */ - if (material_template->ima) { - result += BLI_ghashutil_inthash_p_murmur(material_template->ima); - } - - return result; + union { + struct { + /* WHATCH: Keep in sync with View3DShading.color_type max value. */ + uchar color_type; + uchar diff_r; + uchar diff_g; + uchar diff_b; + + uchar alpha; + uchar ghost; + uchar metal; + uchar roughness; + + void *ima; + }; + /* HACK to ensure input is 4 uint long. */ + uint a[4]; + } input = {.color_type = (uchar)(mat->color_type), + .diff_r = (uchar)(mat->base_color[0] * 0xFF), + .diff_g = (uchar)(mat->base_color[1] * 0xFF), + .diff_b = (uchar)(mat->base_color[2] * 0xFF), + + .alpha = (uint)(mat->alpha * 0xFF), + .ghost = (uchar)is_ghost, + .metal = (uchar)(mat->metallic * 0xFF), + .roughness = (uchar)(mat->roughness * 0xFF), + + .ima = mat->ima}; + + BLI_assert(sizeof(input) == sizeof(uint) * 4); + + return BLI_ghashutil_uinthash_v4((uint *)&input); } int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) @@ -266,8 +261,8 @@ int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, int color_type = wpd->shading.color_type; const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - if ((color_type == V3D_SHADING_TEXTURE_COLOR && (ima == NULL || use_sculpt_pbvh)) || - (ob->dt < OB_TEXTURE)) { + if ((color_type == V3D_SHADING_TEXTURE_COLOR) && + (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) { color_type = V3D_SHADING_MATERIAL_COLOR; } if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) { @@ -315,35 +310,28 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob, - const bool use_metallic, const bool deferred, const int interp) { - if (!deferred || workbench_is_matdata_pass_enabled(wpd)) { - if (workbench_material_determine_color_type(wpd, material->ima, ob, false) == - V3D_SHADING_TEXTURE_COLOR) { - GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "image", tex); - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); - } - else { - DRW_shgroup_uniform_vec3(grp, - "materialDiffuseColor", - (use_metallic) ? material->base_color : material->diffuse_color, - 1); - } + if (!(!deferred || workbench_is_matdata_pass_enabled(wpd))) { + return; + } - if (workbench_is_specular_highlight_enabled(wpd)) { - if (use_metallic) { - DRW_shgroup_uniform_float(grp, "materialMetallic", &material->metallic, 1); - } - else { - DRW_shgroup_uniform_vec3(grp, "materialSpecularColor", material->specular_color, 1); - } - DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); - } + const bool use_highlight = workbench_is_specular_highlight_enabled(wpd); + const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type( + wpd, material->ima, ob, false)); + if (use_texture) { + GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); + DRW_shgroup_uniform_texture(grp, "image", tex); + DRW_shgroup_uniform_bool_copy( + grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); + } + + DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1); + + if (use_highlight) { + DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); } if (WORLD_CLIPPING_ENABLED(wpd)) { @@ -354,10 +342,7 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material) { - dest_material->object_id = source_material->object_id; copy_v3_v3(dest_material->base_color, source_material->base_color); - copy_v3_v3(dest_material->diffuse_color, source_material->diffuse_color); - copy_v3_v3(dest_material->specular_color, source_material->specular_color); dest_material->metallic = source_material->metallic; dest_material->roughness = source_material->roughness; dest_material->ima = source_material->ima; diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index d880d5d58b5..595b92d19d0 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -75,7 +75,8 @@ V3D_SHADING_VERTEX_COLOR)) #define IS_NAVIGATING(wpd) \ - ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING)) + ((DRW_context_state_get()->rv3d) && \ + (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING))) #define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) @@ -193,7 +194,8 @@ typedef struct WORKBENCH_UBO_World { float background_alpha; float curvature_ridge; float curvature_valley; - int pad[3]; + float background_dither_factor; + int pad[2]; } WORKBENCH_UBO_World; BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) @@ -281,13 +283,8 @@ typedef struct WORKBENCH_EffectInfo { } WORKBENCH_EffectInfo; typedef struct WORKBENCH_MaterialData { - float base_color[3]; - float diffuse_color[3]; - float specular_color[3]; - float alpha; - float metallic; - float roughness; - int object_id; + float base_color[3], metallic; + float roughness, alpha; int color_type; int interp; Image *ima; @@ -308,8 +305,6 @@ typedef struct WORKBENCH_ObjectData { float shadow_min[3], shadow_max[3]; BoundBox shadow_bbox; bool shadow_bbox_dirty; - - int object_id; } WORKBENCH_ObjectData; /* inline helper functions */ @@ -412,6 +407,13 @@ BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_Priv return result; } +BLI_INLINE bool workbench_background_dither_factor(const WORKBENCH_PrivateData *wpd) +{ + /* Only apply dithering when rendering on a RGBA8 texture. + * The dithering will remove banding when using a gradient as background */ + return workbench_color_texture_format(wpd) == GPU_RGBA8; +} + /* workbench_deferred.c */ void workbench_deferred_engine_init(WORKBENCH_Data *vedata); void workbench_deferred_engine_free(void); @@ -500,7 +502,6 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob, - const bool use_metallic, const bool deferred, const int interp); void workbench_material_copy(WORKBENCH_MaterialData *dest_material, diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index ac27ff0b736..941a6741998 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -131,7 +131,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd, static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], - float r_line[2]) + float r_line[4]) { sub_v2_v2v2(r_line, v2, v1); /* Find orthogonal vector. */ diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 7ae9d90daff..23f0898c138 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -27,6 +27,7 @@ #include "BLI_rand.h" #include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" @@ -45,8 +46,6 @@ enum { static struct { struct GPUShader *volume_sh[VOLUME_SH_MAX]; struct GPUShader *volume_coba_sh; - struct GPUShader *volume_slice_sh; - struct GPUShader *volume_slice_coba_sh; struct GPUTexture *dummy_tex; struct GPUTexture *dummy_coba_tex; } e_data = {{NULL}}; @@ -54,6 +53,7 @@ static struct { extern char datatoc_workbench_volume_vert_glsl[]; extern char datatoc_workbench_volume_frag_glsl[]; extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) { @@ -78,12 +78,16 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) char *defines = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); + char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_gpu_shader_common_obinfos_lib_glsl); + e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl, NULL, datatoc_workbench_volume_frag_glsl, - datatoc_common_view_lib_glsl, + libs, defines); + MEM_freeN(libs); MEM_freeN(defines); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 4b170e8a2ea..7bcb048017e 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -75,15 +75,13 @@ struct RenderEngineType; struct bContext; struct rcti; +typedef struct DRWCallBuffer DRWCallBuffer; typedef struct DRWInterface DRWInterface; typedef struct DRWPass DRWPass; typedef struct DRWShadingGroup DRWShadingGroup; typedef struct DRWUniform DRWUniform; typedef struct DRWView DRWView; -/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */ -typedef struct DRWCallBuffer DRWCallBuffer; - /* TODO Put it somewhere else? */ typedef struct BoundSphere { float center[3], radius; @@ -415,35 +413,29 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4], struct GPUBatch *geom, - uint v_sta, - uint v_ct, bool bypass_culling, void *user_data); /* If ob is NULL, unit modelmatrix is assumed and culling is bypassed. */ -#define DRW_shgroup_call(shgrp, geom, ob) \ - DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, NULL) +#define DRW_shgroup_call(shgrp, geom, ob) DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, NULL) /* Same as DRW_shgroup_call but override the obmat. Not culled. */ #define DRW_shgroup_call_obmat(shgrp, geom, obmat) \ - DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, 0, 0, false, NULL) + DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, false, NULL) /* TODO(fclem) remove this when we have DRWView */ /* user_data is used by DRWCallVisibilityFn defined in DRWView. */ #define DRW_shgroup_call_with_callback(shgrp, geom, ob, user_data) \ - DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, false, user_data) + DRW_shgroup_call_ex(shgrp, ob, NULL, geom, false, user_data) /* Same as DRW_shgroup_call but bypass culling even if ob is not NULL. */ #define DRW_shgroup_call_no_cull(shgrp, geom, ob) \ - DRW_shgroup_call_ex(shgrp, ob, NULL, geom, 0, 0, true, NULL) + DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL) -/* Only draw a certain range of geom. */ -#define DRW_shgroup_call_range(shgrp, geom, ob, v_sta, v_ct) \ - DRW_shgroup_call_ex(shgrp, ob, NULL, geom, v_sta, v_ct, false, NULL) - -/* Same as DRW_shgroup_call_range but override the obmat. Special for gpencil. */ -#define DRW_shgroup_call_range_obmat(shgrp, geom, obmat, v_sta, v_ct) \ - DRW_shgroup_call_ex(shgrp, NULL, obmat, geom, v_sta, v_ct, false, NULL) +void DRW_shgroup_call_range(DRWShadingGroup *shgroup, + struct GPUBatch *geom, + uint v_sta, + uint v_ct); void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct); void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct); @@ -480,6 +472,16 @@ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); +/* Issue a clear command. */ +void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, + eGPUFrameBufferBits channels, + uchar r, + uchar g, + uchar b, + uchar a, + float depth, + uchar stencil); + void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); @@ -536,17 +538,17 @@ void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]); /* Store value instead of referencing it. */ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value); +void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgrp, const char *name, const int *value); +void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgrp, const char *name, const int *value); +void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgrp, const char *name, const int *value); void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value); void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value); void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value); +void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value); bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); -/* TODO: workaround functions waiting for the clearing operation to be available inside the - * shgroups. */ -DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup); -uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup); - /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); /* TODO Replace with passes inheritance. */ diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c index 72459309133..7e0110cbb99 100644 --- a/source/blender/draw/intern/draw_anim_viz.c +++ b/source/blender/draw/intern/draw_anim_viz.c @@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl, DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1); } /* Only draw the required range. */ - DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len); + DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), start_index, len); } /* Draw points. */ @@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl, DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1); } /* Only draw the required range. */ - DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len); + DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), start_index, len); /* Draw frame numbers at each framestep value */ bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0; @@ -289,10 +289,9 @@ static void MPATH_cache_populate(void *vedata, Object *ob) } } } - else { - if (ob->mpath) { - MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath); - } + + if (ob->mpath) { + MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath); } } diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 865cfea14e3..5cd6a4a1286 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -60,7 +60,6 @@ static struct { Object *ob; /* Reset when changing current_armature */ DRWCallBuffer *bone_octahedral_solid; - DRWCallBuffer *bone_octahedral_wire; DRWCallBuffer *bone_octahedral_outline; DRWCallBuffer *bone_box_solid; DRWCallBuffer *bone_box_wire; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 06ed661ad8e..b085d402e81 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -53,7 +53,6 @@ static struct DRWShapeCache { GPUBatch *drw_cursor; GPUBatch *drw_cursor_only_circle; GPUBatch *drw_fullscreen_quad; - GPUBatch *drw_fullscreen_quad_texcoord; GPUBatch *drw_quad; GPUBatch *drw_quad_wires; GPUBatch *drw_grid; @@ -72,8 +71,6 @@ static struct DRWShapeCache { GPUBatch *drw_empty_capsule_body; GPUBatch *drw_empty_capsule_cap; GPUBatch *drw_empty_cone; - GPUBatch *drw_arrows; - GPUBatch *drw_axis_names; GPUBatch *drw_image_plane; GPUBatch *drw_image_plane_wire; GPUBatch *drw_field_wind; @@ -99,7 +96,6 @@ static struct DRWShapeCache { GPUBatch *drw_bone_octahedral_wire; GPUBatch *drw_bone_box; GPUBatch *drw_bone_box_wire; - GPUBatch *drw_bone_wire_wire; GPUBatch *drw_bone_envelope; GPUBatch *drw_bone_envelope_outline; GPUBatch *drw_bone_point; @@ -111,7 +107,6 @@ static struct DRWShapeCache { GPUBatch *drw_camera; GPUBatch *drw_camera_frame; GPUBatch *drw_camera_tria; - GPUBatch *drw_camera_focus; GPUBatch *drw_particle_cross; GPUBatch *drw_particle_circle; GPUBatch *drw_particle_axis; @@ -347,6 +342,7 @@ GPUBatch *DRW_cache_fullscreen_quad_get(void) attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); GPU_vertformat_alias_add(&format, "texCoord"); + GPU_vertformat_alias_add(&format, "orco"); /* Fix driver bug (see T70004) */ } GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 75b8d820884..b1eab3c73ae 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -48,6 +48,9 @@ typedef struct DRW_MeshCDMask { uint32_t vcol : 8; uint32_t orco : 1; uint32_t tan_orco : 1; + /** Edit uv layer is from the base edit mesh as + * modifiers could remove it. (see T68857) */ + uint32_t edit_uv : 1; } DRW_MeshCDMask; typedef enum eMRIterType { @@ -78,7 +81,7 @@ BLI_INLINE int mesh_render_mat_len_get(Mesh *me) typedef struct MeshBufferCache { /* Every VBO below contains at least enough - * data for every loops in the mesh (except fdots). + * data for every loops in the mesh (except fdots and skin roots). * For some VBOs, it extends to (in this exact order) : * loops + loose_edges*2 + loose_verts */ struct { @@ -101,6 +104,7 @@ typedef struct MeshBufferCache { GPUVertBuf *fdots_uv; // GPUVertBuf *fdots_edit_data; /* inside fdots_nor for now. */ GPUVertBuf *fdots_edituv_data; + GPUVertBuf *skin_roots; /* Selection */ GPUVertBuf *vert_idx; /* extend */ GPUVertBuf *edge_idx; /* extend */ @@ -154,6 +158,7 @@ typedef enum DRWBatchFlag { MBC_WIRE_LOOPS = (1 << 24), MBC_WIRE_LOOPS_UVS = (1 << 25), MBC_SURF_PER_MAT = (1 << 26), + MBC_SKIN_ROOTS = (1 << 27), } DRWBatchFlag; #define MBC_EDITUV \ @@ -182,6 +187,7 @@ typedef struct MeshBatchCache { GPUBatch *edit_lnor; GPUBatch *edit_fdots; GPUBatch *edit_mesh_analysis; + GPUBatch *edit_skin_roots; /* Edit UVs */ GPUBatch *edituv_faces_stretch_area; GPUBatch *edituv_faces_stretch_angle; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index d7971a9e7db..fb439016a87 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -949,10 +949,8 @@ BLI_INLINE void lines_adjacency_triangle( GPUIndexBufBuilder *elb = &data->elb; /* Iter around the triangle's edges. */ for (int e = 0; e < 3; e++) { - uint tmp = v1; - v1 = v2, v2 = v3, v3 = tmp; - tmp = l1; - l1 = l2, l2 = l3, l3 = tmp; + SHIFT3(uint, v3, v2, v1); + SHIFT3(uint, l3, l2, l1); bool inv_indices = (v2 > v3); void **pval; @@ -1185,8 +1183,7 @@ static void extract_edituv_lines_loop_mesh(const MeshRenderData *mr, { int loopend = mpoly->totloop + mpoly->loopstart - 1; int loop_next_idx = (loop_idx == loopend) ? mpoly->loopstart : (loop_idx + 1); - const bool real_edge = (mr->extract_type == MR_EXTRACT_MAPPED && - mr->e_origindex[mloop->e] != ORIGINDEX_NONE); + const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[mloop->e] != ORIGINDEX_NONE); edituv_edge_add(data, (mpoly->flag & ME_HIDE) != 0 || !real_edge, (mpoly->flag & ME_FACE_SEL) != 0, @@ -1604,6 +1601,14 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf) CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t uv_layers = mr->cache->cd_used.uv; + /* HACK to fix T68857 */ + if (mr->extract_type == MR_EXTRACT_BMESH && mr->cache->cd_used.edit_uv == 1) { + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + uv_layers |= (1 << layer); + } + } + for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME]; @@ -3855,6 +3860,69 @@ static const MeshExtract extract_fdots_edituv_data = { /** \} */ /* ---------------------------------------------------------------------- */ +/** \name Extract Skin Modifier Roots + * \{ */ + +typedef struct SkinRootData { + float size; + float local_pos[3]; +} SkinRootData; + +static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf) +{ + /* Exclusively for edit mode. */ + BLI_assert(mr->bm); + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + GPUVertBuf *vbo = buf; + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->bm->totvert); + + SkinRootData *vbo_data = (SkinRootData *)vbo->data; + + int root_len = 0; + int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN); + + BMIter iter; + BMVert *eve; + BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) { + const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs); + if (vs->flag & MVERT_SKIN_ROOT) { + vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f; + copy_v3_v3(vbo_data->local_pos, eve->co); + vbo_data++; + root_len++; + } + } + + /* It's really unlikely that all verts will be roots. Resize to avoid loosing VRAM. */ + GPU_vertbuf_data_len_set(vbo, root_len); + + return NULL; +} + +static const MeshExtract extract_skin_roots = { + extract_skin_roots_init, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + false, +}; + +/** \} */ + +/* ---------------------------------------------------------------------- */ /** \name Extract Selection Index * \{ */ @@ -4286,6 +4354,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, TEST_ASSIGN(VBO, vbo, edge_idx); TEST_ASSIGN(VBO, vbo, vert_idx); TEST_ASSIGN(VBO, vbo, fdot_idx); + TEST_ASSIGN(VBO, vbo, skin_roots); TEST_ASSIGN(IBO, ibo, tris); TEST_ASSIGN(IBO, ibo, lines); @@ -4329,7 +4398,8 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, if (mbc.buf.name) { \ extract_task_create( \ task_pool, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \ - } + } \ + ((void)0) EXTRACT(vbo, pos_nor); EXTRACT(vbo, lnor); @@ -4352,6 +4422,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, EXTRACT(vbo, edge_idx); EXTRACT(vbo, vert_idx); EXTRACT(vbo, fdot_idx); + EXTRACT(vbo, skin_roots); EXTRACT(ibo, tris); EXTRACT(ibo, lines); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 970b6053cf9..8cb318bd0bb 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -142,6 +142,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edit_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_vnors(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(struct Mesh *me); /* edit-mesh selection */ struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me); @@ -151,8 +152,8 @@ struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me); /* edit-mesh UV editor */ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Mesh *me, - float *tot_area, - float *tot_uv_area); + float **tot_area, + float **tot_uv_area); struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Mesh *me); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 56b2b20cc05..ca185fa7d7d 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -90,9 +90,15 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a) *((uint32_t *)a) = 0; } +static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used) +{ + cd_used->edit_uv = 1; +} + static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -102,7 +108,8 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { @@ -112,7 +119,8 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL); if (layer != -1) { @@ -124,7 +132,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, struct GPUMaterial **gpumat_array, int gpumat_array_len) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; /* See: DM_vertex_attributes_from_gpu for similar logic */ DRW_MeshCDMask cd_used; @@ -227,7 +236,8 @@ static void mesh_cd_extract_auto_layers_names_and_srgb(Mesh *me, int **r_auto_layers_srgb, int *r_auto_layers_len) { - const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; + const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + const CustomData *cd_ldata = &me_final->ldata; int uv_len_used = count_bits_i(cd_used.uv); int vcol_len_used = count_bits_i(cd_used.vcol); @@ -458,6 +468,16 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, } } +static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache) +{ + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); + } + } + cache->batch_ready &= ~MBC_SURF_PER_MAT; +} + static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) { FOREACH_MESH_BUFFER_CACHE(cache, mbufcache) @@ -468,21 +488,13 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.vcol); GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.orco); } + mesh_batch_cache_discard_shaded_batches(cache); + mesh_cd_layers_type_clear(&cache->cd_used); - if (cache->surface_per_mat) { - for (int i = 0; i < cache->mat_len; i++) { - GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); - } - } MEM_SAFE_FREE(cache->surface_per_mat); - - cache->batch_ready &= ~MBC_SURF_PER_MAT; - MEM_SAFE_FREE(cache->auto_layer_names); MEM_SAFE_FREE(cache->auto_layer_is_srgb); - mesh_cd_layers_type_clear(&cache->cd_used); - cache->mat_len = 0; } @@ -513,6 +525,37 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) cache->tot_uv_area = 0.0f; cache->batch_ready &= ~MBC_EDITUV; + + /* We discarded the vbo.uv so we need to reset the cd_used flag. */ + cache->cd_used.uv = 0; + cache->cd_used.edit_uv = 0; + + /* Discard other batches that uses vbo.uv */ + mesh_batch_cache_discard_shaded_batches(cache); + + GPU_BATCH_DISCARD_SAFE(cache->batch.surface); + cache->batch_ready &= ~MBC_SURFACE; +} + +static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache) +{ + FOREACH_MESH_BUFFER_CACHE(cache, mbufcache) + { + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data); + GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_lines); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_points); + GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_fdots); + } + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_area); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces_stretch_angle); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_faces); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts); + GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_fdots); + GPU_BATCH_DISCARD_SAFE(cache->batch.wire_loops_uvs); + cache->batch_ready &= ~MBC_EDITUV; } void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) @@ -541,8 +584,8 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS | MBC_EDIT_SELECTION_FACES | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_VERTS | MBC_EDIT_MESH_ANALYSIS); - /* Because visible UVs depends on edit mode selection, discard everything. */ - mesh_batch_cache_discard_uvedit(cache); + /* Because visible UVs depends on edit mode selection, discard topology. */ + mesh_batch_cache_discard_uvedit_select(cache); break; case BKE_MESH_BATCH_DIRTY_SELECT_PAINT: /* Paint mode selection flag is packed inside the nor attrib. @@ -836,6 +879,13 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) return DRW_batch_request(&cache->batch.edit_fdots); } +GPUBatch *DRW_mesh_batch_cache_get_edit_skin_roots(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SKIN_ROOTS); + return DRW_batch_request(&cache->batch.edit_skin_roots); +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -876,24 +926,37 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) /** \name UV Image editor API * \{ */ +static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me) +{ + DRW_MeshCDMask cd_needed; + mesh_cd_layers_type_clear(&cd_needed); + mesh_cd_calc_edit_uv_layer(me, &cd_needed); + + BLI_assert(cd_needed.edit_uv != 0 && + "No uv layer available in edituv, but batches requested anyway!"); + + mesh_cd_calc_active_mask_uv_layer(me, &cd_needed); + mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed); +} + /* Creates the GPUBatch for drawing the UV Stretching Area Overlay. * Optional retrieves the total area or total uv area of the mesh. * * The `cache->tot_area` and cache->tot_uv_area` update are calculation are * only valid after calling `DRW_mesh_batch_cache_create_requested`. */ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me, - float *tot_area, - float *tot_uv_area) + float **tot_area, + float **tot_uv_area) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA); if (tot_area != NULL) { - *tot_area = cache->tot_area; + *tot_area = &cache->tot_area; } if (tot_uv_area != NULL) { - *tot_uv_area = cache->tot_uv_area; + *tot_uv_area = &cache->tot_uv_area; } return DRW_batch_request(&cache->batch.edituv_faces_stretch_area); } @@ -901,7 +964,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me, GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE); return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle); } @@ -909,7 +972,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES); return DRW_batch_request(&cache->batch.edituv_faces); } @@ -917,7 +980,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES); return DRW_batch_request(&cache->batch.edituv_edges); } @@ -925,7 +988,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS); return DRW_batch_request(&cache->batch.edituv_verts); } @@ -933,7 +996,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS); return DRW_batch_request(&cache->batch.edituv_fdots); } @@ -941,7 +1004,7 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - texpaint_request_active_uv(cache, me); + edituv_request_active_uv(cache, me); mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS); return DRW_batch_request(&cache->batch.wire_loops_uvs); } @@ -1016,12 +1079,37 @@ void DRW_mesh_batch_cache_create_requested( } } + /* HACK: if MBC_SURF_PER_MAT is requested and ibo.tris is already available, it won't have it's + * index ranges initialized. So discard ibo.tris in order to recreate it. + * This needs to happen before saved_elem_ranges is populated. */ + if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) { + FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache) + { + GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris); + } + /* Clear all batches that reference ibo.tris. */ + GPU_BATCH_CLEAR_SAFE(cache->batch.surface); + GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); + GPU_BATCH_CLEAR_SAFE(cache->batch.edit_mesh_analysis); + GPU_BATCH_CLEAR_SAFE(cache->batch.edit_triangles); + GPU_BATCH_CLEAR_SAFE(cache->batch.edit_lnor); + GPU_BATCH_CLEAR_SAFE(cache->batch.edit_selection_faces); + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_CLEAR_SAFE(cache->surface_per_mat[i]); + } + + cache->batch_ready &= ~(MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_MESH_ANALYSIS | + MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | MBC_EDIT_SELECTION_FACES); + } + if (batch_requested & (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS)) { /* Modifiers will only generate an orco layer if the mesh is deformed. */ if (cache->cd_needed.orco != 0) { - if (CustomData_get_layer(&me->vdata, CD_ORCO) == NULL) { + /* Orco is always extracted from final mesh. */ + Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me; + if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) { /* Skip orco calculation */ cache->cd_needed.orco = 0; } @@ -1083,9 +1171,6 @@ void DRW_mesh_batch_cache_create_requested( FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache) { GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_angle); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.stretch_area); - GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv); GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv); GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris); GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_lines); @@ -1241,6 +1326,18 @@ void DRW_mesh_batch_cache_create_requested( DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_pos); DRW_vbo_request(cache->batch.edit_fdots, &mbufcache->vbo.fdots_nor); } + if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_LINES)) { + DRW_vbo_request(cache->batch.edit_skin_roots, &mbufcache->vbo.skin_roots); + /* HACK(fclem): This is to workaround the deferred batch init + * that prevent drawing using DRW_shgroup_call_instances_with_attribs. + * So we instead create the whole instancing batch here. + * Note that we use GPU_PRIM_LINES instead of expected GPU_PRIM_LINE_STRIP + * in order to mimic the old stipple pattern. */ + cache->batch.edit_skin_roots->inst = cache->batch.edit_skin_roots->verts[0]; + cache->batch.edit_skin_roots->verts[0] = NULL; + GPUBatch *circle = DRW_cache_screenspace_circle_get(); + GPU_batch_vertbuf_add(cache->batch.edit_skin_roots, circle->verts[0]); + } /* Selection */ if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index d6e5da9307e..b1fde427de2 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -83,6 +83,7 @@ void DRW_globals_update(void) UI_GetThemeColor4fv(TH_VNORMAL, gb->colorVNormal); UI_GetThemeColor4fv(TH_LNORMAL, gb->colorLNormal); UI_GetThemeColor4fv(TH_FACE_DOT, gb->colorFaceDot); + UI_GetThemeColor4fv(TH_SKIN_ROOT, gb->colorSkinRoot); UI_GetThemeColor4fv(TH_BACK, gb->colorBackground); /* Custom median color to slightly affect the edit mesh colors. */ @@ -277,7 +278,6 @@ static struct { struct GPUVertFormat *instance_scaled; struct GPUVertFormat *instance_sized; struct GPUVertFormat *instance_outline; - struct GPUVertFormat *instance; struct GPUVertFormat *instance_camera; struct GPUVertFormat *instance_distance_lines; struct GPUVertFormat *instance_spot; @@ -1095,7 +1095,7 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle) NULL, datatoc_gpu_shader_flat_color_frag_glsl, datatoc_common_view_lib_glsl, - "#define USE_NEEDLE"); + "#define USE_NEEDLE\n"); } return sh_data->volume_velocity_needle_sh; } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 9899b6c0194..01c0946247a 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -73,6 +73,7 @@ typedef struct GlobalsUboStorage { float colorVNormal[4]; float colorLNormal[4]; float colorFaceDot[4]; + float colorSkinRoot[4]; float colorDeselect[4]; float colorOutline[4]; diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index f77243ca9f1..58085cf08c6 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -201,30 +201,33 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, /* Transform Feedback subdiv. */ if (need_ft_update) { int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len; - GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + if (final_points_len) { + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); #ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf); + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( + tf_shader, g_tf_pass, hair_cache->final[subdiv].proc_buf); #else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); - pr_call->next = g_tf_calls; - pr_call->vbo = hair_cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__); + pr_call->next = g_tf_calls; + pr_call->vbo = hair_cache->final[subdiv].proc_buf; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); #endif - DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); - DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); - DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); + DRW_shgroup_uniform_int( + tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); + DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len); + } } return shgrp; diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 69756203d66..81b10e095c3 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -64,7 +64,7 @@ typedef struct DRWTempBufferHandle { /** Format pointer for reuse. */ GPUVertFormat *format; /** Touched vertex length for resize. */ - uint *vert_len; + int *vert_len; } DRWTempBufferHandle; static ListBase g_idatalists = {NULL, NULL}; @@ -112,7 +112,7 @@ static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data)) */ GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist, GPUVertFormat *format, - uint *vert_len) + int *vert_len) { BLI_assert(format != NULL); BLI_assert(vert_len != NULL); diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h index 2ede68e16d8..524c4cd96d8 100644 --- a/source/blender/draw/intern/draw_instance_data.h +++ b/source/blender/draw/intern/draw_instance_data.h @@ -40,7 +40,7 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist, GPUVertFormat *format, - uint *vert_len); + int *vert_len); GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, GPUVertBuf *buf, GPUBatch *geom); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index f4648405cfd..b75053f461e 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -165,7 +165,7 @@ struct DRWTextStore *DRW_text_cache_ensure(void) bool DRW_object_is_renderable(const Object *ob) { - BLI_assert((ob->base_flag & BASE_VISIBLE) != 0); + BLI_assert((ob->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0); if (ob->type == OB_MESH) { if ((ob == DST.draw_ctx.object_edit) || BKE_object_is_in_editmode(ob)) { @@ -538,8 +538,11 @@ static void drw_viewport_cache_resize(void) GPU_texture_free(*tex); } - BLI_memblock_clear(DST.vmempool->calls, NULL); - BLI_memblock_clear(DST.vmempool->states, NULL); + BLI_memblock_clear(DST.vmempool->commands, NULL); + BLI_memblock_clear(DST.vmempool->commands_small, NULL); + BLI_memblock_clear(DST.vmempool->callbuffers, NULL); + BLI_memblock_clear(DST.vmempool->obmats, NULL); + BLI_memblock_clear(DST.vmempool->obinfos, NULL); BLI_memblock_clear(DST.vmempool->cullstates, NULL); BLI_memblock_clear(DST.vmempool->shgroups, NULL); BLI_memblock_clear(DST.vmempool->uniforms, NULL); @@ -587,28 +590,28 @@ static void drw_context_state_init(void) } } -static DRWCallState *draw_unit_state_create(void) +static void draw_unit_state_create(void) { - DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states); - state->flag = 0; - state->matflag = 0; + DRWObjectInfos *infos = BLI_memblock_alloc(DST.vmempool->obinfos); + DRWObjectMatrix *mats = BLI_memblock_alloc(DST.vmempool->obmats); + DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates); - unit_m4(state->model); - unit_m4(state->modelinverse); + unit_m4(mats->model); + unit_m4(mats->modelinverse); - copy_v3_fl(state->orcotexfac[0], 0.0f); - copy_v3_fl(state->orcotexfac[1], 1.0f); + copy_v3_fl(infos->orcotexfac[0], 0.0f); + copy_v3_fl(infos->orcotexfac[1], 1.0f); - state->ob_index = 0; - state->ob_random = 0.0f; - copy_v3_fl(state->ob_color, 1.0f); + infos->ob_index = 0; + infos->ob_random = 0.0f; + infos->ob_neg_scale = 1.0f; + copy_v3_fl(infos->ob_color, 1.0f); /* TODO(fclem) get rid of this. */ - state->culling = BLI_memblock_alloc(DST.vmempool->cullstates); - state->culling->bsphere.radius = -1.0f; - state->culling->user_data = NULL; + culling->bsphere.radius = -1.0f; + culling->user_data = NULL; - return state; + DRW_handle_increment(&DST.resource_handle); } /* It also stores viewport variable to an immutable place: DST @@ -633,33 +636,48 @@ static void drw_viewport_var_init(void) DST.vmempool = GPU_viewport_mempool_get(DST.viewport); - if (DST.vmempool->calls == NULL) { - DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall)); + if (DST.vmempool->commands == NULL) { + DST.vmempool->commands = BLI_memblock_create(sizeof(DRWCommandChunk)); } - if (DST.vmempool->states == NULL) { - DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState)); + if (DST.vmempool->commands_small == NULL) { + DST.vmempool->commands_small = BLI_memblock_create(sizeof(DRWCommandSmallChunk)); + } + if (DST.vmempool->callbuffers == NULL) { + DST.vmempool->callbuffers = BLI_memblock_create(sizeof(DRWCallBuffer)); + } + if (DST.vmempool->obmats == NULL) { + uint chunk_len = sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN; + DST.vmempool->obmats = BLI_memblock_create_ex(sizeof(DRWObjectMatrix), chunk_len); + } + if (DST.vmempool->obinfos == NULL) { + uint chunk_len = sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN; + DST.vmempool->obinfos = BLI_memblock_create_ex(sizeof(DRWObjectInfos), chunk_len); } if (DST.vmempool->cullstates == NULL) { - DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState)); + uint chunk_len = sizeof(DRWCullingState) * DRW_RESOURCE_CHUNK_LEN; + DST.vmempool->cullstates = BLI_memblock_create_ex(sizeof(DRWCullingState), chunk_len); } if (DST.vmempool->shgroups == NULL) { DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup)); } if (DST.vmempool->uniforms == NULL) { - DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform)); + DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniformChunk)); } if (DST.vmempool->views == NULL) { DST.vmempool->views = BLI_memblock_create(sizeof(DRWView)); } if (DST.vmempool->passes == NULL) { - DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass)); + uint chunk_len = sizeof(DRWPass) * DRW_RESOURCE_CHUNK_LEN; + DST.vmempool->passes = BLI_memblock_create_ex(sizeof(DRWPass), chunk_len); } if (DST.vmempool->images == NULL) { DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *)); } - /* Alloc default unit state */ - DST.unit_state = draw_unit_state_create(); + DST.resource_handle = 0; + DST.pass_handle = 0; + + draw_unit_state_create(); DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport); DRW_instance_data_list_reset(DST.idatalist); @@ -673,8 +691,6 @@ static void drw_viewport_var_init(void) DST.default_framebuffer = NULL; DST.vmempool = NULL; - - DST.unit_state = NULL; } DST.primary_view_ct = 0; @@ -717,6 +733,10 @@ static void drw_viewport_var_init(void) G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL); } + if (DST.draw_list == NULL) { + DST.draw_list = GPU_draw_list_create(DRW_DRAWLIST_LEN); + } + memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data)); } @@ -1100,7 +1120,7 @@ static void drw_engines_world_update(Scene *scene) static void drw_engines_cache_populate(Object *ob) { - DST.ob_state = NULL; + DST.ob_handle = 0; /* HACK: DrawData is copied by COW from the duplicated object. * This is valid for IDs that cannot be instantiated but this @@ -1152,7 +1172,7 @@ static void drw_engines_cache_finish(void) MEM_freeN(DST.vedata_array); } -static void drw_engines_draw_background(void) +static bool drw_engines_draw_background(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; @@ -1166,10 +1186,20 @@ static void drw_engines_draw_background(void) DRW_stats_group_end(); PROFILE_END_UPDATE(data->background_time, stime); - return; + return true; } } + /* No draw engines draw the background. We clear the background. + * We draw the background after drawing of the scene so the camera background + * images can be drawn using ALPHA Under. Otherwise the background always + * interfered with the alpha blending. */ + DRW_clear_background(); + return false; +} + +static void drw_draw_background_alpha_under(void) +{ /* No draw_background found, doing default background */ const bool do_alpha_checker = !DRW_state_draw_background(); DRW_draw_background(do_alpha_checker); @@ -1546,20 +1576,6 @@ void DRW_draw_view(const bContext *C) DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C); } -static bool is_object_visible_in_viewport(View3D *v3d, Object *ob) -{ - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { - return false; - } - - if ((v3d->flag & V3D_LOCAL_COLLECTIONS) && - ((v3d->local_collections_uuid & ob->runtime.local_collections_bits) == 0)) { - return false; - } - - return true; -} - /** * Used for both regular and off-screen drawing. * Need to reset DST before calling this function @@ -1635,7 +1651,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } DST.dupli_parent = data_.dupli_parent; @@ -1666,7 +1682,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_hair_update(); - drw_engines_draw_background(); + const bool background_drawn = drw_engines_draw_background(); GPU_framebuffer_bind(DST.default_framebuffer); @@ -1677,6 +1693,10 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_engines_draw_scene(); + if (!background_drawn) { + drw_draw_background_alpha_under(); + } + /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */ GPU_flush(); @@ -1918,6 +1938,8 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph RenderResult *render_result = RE_engine_get_result(engine); RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name); + DST.buffer_finish_called = false; + DRW_render_gpencil_to_image(engine, render_layer, &render_rect); /* Force cache to reset. */ @@ -2028,13 +2050,15 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) RE_SetActiveRenderView(render, render_view->name); drw_view_reset(); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); + DST.buffer_finish_called = false; + /* grease pencil: render result is merged in the previous render result. */ if (DRW_render_check_grease_pencil(depsgraph)) { DRW_state_reset(); drw_view_reset(); DRW_render_gpencil_to_image(engine, render_layer, &render_rect); + DST.buffer_finish_called = false; } - DST.buffer_finish_called = false; } RE_engine_end_result(engine, render_result, false, false, false); @@ -2080,7 +2104,7 @@ void DRW_render_object_iter( if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; - DST.ob_state = NULL; + DST.ob_handle = 0; drw_duplidata_load(DST.dupli_source); if (!DST.dupli_source) { @@ -2187,6 +2211,7 @@ void DRW_render_instance_buffer_finish(void) BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!"); DST.buffer_finish_called = true; DRW_instance_buffer_finish(DST.idatalist); + drw_resource_buffer_finish(DST.vmempool); } /** @@ -2210,7 +2235,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, Object *obact = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(obact); #ifndef USE_GPU_SELECT - UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect); + UNUSED_VARS(scene, view_layer, v3d, ar, rect); #else RegionView3D *rv3d = ar->regiondata; @@ -2326,7 +2351,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, v3d->object_type_exclude_select); bool filter_exclude = false; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } if ((ob->base_flag & BASE_SELECTABLE) && @@ -2418,8 +2443,38 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /** * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing). */ -static void drw_draw_depth_loop_imp(void) +static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph, + ARegion *ar, + View3D *v3d, + GPUViewport *viewport, + const bool use_opengl_context) { + Scene *scene = DEG_get_evaluated_scene(depsgraph); + RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + RegionView3D *rv3d = ar->regiondata; + + if (use_opengl_context) { + DRW_opengl_context_enable(); + } + + DST.viewport = viewport; + DST.options.is_depth = true; + + /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ + DST.draw_ctx = (DRWContextState){ + .ar = ar, + .rv3d = rv3d, + .v3d = v3d, + .scene = scene, + .view_layer = view_layer, + .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, + }; + + drw_engines_data_validate(); + /* Setup framebuffer */ DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get( DST.viewport); @@ -2441,13 +2496,12 @@ static void drw_draw_depth_loop_imp(void) drw_engines_cache_init(); drw_engines_world_update(DST.draw_ctx.scene); - View3D *v3d = DST.draw_ctx.v3d; const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; } - if (!is_object_visible_in_viewport(v3d, ob)) { + if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; } DST.dupli_parent = data_.dupli_parent; @@ -2477,6 +2531,20 @@ static void drw_draw_depth_loop_imp(void) /* TODO: Reading depth for operators should be done here. */ GPU_framebuffer_restore(); + + drw_engines_disable(); + + drw_viewport_cache_resize(); + +#ifdef DEBUG + /* Avoid accidental reuse. */ + drw_state_ensure_not_reused(&DST); +#endif + + /* Changin context */ + if (use_opengl_context) { + DRW_opengl_context_disable(); + } } /** @@ -2488,55 +2556,18 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, GPUViewport *viewport, bool use_opengl_context) { - Scene *scene = DEG_get_evaluated_scene(depsgraph); - RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); - ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); - RegionView3D *rv3d = ar->regiondata; - - if (use_opengl_context) { - DRW_opengl_context_enable(); - } - /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); - DST.viewport = viewport; - DST.options.is_depth = true; - - /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ - DST.draw_ctx = (DRWContextState){ - .ar = ar, - .rv3d = rv3d, - .v3d = v3d, - .scene = scene, - .view_layer = view_layer, - .obact = OBACT(view_layer), - .engine_type = engine_type, - .depsgraph = depsgraph, - }; - /* Get list of enabled engines */ { drw_engines_enable_basic(); if (DRW_state_draw_support()) { drw_engines_enable_from_object_mode(); } - drw_engines_data_validate(); } - drw_draw_depth_loop_imp(); - - drw_engines_disable(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif - - /* Changin context */ - if (use_opengl_context) { - DRW_opengl_context_disable(); - } + drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, use_opengl_context); } /** @@ -2547,43 +2578,12 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, View3D *v3d, GPUViewport *viewport) { - Scene *scene = DEG_get_evaluated_scene(depsgraph); - ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); - RegionView3D *rv3d = ar->regiondata; - - DRW_opengl_context_enable(); - /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); - DST.viewport = viewport; - DST.options.is_depth = true; - - /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ - DST.draw_ctx = (DRWContextState){ - .ar = ar, - .rv3d = rv3d, - .v3d = v3d, - .scene = scene, - .view_layer = view_layer, - .obact = OBACT(view_layer), - .depsgraph = depsgraph, - }; - use_drw_engine(&draw_engine_gpencil_type); - drw_engines_data_validate(); - - drw_draw_depth_loop_imp(); - - drw_engines_disable(); - -#ifdef DEBUG - /* Avoid accidental reuse. */ - drw_state_ensure_not_reused(&DST); -#endif - /* Changin context */ - DRW_opengl_context_disable(); + drw_draw_depth_loop_imp(depsgraph, ar, v3d, viewport, true); } void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rcti *rect) @@ -2631,7 +2631,13 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const rc drw_engines_cache_finish(); +#if 0 /* This is a workaround to a nasty bug that seems to be a nasty driver bug. (See T69377) */ DRW_render_instance_buffer_finish(); +#else + DST.buffer_finish_called = true; + // DRW_instance_buffer_finish(DST.idatalist); + drw_resource_buffer_finish(DST.vmempool); +#endif } /* Start Drawing */ @@ -2937,6 +2943,10 @@ void DRW_engines_free(void) MEM_SAFE_FREE(DST.uniform_names.buffer); + if (DST.draw_list) { + GPU_draw_list_discard(DST.draw_list); + } + DRW_opengl_context_disable(); } diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 85f6cf05e83..709116c78e5 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -28,8 +28,10 @@ #include "DRW_engine.h" #include "DRW_render.h" +#include "BLI_assert.h" #include "BLI_linklist.h" #include "BLI_threads.h" +#include "BLI_memblock.h" #include "GPU_batch.h" #include "GPU_context.h" @@ -43,6 +45,9 @@ /* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ #define USE_GPU_SELECT +/* Use drawcall batching using instanced rendering. */ +#define USE_BATCHING 1 + // #define DRW_DEBUG_CULLING #define DRW_DEBUG_USE_UNIFORM_NAME 0 #define DRW_UNIFORM_BUFFER_NAME 64 @@ -90,20 +95,6 @@ * > DRWUniform */ -/* Used by DRWCallState.flag */ -enum { - DRW_CALL_NEGSCALE = (1 << 1), -}; - -/* Used by DRWCallState.matflag */ -enum { - DRW_CALL_MODELINVERSE = (1 << 0), - DRW_CALL_MODELVIEWPROJECTION = (1 << 1), - DRW_CALL_ORCOTEXFAC = (1 << 2), - DRW_CALL_OBJECTINFO = (1 << 3), - DRW_CALL_OBJECTCOLOR = (1 << 4), -}; - typedef struct DRWCullingState { uint32_t mask; /* Culling: Using Bounding Sphere for now for faster culling. @@ -113,38 +104,161 @@ typedef struct DRWCullingState { void *user_data; } DRWCullingState; -typedef struct DRWCallState { - DRWCullingState *culling; - uchar flag; - uchar matflag; /* Which matrices to compute. */ - short ob_index; - /* Matrices */ +/* Minimum max UBO size is 64KiB. We take the largest + * UBO struct and alloc the max number. + * ((1 << 16) / sizeof(DRWObjectMatrix)) = 512 + * Keep in sync with common_view_lib.glsl */ +#define DRW_RESOURCE_CHUNK_LEN 512 + +/** + * Identifier used to sort similar drawcalls together. + * Also used to reference elements inside memory blocks. + * + * From MSB to LSB + * 1 bit for negative scale. + * 22 bits for chunk id. + * 9 bits for resource id inside the chunk. (can go up to 511) + * |-|----------------------|---------| + * + * Use manual bit-shift and mask instead of bit-fields to avoid + * compiler dependent behavior that would mess the ordering of + * the members thus changing the sorting order. + */ +typedef uint32_t DRWResourceHandle; + +BLI_INLINE uint32_t DRW_handle_negative_scale_get(const DRWResourceHandle *handle) +{ + return (*handle & 0x80000000) != 0; +} + +BLI_INLINE uint32_t DRW_handle_chunk_get(const DRWResourceHandle *handle) +{ + return (*handle & 0x7FFFFFFF) >> 9; +} + +BLI_INLINE uint32_t DRW_handle_id_get(const DRWResourceHandle *handle) +{ + return (*handle & 0x000001FF); +} + +BLI_INLINE void DRW_handle_increment(DRWResourceHandle *handle) +{ + *handle += 1; +} + +BLI_INLINE void DRW_handle_negative_scale_enable(DRWResourceHandle *handle) +{ + *handle |= 0x80000000; +} + +BLI_INLINE void *DRW_memblock_elem_from_handle(struct BLI_memblock *memblock, + const DRWResourceHandle *handle) +{ + int elem = DRW_handle_id_get(handle); + int chunk = DRW_handle_chunk_get(handle); + return BLI_memblock_elem_get(memblock, chunk, elem); +} + +typedef struct DRWObjectMatrix { float model[4][4]; float modelinverse[4][4]; - float orcotexfac[2][3]; - float ob_random; +} DRWObjectMatrix; + +typedef struct DRWObjectInfos { + float orcotexfac[2][4]; float ob_color[4]; -} DRWCallState; + float ob_index; + float pad; /* UNUSED*/ + float ob_random; + float ob_neg_scale; +} DRWObjectInfos; + +BLI_STATIC_ASSERT_ALIGN(DRWObjectMatrix, 16) +BLI_STATIC_ASSERT_ALIGN(DRWObjectInfos, 16) -typedef struct DRWCall { - struct DRWCall *next; - DRWCallState *state; +typedef enum { + /* Draw Commands */ + DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */ + DRW_CMD_DRAW_RANGE = 1, + DRW_CMD_DRAW_INSTANCE = 2, + DRW_CMD_DRAW_PROCEDURAL = 3, + /* Other Commands */ + DRW_CMD_CLEAR = 12, + DRW_CMD_DRWSTATE = 13, + DRW_CMD_STENCIL = 14, + DRW_CMD_SELECTID = 15, + /* Needs to fit in 4bits */ +} eDRWCommandType; + +#define DRW_MAX_DRAW_CMD_TYPE DRW_CMD_DRAW_PROCEDURAL + +typedef struct DRWCommandDraw { + GPUBatch *batch; + DRWResourceHandle handle; +} DRWCommandDraw; +/* Assume DRWResourceHandle to be 0. */ +typedef struct DRWCommandDrawRange { GPUBatch *batch; uint vert_first; uint vert_count; +} DRWCommandDrawRange; + +typedef struct DRWCommandDrawInstance { + GPUBatch *batch; + DRWResourceHandle handle; uint inst_count; +} DRWCommandDrawInstance; -#ifdef USE_GPU_SELECT - /* TODO(fclem) remove once we have a dedicated selection engine. */ - int select_id; - GPUVertBuf *inst_selectid; -#endif -} DRWCall; +typedef struct DRWCommandDrawProcedural { + GPUBatch *batch; + DRWResourceHandle handle; + uint vert_count; +} DRWCommandDrawProcedural; + +typedef struct DRWCommandSetMutableState { + /** State changes (or'd or and'd with the pass's state) */ + DRWState enable; + DRWState disable; +} DRWCommandSetMutableState; + +typedef struct DRWCommandSetStencil { + uint mask; +} DRWCommandSetStencil; + +typedef struct DRWCommandSetSelectID { + GPUVertBuf *select_buf; + uint select_id; +} DRWCommandSetSelectID; + +typedef struct DRWCommandClear { + eGPUFrameBufferBits clear_channels; + uchar r, g, b, a; /* [0..1] for each channels. Normalized. */ + float depth; /* [0..1] for depth. Normalized. */ + uchar stencil; /* Stencil value [0..255] */ +} DRWCommandClear; + +typedef union DRWCommand { + DRWCommandDraw draw; + DRWCommandDrawRange range; + DRWCommandDrawInstance instance; + DRWCommandDrawProcedural procedural; + DRWCommandSetMutableState state; + DRWCommandSetStencil stencil; + DRWCommandSetSelectID select_id; + DRWCommandClear clear; +} DRWCommand; + +/* Used for agregating calls into GPUVertBufs. */ +struct DRWCallBuffer { + GPUVertBuf *buf; + GPUVertBuf *buf_select; + int count; +}; /* Used by DRWUniform.type */ typedef enum { - DRW_UNIFORM_INT, + DRW_UNIFORM_INT = 0, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT, DRW_UNIFORM_FLOAT_COPY, @@ -153,55 +267,56 @@ typedef enum { DRW_UNIFORM_TEXTURE_REF, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST, + DRW_UNIFORM_TFEEDBACK_TARGET, + /** Per drawcall uniforms/UBO */ + DRW_UNIFORM_BLOCK_OBMATS, + DRW_UNIFORM_BLOCK_OBINFOS, + DRW_UNIFORM_RESOURCE_CHUNK, + /** Legacy / Fallback */ + DRW_UNIFORM_BASE_INSTANCE, + DRW_UNIFORM_MODEL_MATRIX, + DRW_UNIFORM_MODEL_MATRIX_INVERSE, + DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, + /* WARNING: set DRWUniform->type + * bit length accordingly. */ } DRWUniformType; struct DRWUniform { - DRWUniform *next; /* single-linked list */ union { /* For reference or array/vector types. */ const void *pvalue; /* Single values. */ - float fvalue[2]; - int ivalue[2]; + float fvalue[4]; + int ivalue[4]; }; - int name_ofs; /* name offset in name buffer. */ int location; - char type; /* DRWUniformType */ - char length; /* cannot be more than 16 */ - char arraysize; /* cannot be more than 16 too */ + uint32_t type : 5; /* DRWUniformType */ + uint32_t length : 5; /* cannot be more than 16 */ + uint32_t arraysize : 5; /* cannot be more than 16 too */ + uint32_t name_ofs : 17; /* name offset in name buffer. */ }; struct DRWShadingGroup { DRWShadingGroup *next; - GPUShader *shader; /* Shader to bind */ - DRWUniform *uniforms; /* Uniforms pointers */ + GPUShader *shader; /* Shader to bind */ + struct DRWUniformChunk *uniforms; /* Uniforms pointers */ struct { - DRWCall *first, *last; /* Linked list of DRWCall */ - } calls; + /* Chunks of draw calls. */ + struct DRWCommandChunk *first, *last; + } cmd; - /** TODO Maybe remove from here */ - struct GPUVertBuf *tfeedback_target; - - /** State changes for this batch only (or'd with the pass's state) */ - DRWState state_extra; - /** State changes for this batch only (and'd with the pass's state) */ - DRWState state_extra_disable; - /** Stencil mask to use for stencil test / write operations */ - uint stencil_mask; - - /* Builtin matrices locations */ - int model; - int modelinverse; - int modelviewprojection; - int orcotexfac; - int callid; - int objectinfo; - int objectcolor; - uchar matflag; /* Matrices needed, same as DRWCall.flag */ - - DRWPass *pass_parent; /* backlink to pass we're in */ + union { + struct { + int objectinfo; /* Equal to 1 if the shader needs obinfos. */ + DRWResourceHandle pass_handle; /* Memblock key to parent pass. */ + }; + struct { + float distance; /* Distance from camera. */ + uint original_index; /* Original position inside the shgroup list. */ + } z_sorting; + }; }; #define MAX_PASS_NAME 32 @@ -213,6 +328,7 @@ struct DRWPass { DRWShadingGroup *last; } shgroups; + DRWResourceHandle handle; DRWState state; char name[MAX_PASS_NAME]; }; @@ -232,6 +348,8 @@ typedef struct DRWViewUboStorage { float viewcamtexcofac[4]; } DRWViewUboStorage; +BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16) + #define MAX_CULLED_VIEWS 32 struct DRWView { @@ -253,13 +371,45 @@ struct DRWView { void *user_data; }; -/* TODO(fclem): Future awaits */ -#if 0 -typedef struct ModelUboStorage { - float model[4][4]; - float modelinverse[4][4]; -} ModelUboStorage; -#endif +/* ------------ Data Chunks --------------- */ +/** + * In order to keep a cache friendly data structure, + * we alloc most of our little data into chunks of multiple item. + * Iteration, allocation and memory usage are better. + * We loose a bit of memory by allocating more than what we need + * but it's counterbalanced by not needing the linked-list pointers + * for each item. + **/ + +typedef struct DRWUniformChunk { + struct DRWUniformChunk *next; /* single-linked list */ + uint32_t uniform_len; + uint32_t uniform_used; + DRWUniform uniforms[10]; +} DRWUniformChunk; + +typedef struct DRWCommandChunk { + struct DRWCommandChunk *next; + uint32_t command_len; + uint32_t command_used; + /* 4bits for each command. */ + uint64_t command_type[6]; + /* -- 64 bytes aligned -- */ + DRWCommand commands[96]; + /* -- 64 bytes aligned -- */ +} DRWCommandChunk; + +typedef struct DRWCommandSmallChunk { + struct DRWCommandChunk *next; + uint32_t command_len; + uint32_t command_used; + /* 4bits for each command. */ + /* TODO reduce size of command_type. */ + uint64_t command_type[6]; + DRWCommand commands[6]; +} DRWCommandSmallChunk; + +BLI_STATIC_ASSERT_ALIGN(DRWCommandChunk, 16); /* ------------- DRAW DEBUG ------------ */ @@ -280,21 +430,31 @@ typedef struct DRWDebugSphere { #define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */ #define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */ #define STENCIL_UNDEFINED 256 +#define DRW_DRAWLIST_LEN 256 typedef struct DRWManager { /* TODO clean up this struct a bit */ /* Cache generation */ ViewportMemoryPool *vmempool; DRWInstanceDataList *idatalist; - DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE]; - /* Default Unit model matrix state without culling. */ - DRWCallState *unit_state; /* State of the object being evaluated if already allocated. */ - DRWCallState *ob_state; + DRWResourceHandle ob_handle; + /** True if current DST.ob_state has its matching DRWObjectInfos init. */ + bool ob_state_obinfo_init; + /** Handle of current object resource in object resource arrays (DRWObjectMatrices/Infos). */ + DRWResourceHandle resource_handle; + /** Handle of next DRWPass to be allocated. */ + DRWResourceHandle pass_handle; + + /** Dupli state. NULL if not dupli. */ struct DupliObject *dupli_source; struct Object *dupli_parent; struct Object *dupli_origin; + /** Ghash containing original objects. */ struct GHash *dupli_ghash; - void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */ + /** TODO(fclem) try to remove usage of this. */ + DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE]; + /* Array of dupli_data (one for each enabled engine) to handle duplis. */ + void **dupli_datas; /* Rendering state */ GPUShader *shader; @@ -357,6 +517,8 @@ typedef struct DRWManager { /** Mutex to lock the drw manager and avoid concurrent context usage. */ TicketMutex *gl_context_mutex; + GPUDrawList *draw_list; + /** GPU Resource State: Memory storage between drawing. */ struct { /* High end GPUs supports up to 32 binds per shader stage. @@ -397,9 +559,13 @@ void drw_state_set(DRWState state); void drw_debug_draw(void); void drw_debug_init(void); +eDRWCommandType command_type_get(uint64_t *command_type_bits, int index); + void drw_batch_cache_validate(Object *ob); void drw_batch_cache_generate_requested(struct Object *ob); +void drw_resource_buffer_finish(ViewportMemoryPool *vmempool); + /* Procedural Drawing */ GPUBatch *drw_cache_procedural_points_get(void); GPUBatch *drw_cache_procedural_lines_get(void); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index cd174e899d4..330f72eda18 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -34,6 +34,7 @@ #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "BLI_alloca.h" #include "BLI_hash.h" #include "BLI_link_utils.h" #include "BLI_mempool.h" @@ -51,6 +52,36 @@ /** \name Uniform Buffer Object (DRW_uniformbuffer) * \{ */ +static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len) +{ + /* Count unique batches. Tt's not really important if + * there is collisions. If there is a lot of different batches, + * the sorting benefit will be negligible. + * So at least sort fast! */ + uchar idx[128] = {0}; + /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */ +#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx)) + BLI_assert(array_len <= ARRAY_SIZE(idx)); + + for (int i = 0; i < array_len; i++) { + /* Early out if nothing to sort. */ + if (++idx[KEY(array[i])] == array_len) { + return; + } + } + /* Cumulate batch indices */ + for (int i = 1; i < ARRAY_SIZE(idx); i++) { + idx[i] += idx[i - 1]; + } + /* Traverse in reverse to not change the order of the resource ids. */ + for (int src = array_len - 1; src >= 0; src--) { + array_tmp[--idx[KEY(array[src])]] = array[src]; + } +#undef KEY + + memcpy(array, array_tmp, sizeof(*array) * array_len); +} + GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data) { return GPU_uniformbuffer_create(size, data, NULL); @@ -66,20 +97,94 @@ void DRW_uniformbuffer_free(GPUUniformBuffer *ubo) GPU_uniformbuffer_free(ubo); } +void drw_resource_buffer_finish(ViewportMemoryPool *vmempool) +{ + int chunk_id = DRW_handle_chunk_get(&DST.resource_handle); + int elem_id = DRW_handle_id_get(&DST.resource_handle); + int ubo_len = 1 + chunk_id - ((elem_id == 0) ? 1 : 0); + size_t list_size = sizeof(GPUUniformBuffer *) * ubo_len; + + /* TODO find a better system. currently a lot of obinfos UBO are going to be unused + * if not rendering with Eevee. */ + + if (vmempool->matrices_ubo == NULL) { + vmempool->matrices_ubo = MEM_callocN(list_size, __func__); + vmempool->obinfos_ubo = MEM_callocN(list_size, __func__); + vmempool->ubo_len = ubo_len; + } + + /* Remove unecessary buffers */ + for (int i = ubo_len; i < vmempool->ubo_len; i++) { + GPU_uniformbuffer_free(vmempool->matrices_ubo[i]); + GPU_uniformbuffer_free(vmempool->obinfos_ubo[i]); + } + + if (ubo_len != vmempool->ubo_len) { + vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size); + vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size); + vmempool->ubo_len = ubo_len; + } + + /* Create/Update buffers. */ + for (int i = 0; i < ubo_len; i++) { + void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0); + void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0); + if (vmempool->matrices_ubo[i] == NULL) { + vmempool->matrices_ubo[i] = GPU_uniformbuffer_create( + sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN, data_obmat, NULL); + vmempool->obinfos_ubo[i] = GPU_uniformbuffer_create( + sizeof(DRWObjectInfos) * DRW_RESOURCE_CHUNK_LEN, data_infos, NULL); + } + else { + GPU_uniformbuffer_update(vmempool->matrices_ubo[i], data_obmat); + GPU_uniformbuffer_update(vmempool->obinfos_ubo[i], data_infos); + } + } + + /* Aligned alloc to avoid unaligned memcpy. */ + DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk"); + DRWCommandChunk *chunk; + BLI_memblock_iter iter; + BLI_memblock_iternew(vmempool->commands, &iter); + while ((chunk = BLI_memblock_iterstep(&iter))) { + bool sortable = true; + /* We can only sort chunks that contain DRWCommandDraw only. */ + for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) { + if (chunk->command_type[i] != 0) { + sortable = false; + } + } + if (sortable) { + draw_call_sort(chunk->commands, chunk_tmp->commands, chunk->command_used); + } + } + MEM_freeN(chunk_tmp); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name Uniforms (DRW_shgroup_uniform) * \{ */ -static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, - int loc, - DRWUniformType type, - const void *value, - int length, - int arraysize) +static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, + int loc, + DRWUniformType type, + const void *value, + int length, + int arraysize) { - DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms); + DRWUniformChunk *unichunk = shgroup->uniforms; + /* Happens on first uniform or if chunk is full. */ + if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) { + unichunk = BLI_memblock_alloc(DST.vmempool->uniforms); + unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms); + unichunk->uniform_used = 0; + BLI_LINKS_PREPEND(shgroup->uniforms, unichunk); + } + + DRWUniform *uni = unichunk->uniforms + unichunk->uniform_used++; + uni->location = loc; uni->type = type; uni->length = length; @@ -87,11 +192,11 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, switch (type) { case DRW_UNIFORM_INT_COPY: - BLI_assert(length <= 2); + BLI_assert(length <= 4); memcpy(uni->ivalue, value, sizeof(int) * length); break; case DRW_UNIFORM_FLOAT_COPY: - BLI_assert(length <= 2); + BLI_assert(length <= 4); memcpy(uni->fvalue, value, sizeof(float) * length); break; default: @@ -99,7 +204,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, break; } - BLI_LINKS_PREPEND(shgroup->uniforms, uni); + return uni; } static void drw_shgroup_builtin_uniform( @@ -136,7 +241,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, BLI_assert(arraysize > 0 && arraysize <= 16); BLI_assert(length >= 0 && length <= 16); - drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize); + DRWUniform *uni = drw_shgroup_uniform_create_ex( + shgroup, location, type, value, length, arraysize); /* If location is -2, the uniform has not yet been queried. * We save the name for query just before drawing. */ @@ -155,7 +261,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, memcpy(dst, name, len); /* Copies NULL terminator. */ DST.uniform_names.buffer_ofs += len; - shgroup->uniforms->name_ofs = ofs; + uni->name_ofs = ofs; } } @@ -286,6 +392,21 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1); } +void DRW_shgroup_uniform_ivec2_copy(DRWShadingGroup *shgroup, const char *name, const int *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 2, 1); +} + +void DRW_shgroup_uniform_ivec3_copy(DRWShadingGroup *shgroup, const char *name, const int *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 3, 1); +} + +void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, value, 4, 1); +} + void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value) { int ival = value; @@ -302,13 +423,23 @@ void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, c drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1); } +void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 3, 1); +} + +void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1); +} + /** \} */ /* -------------------------------------------------------------------- */ /** \name Draw Call (DRW_calls) * \{ */ -static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3]) +static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4]) { ID *ob_data = (ob) ? ob->data : NULL; float *texcoloc = NULL; @@ -316,13 +447,11 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3]) if (ob_data != NULL) { switch (GS(ob_data->name)) { case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); + BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize); break; case ID_CU: { Curve *cu = (Curve *)ob_data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } + BKE_curve_texspace_ensure(cu); texcoloc = cu->loc; texcosize = cu->size; break; @@ -351,159 +480,283 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3]) } } -static void drw_call_state_update_matflag(DRWCallState *state, - DRWShadingGroup *shgroup, - Object *ob) +BLI_INLINE void drw_call_matrix_init(DRWObjectMatrix *ob_mats, Object *ob, float (*obmat)[4]) { - uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag); - - /* HACK: Here we set the matflags bit to 1 when computing the value - * so that it's not recomputed for other drawcalls. - * This is the opposite of what draw_matrices_model_prepare() does. */ - state->matflag |= shgroup->matflag; - - if (new_flags & DRW_CALL_MODELINVERSE) { - if (ob) { - copy_m4_m4(state->modelinverse, ob->imat); - } - else { - invert_m4_m4(state->modelinverse, state->model); - } + copy_m4_m4(ob_mats->model, obmat); + if (ob) { + copy_m4_m4(ob_mats->modelinverse, ob->imat); } - - /* Orco factors: We compute this at creation to not have to save the *ob_data */ - if (new_flags & DRW_CALL_ORCOTEXFAC) { - drw_call_calc_orco(ob, state->orcotexfac); - } - - if (new_flags & DRW_CALL_OBJECTINFO) { - state->ob_index = ob ? ob->index : 0; - uint random; - if (DST.dupli_source) { - random = DST.dupli_source->random_id; - } - else { - random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0); - } - state->ob_random = random * (1.0f / (float)0xFFFFFFFF); - } - - if (new_flags & DRW_CALL_OBJECTCOLOR) { - copy_v4_v4(state->ob_color, ob->color); + else { + /* WATCH: Can be costly. */ + invert_m4_m4(ob_mats->modelinverse, ob_mats->model); } } -static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) +static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob) { - DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states); - state->flag = 0; - state->matflag = 0; - - /* Matrices */ - copy_m4_m4(state->model, obmat); - - if (ob && (ob->transflag & OB_NEG_SCALE)) { - state->flag |= DRW_CALL_NEGSCALE; - } - - drw_call_state_update_matflag(state, shgroup, ob); - - DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates); - state->culling = cull; + BLI_assert(ob); + /* Index. */ + ob_infos->ob_index = ob->index; + /* Orco factors. */ + drw_call_calc_orco(ob, ob_infos->orcotexfac); + /* Random float value. */ + uint random = (DST.dupli_source) ? + DST.dupli_source->random_id : + /* TODO(fclem) this is rather costly to do at runtime. Maybe we can + * put it in ob->runtime and make depsgraph ensure it is up to date. */ + BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0); + ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF); + /* Negative scalling. */ + ob_infos->ob_neg_scale = (ob->transflag & OB_NEG_SCALE) ? -1.0f : 1.0f; + /* Object Color. */ + copy_v4_v4(ob_infos->ob_color, ob->color); +} +static void drw_call_culling_init(DRWCullingState *cull, Object *ob) +{ BoundBox *bbox; if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) { float corner[3]; /* Get BoundSphere center and radius from the BoundBox. */ mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]); - mul_v3_m4v3(corner, obmat, bbox->vec[0]); - mul_m4_v3(obmat, cull->bsphere.center); + mul_v3_m4v3(corner, ob->obmat, bbox->vec[0]); + mul_m4_v3(ob->obmat, cull->bsphere.center); cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); } else { - /* TODO(fclem) Bypass alloc if we can (see if eevee's - * probe visibility collection still works). */ /* Bypass test. */ cull->bsphere.radius = -1.0f; } + /* Reset user data */ + cull->user_data = NULL; +} + +static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob) +{ + DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates); + DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats); + /* FIXME Meh, not always needed but can be accessed after creation. + * Also it needs to have the same resource handle. */ + DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos); + UNUSED_VARS(ob_infos); + + DRWResourceHandle handle = DST.resource_handle; + DRW_handle_increment(&DST.resource_handle); + + if (ob && (ob->transflag & OB_NEG_SCALE)) { + DRW_handle_negative_scale_enable(&handle); + } + + drw_call_matrix_init(ob_mats, ob, obmat); + drw_call_culling_init(culling, ob); + /* ob_infos is init only if needed. */ - return state; + return handle; } -static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) +static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, + float (*obmat)[4], + Object *ob) { if (ob == NULL) { if (obmat == NULL) { - BLI_assert(DST.unit_state); - return DST.unit_state; + DRWResourceHandle handle = 0; + return handle; } else { - return drw_call_state_create(shgroup, obmat, ob); + return drw_resource_handle_new(obmat, NULL); } } else { - if (DST.ob_state == NULL) { - DST.ob_state = drw_call_state_create(shgroup, obmat, ob); + if (DST.ob_handle == 0) { + DST.ob_handle = drw_resource_handle_new(obmat, ob); + DST.ob_state_obinfo_init = false; } - else { - /* If the DRWCallState is reused, add necessary matrices. */ - drw_call_state_update_matflag(DST.ob_state, shgroup, ob); + + if (shgroup->objectinfo) { + if (!DST.ob_state_obinfo_init) { + DST.ob_state_obinfo_init = true; + DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos, + &DST.ob_handle); + + drw_call_obinfos_init(ob_infos, ob); + } } - return DST.ob_state; + return DST.ob_handle; } } +static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type) +{ + command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4); +} + +eDRWCommandType command_type_get(uint64_t *command_type_bits, int index) +{ + return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF); +} + +static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type) +{ + DRWCommandChunk *chunk = shgroup->cmd.last; + + if (chunk == NULL) { + DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small); + smallchunk->command_len = ARRAY_SIZE(smallchunk->commands); + smallchunk->command_used = 0; + smallchunk->command_type[0] = 0x0lu; + chunk = (DRWCommandChunk *)smallchunk; + BLI_LINKS_APPEND(&shgroup->cmd, chunk); + } + else if (chunk->command_used == chunk->command_len) { + chunk = BLI_memblock_alloc(DST.vmempool->commands); + chunk->command_len = ARRAY_SIZE(chunk->commands); + chunk->command_used = 0; + memset(chunk->command_type, 0x0, sizeof(chunk->command_type)); + BLI_LINKS_APPEND(&shgroup->cmd, chunk); + } + + command_type_set(chunk->command_type, chunk->command_used, type); + + return chunk->commands + chunk->command_used++; +} + +static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle) +{ + DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW); + cmd->batch = batch; + cmd->handle = handle; +} + +static void drw_command_draw_range(DRWShadingGroup *shgroup, + GPUBatch *batch, + uint start, + uint count) +{ + DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE); + cmd->batch = batch; + cmd->vert_first = start; + cmd->vert_count = count; +} + +static void drw_command_draw_instance(DRWShadingGroup *shgroup, + GPUBatch *batch, + DRWResourceHandle handle, + uint count) +{ + DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE); + cmd->batch = batch; + cmd->handle = handle; + cmd->inst_count = count; +} + +static void drw_command_draw_procedural(DRWShadingGroup *shgroup, + GPUBatch *batch, + DRWResourceHandle handle, + uint vert_count) +{ + DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL); + cmd->batch = batch; + cmd->handle = handle; + cmd->vert_count = vert_count; +} + +static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id) +{ + /* Only one can be valid. */ + BLI_assert(buf == NULL || select_id == -1); + DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID); + cmd->select_buf = buf; + cmd->select_id = select_id; +} + +static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask) +{ + BLI_assert(mask <= 0xFF); + DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL); + cmd->mask = mask; +} + +static void drw_command_clear(DRWShadingGroup *shgroup, + eGPUFrameBufferBits channels, + uchar r, + uchar g, + uchar b, + uchar a, + float depth, + uchar stencil) +{ + DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR); + cmd->clear_channels = channels; + cmd->r = r; + cmd->g = g; + cmd->b = b; + cmd->a = a; + cmd->depth = depth; + cmd->stencil = stencil; +} + +static void drw_command_set_mutable_state(DRWShadingGroup *shgroup, + DRWState enable, + DRWState disable) +{ + /* TODO Restrict what state can be changed. */ + DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE); + cmd->enable = enable; + cmd->disable = disable; +} + void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4], struct GPUBatch *geom, - uint v_sta, - uint v_ct, bool bypass_culling, void *user_data) { BLI_assert(geom != NULL); + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob); + drw_command_draw(shgroup, geom, handle); - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); - - call->state = drw_call_state_object(shgroup, ob ? ob->obmat : obmat, ob); - call->batch = geom; - call->vert_first = v_sta; - call->vert_count = v_ct; /* 0 means auto from batch. */ - call->inst_count = 0; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; - call->inst_selectid = NULL; -#endif - if (call->state->culling) { - call->state->culling->user_data = user_data; + /* Culling data. */ + if (user_data || bypass_culling) { + DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, + &DST.ob_handle); + + if (user_data) { + culling->user_data = user_data; + } if (bypass_culling) { /* NOTE this will disable culling for the whole object. */ - call->state->culling->bsphere.radius = -1.0f; + culling->bsphere.radius = -1.0f; } } } +void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct) +{ + BLI_assert(geom != NULL); + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + drw_command_draw_range(shgroup, geom, v_sta, v_ct); +} + static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, uint vert_count) { - - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); - - call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob); - call->batch = geom; - call->vert_first = 0; - call->vert_count = vert_count; - call->inst_count = 0; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; - call->inst_selectid = NULL; -#endif + BLI_assert(vert_count > 0); + BLI_assert(geom != NULL); + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + drw_command_draw_procedural(shgroup, geom, handle, vert_count); } void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, Object *ob, uint point_len) @@ -524,25 +777,18 @@ void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, Object *ob, drw_shgroup_call_procedural_add_ex(shgroup, geom, ob, tria_count * 3); } +/* Should be removed */ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint count) { BLI_assert(geom != NULL); - - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); - - call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob); - call->batch = geom; - call->vert_first = 0; - call->vert_count = 0; /* Auto from batch. */ - call->inst_count = count; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; - call->inst_selectid = NULL; -#endif + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + drw_command_draw_instance(shgroup, geom, handle, count); } void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup, @@ -552,25 +798,16 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup, { BLI_assert(geom != NULL); BLI_assert(inst_attributes->verts[0] != NULL); - + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); GPUVertBuf *buf_inst = inst_attributes->verts[0]; - - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); - - call->state = drw_call_state_object(shgroup, ob ? ob->obmat : NULL, ob); - call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom); - call->vert_first = 0; - call->vert_count = 0; /* Auto from batch. */ - call->inst_count = buf_inst->vertex_len; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; - call->inst_selectid = NULL; -#endif + GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom); + drw_command_draw(shgroup, batch, handle); } -// #define SCULPT_DEBUG_BUFFERS - +#define SCULPT_DEBUG_BUFFERS (G.debug_value == 889) typedef struct DRWSculptCallbackData { Object *ob; DRWShadingGroup **shading_groups; @@ -578,13 +815,11 @@ typedef struct DRWSculptCallbackData { bool use_mats; bool use_mask; bool fast_mode; /* Set by draw manager. Do not init. */ -#ifdef SCULPT_DEBUG_BUFFERS - int node_nr; -#endif + + int debug_node_nr; } DRWSculptCallbackData; -#ifdef SCULPT_DEBUG_BUFFERS -# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9]) +#define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9]) static float sculpt_debug_colors[9][4] = { {1.0f, 0.2f, 0.2f, 1.0f}, {0.2f, 1.0f, 0.2f, 1.0f}, @@ -596,59 +831,72 @@ static float sculpt_debug_colors[9][4] = { {0.2f, 1.0f, 0.7f, 1.0f}, {0.7f, 0.2f, 1.0f, 1.0f}, }; -#endif static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers) { - GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); - short index = 0; - /* Meh... use_mask is a bit misleading here. */ if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) { return; } + GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); + short index = 0; + if (scd->use_mats) { index = GPU_pbvh_buffers_material_index_get(buffers); } DRWShadingGroup *shgrp = scd->shading_groups[index]; if (geom != NULL && shgrp != NULL) { -#ifdef SCULPT_DEBUG_BUFFERS - /* Color each buffers in different colors. Only work in solid/Xray mode. */ - shgrp = DRW_shgroup_create_sub(shgrp); - DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1); -#endif + if (SCULPT_DEBUG_BUFFERS) { + /* Color each buffers in different colors. Only work in solid/Xray mode. */ + shgrp = DRW_shgroup_create_sub(shgrp); + DRW_shgroup_uniform_vec3( + shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1); + } /* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this * object. */ DRW_shgroup_call_no_cull(shgrp, geom, scd->ob); } } -#ifdef SCULPT_DEBUG_BUFFERS static void sculpt_debug_cb(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag) { - int *node_nr = (int *)user_data; + int *debug_node_nr = (int *)user_data; BoundBox bb; BKE_boundbox_init_from_minmax(&bb, bmin, bmax); -# if 0 /* Nodes hierarchy. */ +#if 0 /* Nodes hierarchy. */ if (flag & PBVH_Leaf) { DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); } else { DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f}); } -# else /* Color coded leaf bounds. */ +#else /* Color coded leaf bounds. */ if (flag & PBVH_Leaf) { - DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++)); + DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*debug_node_nr)++)); } -# endif -} #endif +} + +static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4]) +{ + /* TODO: take into account partial redraw for clipping planes. */ + DRW_view_frustum_planes_get(DRW_view_default_get(), planes); + + /* Transform clipping planes to object space. Transforming a plane with a + * 4x4 matrix is done by multiplying with the transpose inverse. + * The inverse cancels out here since we transform by inverse(obmat). */ + float tmat[4][4]; + transpose_m4_m4(tmat, ob->obmat); + for (int i = 0; i < 6; i++) { + mul_m4_v4(tmat, planes[i]); + } +} static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol) { @@ -658,31 +906,46 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol) return; } - float(*planes)[4] = NULL; /* TODO proper culling. */ - scd->fast_mode = false; - const DRWContextState *drwctx = DRW_context_state_get(); + RegionView3D *rv3d = drwctx->rv3d; + + /* Frustum planes to show only visible PBVH nodes. */ + float planes[6][4]; + drw_sculpt_get_frustum_planes(scd->ob, planes); + PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6}; + + /* Fast mode to show low poly multires while navigating. */ + scd->fast_mode = false; if (drwctx->evil_C != NULL) { Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0; + scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING); } } + /* Update draw buffers only for visible nodes while painting. + * But do update them otherwise so navigating stays smooth. */ + const bool update_only_visible = rv3d && (rv3d->rflag & RV3D_PAINTING); + Mesh *mesh = scd->ob->data; BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg); - BKE_pbvh_update_draw_buffers(pbvh, use_vcol); - BKE_pbvh_draw_cb(pbvh, planes, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd); + BKE_pbvh_draw_cb(pbvh, + use_vcol, + update_only_visible, + &frustum, + (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, + scd); -#ifdef SCULPT_DEBUG_BUFFERS - int node_nr = 0; - DRW_debug_modelmat(scd->ob->obmat); - BKE_pbvh_draw_debug_cb( - pbvh, - (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb, - &node_nr); -#endif + if (SCULPT_DEBUG_BUFFERS) { + int debug_node_nr = 0; + DRW_debug_modelmat(scd->ob->obmat); + BKE_pbvh_draw_debug_cb( + pbvh, + (void (*)( + void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb, + &debug_node_nr); + } } void DRW_shgroup_call_sculpt( @@ -719,27 +982,26 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN)); BLI_assert(format != NULL); - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); + DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); + callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count); + callbuf->buf_select = NULL; + callbuf->count = 0; - call->state = drw_call_state_object(shgroup, NULL, NULL); - GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count); - call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type); - call->vert_first = 0; - call->vert_count = 0; - call->inst_count = 0; - -#ifdef USE_GPU_SELECT if (G.f & G_FLAG_PICKSEL) { /* Not actually used for rendering but alloced in one chunk. */ if (inst_select_format.attr_len == 0) { GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } - call->inst_selectid = DRW_temp_buffer_request( - DST.idatalist, &inst_select_format, &call->vert_count); + callbuf->buf_select = DRW_temp_buffer_request( + DST.idatalist, &inst_select_format, &callbuf->count); + drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } -#endif - return (DRWCallBuffer *)call; + + DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); + GPUBatch *batch = DRW_temp_batch_request(DST.idatalist, callbuf->buf, prim_type); + drw_command_draw(shgroup, batch, handle); + + return callbuf; } DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, @@ -749,56 +1011,52 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, BLI_assert(geom != NULL); BLI_assert(format != NULL); - DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); - BLI_LINKS_APPEND(&shgroup->calls, call); + DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); + callbuf->buf = DRW_temp_buffer_request(DST.idatalist, format, &callbuf->count); + callbuf->buf_select = NULL; + callbuf->count = 0; - call->state = drw_call_state_object(shgroup, NULL, NULL); - GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count); - call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom); - call->vert_first = 0; - call->vert_count = 0; /* Auto from batch. */ - call->inst_count = 0; - -#ifdef USE_GPU_SELECT if (G.f & G_FLAG_PICKSEL) { /* Not actually used for rendering but alloced in one chunk. */ if (inst_select_format.attr_len == 0) { GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } - call->inst_selectid = DRW_temp_buffer_request( - DST.idatalist, &inst_select_format, &call->inst_count); + callbuf->buf_select = DRW_temp_buffer_request( + DST.idatalist, &inst_select_format, &callbuf->count); + drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } -#endif - return (DRWCallBuffer *)call; + + DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); + GPUBatch *batch = DRW_temp_batch_instance_request(DST.idatalist, callbuf->buf, geom); + drw_command_draw(shgroup, batch, handle); + + return callbuf; } void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len) { - DRWCall *call = (DRWCall *)callbuf; - const bool is_instance = call->batch->inst != NULL; - GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0]; - uint count = is_instance ? call->inst_count++ : call->vert_count++; - const bool resize = (count == buf->vertex_alloc); + GPUVertBuf *buf = callbuf->buf; + const bool resize = (callbuf->count == buf->vertex_alloc); BLI_assert(attr_len == buf->format.attr_len); UNUSED_VARS_NDEBUG(attr_len); if (UNLIKELY(resize)) { - GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK); + GPU_vertbuf_data_resize(buf, callbuf->count + DRW_BUFFER_VERTS_CHUNK); } for (int i = 0; i < attr_len; i++) { - GPU_vertbuf_attr_set(buf, i, count, attr[i]); + GPU_vertbuf_attr_set(buf, i, callbuf->count, attr[i]); } -#ifdef USE_GPU_SELECT if (G.f & G_FLAG_PICKSEL) { if (UNLIKELY(resize)) { - GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK); + GPU_vertbuf_data_resize(callbuf->buf_select, callbuf->count + DRW_BUFFER_VERTS_CHUNK); } - GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id); + GPU_vertbuf_attr_set(callbuf->buf_select, 0, callbuf->count, &DST.select_id); } -#endif + + callbuf->count++; } /** \} */ @@ -811,7 +1069,54 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) { shgroup->uniforms = NULL; + /* TODO(fclem) make them builtin. */ int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock"); + int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock"); + int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock"); + int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE); + int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK); + + if (chunkid_location != -1) { + drw_shgroup_uniform_create_ex( + shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1); + } + + if (baseinst_location != -1) { + drw_shgroup_uniform_create_ex( + shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1); + } + + if (model_ubo_location != -1) { + drw_shgroup_uniform_create_ex( + shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1); + } + else { + int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL); + int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV); + int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); + if (model != -1) { + drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1); + } + if (modelinverse != -1) { + drw_shgroup_uniform_create_ex( + shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1); + } + if (modelviewprojection != -1) { + drw_shgroup_uniform_create_ex( + shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1); + } + } + + if (info_ubo_location != -1) { + drw_shgroup_uniform_create_ex( + shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1); + + /* Abusing this loc to tell shgroup we need the obinfos. */ + shgroup->objectinfo = 1; + } + else { + shgroup->objectinfo = 0; + } if (view_ubo_location != -1) { drw_shgroup_uniform_create_ex( @@ -834,31 +1139,6 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1); - - shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL); - shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV); - shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); - shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO); - shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO); - shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR); - shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID); - - shgroup->matflag = 0; - if (shgroup->modelinverse > -1) { - shgroup->matflag |= DRW_CALL_MODELINVERSE; - } - if (shgroup->modelviewprojection > -1) { - shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION; - } - if (shgroup->orcotexfac > -1) { - shgroup->matflag |= DRW_CALL_ORCOTEXFAC; - } - if (shgroup->objectinfo > -1) { - shgroup->matflag |= DRW_CALL_OBJECTINFO; - } - if (shgroup->objectcolor > -1) { - shgroup->matflag |= DRW_CALL_OBJECTCOLOR; - } } static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) @@ -868,13 +1148,9 @@ static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass BLI_LINKS_APPEND(&pass->shgroups, shgroup); shgroup->shader = shader; - shgroup->state_extra = 0; - shgroup->state_extra_disable = ~0x0; - shgroup->stencil_mask = 0; - shgroup->calls.first = NULL; - shgroup->calls.last = NULL; - shgroup->tfeedback_target = NULL; - shgroup->pass_parent = pass; + shgroup->cmd.first = NULL; + shgroup->cmd.last = NULL; + shgroup->pass_handle = pass->handle; return shgroup; } @@ -975,7 +1251,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, BLI_assert(tf_target != NULL); DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); drw_shgroup_init(shgroup, shader); - shgroup->tfeedback_target = tf_target; + drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1); return shgroup; } @@ -985,37 +1261,42 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, */ void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) { - shgroup->state_extra |= state; + drw_command_set_mutable_state(shgroup, state, 0x0); } void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) { - shgroup->state_extra_disable &= ~state; + drw_command_set_mutable_state(shgroup, 0x0, state); } void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask) { - BLI_assert(mask <= 255); - shgroup->stencil_mask = mask; + drw_command_set_stencil_mask(shgroup, mask); } -bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) -{ - return shgroup->calls.first == NULL; -} - -/* This is a workaround function waiting for the clearing operation to be available inside the - * shgroups. */ -DRWShadingGroup *DRW_shgroup_get_next(DRWShadingGroup *shgroup) +void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, + eGPUFrameBufferBits channels, + uchar r, + uchar g, + uchar b, + uchar a, + float depth, + uchar stencil) { - return shgroup->next; + drw_command_clear(shgroup, channels, r, g, b, a, depth, stencil); } -/* This is a workaround function waiting for the clearing operation to be available inside the - * shgroups. */ -uint DRW_shgroup_stencil_mask_get(DRWShadingGroup *shgroup) +bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) { - return shgroup->stencil_mask; + DRWCommandChunk *chunk = shgroup->cmd.first; + for (; chunk; chunk = chunk->next) { + for (int i = 0; i < chunk->command_used; i++) { + if (command_type_get(chunk->command_type, i) <= DRW_MAX_DRAW_CMD_TYPE) { + return false; + } + } + } + return true; } DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) @@ -1023,11 +1304,14 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups); *shgroup_new = *shgroup; - shgroup_new->uniforms = NULL; - shgroup_new->calls.first = NULL; - shgroup_new->calls.last = NULL; + drw_shgroup_init(shgroup_new, shgroup_new->shader); + shgroup_new->cmd.first = NULL; + shgroup_new->cmd.last = NULL; + + DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes, + &shgroup->pass_handle); - BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new); + BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new); return shgroup_new; } @@ -1522,6 +1806,8 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) pass->shgroups.first = NULL; pass->shgroups.last = NULL; + pass->handle = DST.pass_handle; + DRW_handle_increment(&DST.pass_handle); return pass; } @@ -1560,47 +1846,22 @@ void DRW_pass_foreach_shgroup(DRWPass *pass, } } -typedef struct ZSortData { - const float *axis; - const float *origin; -} ZSortData; - -static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) +static int pass_shgroup_dist_sort(const void *a, const void *b) { - const ZSortData *zsortdata = (ZSortData *)thunk; const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a; const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b; - const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first; - const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first; - - if (call_a == NULL) { - return -1; - } - if (call_b == NULL) { - return -1; - } - - float tmp[3]; - sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]); - const float a_sq = dot_v3v3(zsortdata->axis, tmp); - sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]); - const float b_sq = dot_v3v3(zsortdata->axis, tmp); - - if (a_sq < b_sq) { + if (shgrp_a->z_sorting.distance < shgrp_b->z_sorting.distance) { return 1; } - else if (a_sq > b_sq) { + else if (shgrp_a->z_sorting.distance > shgrp_b->z_sorting.distance) { return -1; } else { - /* If there is a depth prepass put it before */ - if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { + /* If distances are the same, keep original order. */ + if (shgrp_a->z_sorting.original_index > shgrp_b->z_sorting.original_index) { return -1; } - else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { - return 1; - } else { return 0; } @@ -1611,35 +1872,61 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) #define SORT_IMPL_LINKTYPE DRWShadingGroup -#define SORT_IMPL_USE_THUNK #define SORT_IMPL_FUNC shgroup_sort_fn_r #include "../../blenlib/intern/list_sort_impl.h" #undef SORT_IMPL_FUNC -#undef SORT_IMPL_USE_THUNK #undef SORT_IMPL_LINKTYPE /** * Sort Shading groups by decreasing Z of their first draw call. - * This is useful for order dependent effect such as transparency. + * This is useful for order dependent effect such as alpha-blending. */ void DRW_pass_sort_shgroup_z(DRWPass *pass) { const float(*viewinv)[4] = DST.view_active->storage.viewinv; - ZSortData zsortdata = {viewinv[2], viewinv[3]}; - - if (pass->shgroups.first && pass->shgroups.first->next) { - pass->shgroups.first = shgroup_sort_fn_r( - pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata); + if (!(pass->shgroups.first && pass->shgroups.first->next)) { + /* Nothing to sort */ + return; + } - /* Find the next last */ - DRWShadingGroup *last = pass->shgroups.first; - while ((last = last->next)) { - /* Do nothing */ + uint index = 0; + DRWShadingGroup *shgroup = pass->shgroups.first; + do { + DRWResourceHandle handle = 0; + /* Find first DRWCommandDraw. */ + DRWCommandChunk *cmd_chunk = shgroup->cmd.first; + for (; cmd_chunk && handle == 0; cmd_chunk = cmd_chunk->next) { + for (int i = 0; i < cmd_chunk->command_used && handle == 0; i++) { + if (DRW_CMD_DRAW == command_type_get(cmd_chunk->command_type, i)) { + handle = cmd_chunk->commands[i].draw.handle; + } + } } - pass->shgroups.last = last; + /* To be sorted a shgroup needs to have at least one draw command. */ + BLI_assert(handle != 0); + + DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle); + + /* Compute distance to camera. */ + float tmp[3]; + sub_v3_v3v3(tmp, viewinv[3], obmats->model[3]); + shgroup->z_sorting.distance = dot_v3v3(viewinv[2], tmp); + shgroup->z_sorting.original_index = index++; + + } while ((shgroup = shgroup->next)); + + /* Sort using computed distances. */ + pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort); + + /* Find the new last */ + DRWShadingGroup *last = pass->shgroups.first; + while ((last = last->next)) { + /* Reset the pass id for debugging. */ + last->pass_handle = pass->handle; } + pass->shgroups.last = last; } /** \} */ diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 1dcaf39fc19..fa7c44c1b1f 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -29,6 +29,7 @@ #include "BKE_global.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "intern/gpu_shader_private.h" #include "intern/gpu_primitive_private.h" @@ -36,16 +37,41 @@ # include "GPU_select.h" #endif -#ifdef USE_GPU_SELECT void DRW_select_load_id(uint id) { +#ifdef USE_GPU_SELECT BLI_assert(G.f & G_FLAG_PICKSEL); DST.select_id = id; -} #endif +} #define DEBUG_UBO_BINDING +typedef struct DRWCommandsState { + GPUBatch *batch; + int resource_chunk; + int base_inst; + int inst_count; + int v_first; + int v_count; + bool neg_scale; + /* Resource location. */ + int obmats_loc; + int obinfos_loc; + int baseinst_loc; + int chunkid_loc; + /* Legacy matrix support. */ + int obmat_loc; + int obinv_loc; + int mvp_loc; + /* Selection ID state. */ + GPUVertBuf *select_buf; + uint select_id; + /* Drawing State */ + DRWState drw_state_enabled; + DRWState drw_state_disabled; +} DRWCommandsState; + /* -------------------------------------------------------------------- */ /** \name Draw State (DRW_state) * \{ */ @@ -407,9 +433,10 @@ void DRW_state_reset(void) /** \name Culling (DRW_culling) * \{ */ -static bool draw_call_is_culled(DRWCall *call, DRWView *view) +static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view) { - return (call->state->culling->mask & view->culling_mask) != 0; + DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle); + return (culling->mask & view->culling_mask) != 0; } /* Set active view for rendering. */ @@ -588,66 +615,96 @@ static void draw_compute_culling(DRWView *view) /** \name Draw (DRW_draw) * \{ */ -static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call) +BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup, + DRWResourceHandle *handle, + float obmat_loc, + float obinv_loc, + float mvp_loc) { - BLI_assert(call); - DRWCallState *state = call->state; - - if (shgroup->model != -1) { - GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model); - } - if (shgroup->modelinverse != -1) { - GPU_shader_uniform_vector( - shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse); - } - if (shgroup->objectinfo != -1) { - float infos[4]; - infos[0] = state->ob_index; - // infos[1]; /* UNUSED. */ - infos[2] = state->ob_random; - infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f; - GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos); - } - if (shgroup->objectcolor != -1) { - GPU_shader_uniform_vector( - shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color); + /* Still supported for compatibility with gpu_shader_* but should be forbidden. */ + DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle); + if (obmat_loc != -1) { + GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model); } - if (shgroup->orcotexfac != -1) { - GPU_shader_uniform_vector( - shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac); + if (obinv_loc != -1) { + GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse); } /* Still supported for compatibility with gpu_shader_* but should be forbidden * and is slow (since it does not cache the result). */ - if (shgroup->modelviewprojection != -1) { + if (mvp_loc != -1) { float mvp[4][4]; - mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model); - GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp); + mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model); + GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp); } } +BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom) +{ + /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */ + if (DST.batch) { + DST.batch->program_in_use = false; + } + + DST.batch = geom; + + GPU_batch_program_set_no_use( + geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); + + geom->program_in_use = true; /* XXX hacking #GPUBatch */ + + GPU_batch_bind(geom); +} + BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup, GPUBatch *geom, - uint vert_first, - uint vert_count, - uint inst_first, - uint inst_count) + int vert_first, + int vert_count, + int inst_first, + int inst_count, + int baseinst_loc) { + /* inst_count can be -1. */ + inst_count = max_ii(0, inst_count); + + if (baseinst_loc != -1) { + /* Fallback when ARB_shader_draw_parameters is not supported. */ + GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first); + /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */ + inst_first = 0; + } + /* bind vertex array */ if (DST.batch != geom) { - DST.batch = geom; - - GPU_batch_program_set_no_use( - geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); - - GPU_batch_bind(geom); + draw_geometry_bind(shgroup, geom); } - /* XXX hacking #GPUBatch. we don't want to call glUseProgram! (huge performance loss) */ - geom->program_in_use = true; - GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count); +} - geom->program_in_use = false; /* XXX hacking #GPUBatch */ +BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state) +{ + if (state->inst_count == 0) { + return; + } + if (state->baseinst_loc == -1) { + /* bind vertex array */ + if (DST.batch != state->batch) { + GPU_draw_list_submit(DST.draw_list); + draw_geometry_bind(shgroup, state->batch); + } + GPU_draw_list_command_add( + DST.draw_list, state->v_first, state->v_count, state->base_inst, state->inst_count); + } + /* Fallback when unsupported */ + else { + draw_geometry_execute(shgroup, + state->batch, + state->v_first, + state->v_count, + state->base_inst, + state->inst_count, + state->baseinst_loc); + } } enum { @@ -719,6 +776,9 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) /* UBO isn't bound yet. Find an empty slot and bind it. */ idx = get_empty_slot_index(DST.RST.bound_ubo_slots); + /* [0..1] are reserved ubo slots. */ + idx += 2; + if (idx < GPU_max_ubo_binds()) { GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx]; /* Unbind any previous UBO. */ @@ -738,10 +798,13 @@ static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) } } else { + BLI_assert(idx < 64); /* This UBO slot was released but the UBO is * still bound here. Just flag the slot again. */ BLI_assert(DST.RST.bound_ubos[idx] == ubo); } + /* Remove offset for flag bitfield. */ + idx -= 2; set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type); } @@ -785,8 +848,12 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup) printf("Trying to draw with missing UBO binding.\n"); valid = false; } + + DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes, + &shgroup->pass_handle); + printf("Pass : %s, Shader : %s, Block : %s\n", - shgroup->pass_parent->name, + parent_pass->name, shgroup->shader->name, blockname); } @@ -818,119 +885,331 @@ static void release_ubo_slots(bool with_persist) } } -static void draw_update_uniforms(DRWShadingGroup *shgroup) +static void draw_update_uniforms(DRWShadingGroup *shgroup, + DRWCommandsState *state, + bool *use_tfeedback) { - for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) { - GPUTexture *tex; - GPUUniformBuffer *ubo; - if (uni->location == -2) { - uni->location = GPU_shader_get_uniform_ensure(shgroup->shader, - DST.uniform_names.buffer + uni->name_ofs); - if (uni->location == -1) { - continue; + for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) { + DRWUniform *uni = unichunk->uniforms; + for (int i = 0; i < unichunk->uniform_used; i++, uni++) { + GPUTexture *tex; + GPUUniformBuffer *ubo; + if (uni->location == -2) { + uni->location = GPU_shader_get_uniform_ensure(shgroup->shader, + DST.uniform_names.buffer + uni->name_ofs); + if (uni->location == -1) { + continue; + } + } + const void *data = uni->pvalue; + if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) { + data = uni->fvalue; + } + switch (uni->type) { + case DRW_UNIFORM_INT_COPY: + case DRW_UNIFORM_INT: + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, data); + break; + case DRW_UNIFORM_FLOAT_COPY: + case DRW_UNIFORM_FLOAT: + GPU_shader_uniform_vector( + shgroup->shader, uni->location, uni->length, uni->arraysize, data); + break; + case DRW_UNIFORM_TEXTURE: + tex = (GPUTexture *)uni->pvalue; + BLI_assert(tex); + bind_texture(tex, BIND_TEMP); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_TEXTURE_PERSIST: + tex = (GPUTexture *)uni->pvalue; + BLI_assert(tex); + bind_texture(tex, BIND_PERSIST); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_TEXTURE_REF: + tex = *((GPUTexture **)uni->pvalue); + BLI_assert(tex); + bind_texture(tex, BIND_TEMP); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_BLOCK: + ubo = (GPUUniformBuffer *)uni->pvalue; + bind_ubo(ubo, BIND_TEMP); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_BLOCK_PERSIST: + ubo = (GPUUniformBuffer *)uni->pvalue; + bind_ubo(ubo, BIND_PERSIST); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_BLOCK_OBMATS: + state->obmats_loc = uni->location; + ubo = DST.vmempool->matrices_ubo[0]; + GPU_uniformbuffer_bind(ubo, 0); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_BLOCK_OBINFOS: + state->obinfos_loc = uni->location; + ubo = DST.vmempool->obinfos_ubo[0]; + GPU_uniformbuffer_bind(ubo, 1); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_RESOURCE_CHUNK: + state->chunkid_loc = uni->location; + GPU_shader_uniform_int(shgroup->shader, uni->location, 0); + break; + case DRW_UNIFORM_TFEEDBACK_TARGET: + BLI_assert(data && (*use_tfeedback == false)); + *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, + ((GPUVertBuf *)data)->vbo_id); + break; + /* Legacy/Fallback support. */ + case DRW_UNIFORM_BASE_INSTANCE: + state->baseinst_loc = uni->location; + break; + case DRW_UNIFORM_MODEL_MATRIX: + state->obmat_loc = uni->location; + break; + case DRW_UNIFORM_MODEL_MATRIX_INVERSE: + state->obinv_loc = uni->location; + break; + case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX: + state->mvp_loc = uni->location; + break; } - } - const void *data = uni->pvalue; - if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) { - data = uni->fvalue; - } - switch (uni->type) { - case DRW_UNIFORM_INT_COPY: - case DRW_UNIFORM_INT: - GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); - break; - case DRW_UNIFORM_FLOAT_COPY: - case DRW_UNIFORM_FLOAT: - GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, data); - break; - case DRW_UNIFORM_TEXTURE: - tex = (GPUTexture *)uni->pvalue; - BLI_assert(tex); - bind_texture(tex, BIND_TEMP); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_TEXTURE_PERSIST: - tex = (GPUTexture *)uni->pvalue; - BLI_assert(tex); - bind_texture(tex, BIND_PERSIST); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_TEXTURE_REF: - tex = *((GPUTexture **)uni->pvalue); - BLI_assert(tex); - bind_texture(tex, BIND_TEMP); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_BLOCK: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_TEMP); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); - break; - case DRW_UNIFORM_BLOCK_PERSIST: - ubo = (GPUUniformBuffer *)uni->pvalue; - bind_ubo(ubo, BIND_PERSIST); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); - break; } } BLI_assert(ubo_bindings_validate(shgroup)); } -BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call) +BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup, + DRWCommandsState *state, + GPUBatch *batch, + const DRWResourceHandle *handle) { -#ifdef USE_GPU_SELECT - if ((G.f & G_FLAG_PICKSEL) == 0) { - return false; + const bool is_instancing = (batch->inst != NULL); + int start = 0; + int count = 1; + int tot = is_instancing ? batch->inst->vertex_len : batch->verts[0]->vertex_len; + /* Hack : get "vbo" data without actually drawing. */ + int *select_id = (void *)state->select_buf->data; + + /* Batching */ + if (!is_instancing) { + /* FIXME: Meh a bit nasty. */ + if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) { + count = 3; + } + else if (batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) { + count = 2; + } } - if (call->inst_selectid != NULL) { - const bool is_instancing = (call->inst_count != 0); - uint start = 0; - uint count = 1; - uint tot = is_instancing ? call->inst_count : call->vert_count; - /* Hack : get vbo data without actually drawing. */ - GPUVertBufRaw raw; - GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw); - int *select_id = GPU_vertbuf_raw_step(&raw); - - /* Batching */ - if (!is_instancing) { - /* FIXME: Meh a bit nasty. */ - if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) { - count = 3; - } - else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) { - count = 2; - } + + while (start < tot) { + GPU_select_load_id(select_id[start]); + if (is_instancing) { + draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc); } + else { + draw_geometry_execute( + shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc); + } + start += count; + } +} - while (start < tot) { - GPU_select_load_id(select_id[start]); - if (is_instancing) { - draw_geometry_execute(shgroup, call->batch, 0, 0, start, count); - } - else { - draw_geometry_execute(shgroup, call->batch, start, count, 0, 0); +typedef struct DRWCommandIterator { + int cmd_index; + DRWCommandChunk *curr_chunk; +} DRWCommandIterator; + +static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup) +{ + iter->curr_chunk = shgroup->cmd.first; + iter->cmd_index = 0; +} + +static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type) +{ + if (iter->curr_chunk) { + if (iter->cmd_index == iter->curr_chunk->command_len) { + iter->curr_chunk = iter->curr_chunk->next; + iter->cmd_index = 0; + } + if (iter->curr_chunk) { + *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index); + if (iter->cmd_index < iter->curr_chunk->command_used) { + return iter->curr_chunk->commands + iter->cmd_index++; } - start += count; } - return true; } + return NULL; +} + +static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle) +{ + /* Front face is not a resource but it is inside the resource handle. */ + bool neg_scale = DRW_handle_negative_scale_get(handle); + if (neg_scale != state->neg_scale) { + glFrontFace((neg_scale) ? GL_CW : GL_CCW); + state->neg_scale = neg_scale; + } + + int chunk = DRW_handle_chunk_get(handle); + if (state->resource_chunk != chunk) { + if (state->chunkid_loc != -1) { + GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk); + } + if (state->obmats_loc != -1) { + GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); + GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0); + } + if (state->obinfos_loc != -1) { + GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]); + GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1); + } + state->resource_chunk = chunk; + } +} + +static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state) +{ + draw_indirect_call(shgroup, state); + GPU_draw_list_submit(DST.draw_list); + + state->batch = NULL; + state->inst_count = 0; + state->base_inst = -1; +} + +static void draw_call_single_do(DRWShadingGroup *shgroup, + DRWCommandsState *state, + GPUBatch *batch, + DRWResourceHandle handle, + int vert_first, + int vert_count, + int inst_count) +{ + draw_call_batching_flush(shgroup, state); + + draw_call_resource_bind(state, &handle); + + /* TODO This is Legacy. Need to be removed. */ + if (state->obmats_loc == -1 && + (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) { + draw_legacy_matrix_update( + shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc); + } + + if (G.f & G_FLAG_PICKSEL) { + if (state->select_buf != NULL) { + draw_select_buffer(shgroup, state, batch, &handle); + return; + } + else { + GPU_select_load_id(state->select_id); + } + } + + draw_geometry_execute(shgroup, + batch, + vert_first, + vert_count, + DRW_handle_id_get(&handle), + inst_count, + state->baseinst_loc); +} + +static void draw_call_batching_start(DRWCommandsState *state) +{ + state->neg_scale = false; + state->resource_chunk = 0; + state->base_inst = 0; + state->inst_count = 0; + state->v_first = 0; + state->v_count = 0; + state->batch = NULL; + + state->select_id = -1; + state->select_buf = NULL; +} + +/* NOTE: Does not support batches with instancing VBOs. */ +static void draw_call_batching_do(DRWShadingGroup *shgroup, + DRWCommandsState *state, + DRWCommandDraw *call) +{ + /* If any condition requires to interupt the merging. */ + bool neg_scale = DRW_handle_negative_scale_get(&call->handle); + int chunk = DRW_handle_chunk_get(&call->handle); + int id = DRW_handle_id_get(&call->handle); + if ((state->neg_scale != neg_scale) || /* Need to change state. */ + (state->resource_chunk != chunk) || /* Need to change UBOs. */ + (state->batch != call->batch) /* Need to change VAO. */ + ) { + draw_call_batching_flush(shgroup, state); + + state->batch = call->batch; + state->v_first = (call->batch->elem) ? call->batch->elem->index_start : 0; + state->v_count = (call->batch->elem) ? call->batch->elem->index_len : + call->batch->verts[0]->vertex_len; + state->inst_count = 1; + state->base_inst = id; + + draw_call_resource_bind(state, &call->handle); + + GPU_draw_list_init(DST.draw_list, state->batch); + } + /* Is the id consecutive? */ + else if (id != state->base_inst + state->inst_count) { + /* We need to add a draw command for the pending instances. */ + draw_indirect_call(shgroup, state); + state->inst_count = 1; + state->base_inst = id; + } + /* We avoid a drawcall by merging with the precedent + * drawcall using instancing. */ else { - GPU_select_load_id(call->select_id); - return false; + state->inst_count++; + } +} + +/* Flush remaining pending drawcalls. */ +static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state) +{ + draw_call_batching_flush(shgroup, state); + + /* Reset state */ + if (state->neg_scale) { + glFrontFace(GL_CCW); + } + if (state->obmats_loc != -1) { + GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); + } + if (state->obinfos_loc != -1) { + GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]); } -#else - return false; -#endif } static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) { BLI_assert(shgroup->shader); + DRWCommandsState state = { + .obmats_loc = -1, + .obinfos_loc = -1, + .baseinst_loc = -1, + .chunkid_loc = -1, + .obmat_loc = -1, + .obinv_loc = -1, + .mvp_loc = -1, + .drw_state_enabled = 0, + .drw_state_disabled = 0, + }; + const bool shader_changed = (DST.shader != shgroup->shader); bool use_tfeedback = false; @@ -940,56 +1219,116 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } GPU_shader_bind(shgroup->shader); DST.shader = shgroup->shader; + /* XXX hacking gawain */ + if (DST.batch) { + DST.batch->program_in_use = false; + } DST.batch = NULL; } - if (shgroup->tfeedback_target != NULL) { - use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, - shgroup->tfeedback_target->vbo_id); - } - release_ubo_slots(shader_changed); release_texture_slots(shader_changed); - drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); - drw_stencil_set(shgroup->stencil_mask); + draw_update_uniforms(shgroup, &state, &use_tfeedback); - draw_update_uniforms(shgroup); + drw_state_set(pass_state); /* Rendering Calls */ { - bool prev_neg_scale = false; - int callid = 0; - for (DRWCall *call = shgroup->calls.first; call; call = call->next) { - - if (draw_call_is_culled(call, DST.view_active)) { - continue; + DRWCommandIterator iter; + DRWCommand *cmd; + eDRWCommandType cmd_type; + + draw_command_iter_begin(&iter, shgroup); + + draw_call_batching_start(&state); + + while ((cmd = draw_command_iter_step(&iter, &cmd_type))) { + + switch (cmd_type) { + case DRW_CMD_DRWSTATE: + case DRW_CMD_STENCIL: + draw_call_batching_flush(shgroup, &state); + break; + case DRW_CMD_DRAW: + case DRW_CMD_DRAW_PROCEDURAL: + case DRW_CMD_DRAW_INSTANCE: + if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) { + continue; + } + break; + default: + break; } - /* XXX small exception/optimisation for outline rendering. */ - if (shgroup->callid != -1) { - GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid); - callid += 1; - } - - /* Negative scale objects */ - bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE; - if (neg_scale != prev_neg_scale) { - glFrontFace((neg_scale) ? GL_CW : GL_CCW); - prev_neg_scale = neg_scale; - } - - draw_geometry_prepare(shgroup, call); - - if (draw_select_do_call(shgroup, call)) { - continue; + switch (cmd_type) { + case DRW_CMD_CLEAR: + GPU_framebuffer_clear( +#ifndef NDEBUG + GPU_framebuffer_active_get(), +#else + NULL, +#endif + cmd->clear.clear_channels, + (float[4]){cmd->clear.r / 255.0f, + cmd->clear.g / 255.0f, + cmd->clear.b / 255.0f, + cmd->clear.a / 255.0f}, + cmd->clear.depth, + cmd->clear.stencil); + break; + case DRW_CMD_DRWSTATE: + state.drw_state_enabled |= cmd->state.enable; + state.drw_state_disabled |= cmd->state.disable; + drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled); + break; + case DRW_CMD_STENCIL: + drw_stencil_set(cmd->stencil.mask); + break; + case DRW_CMD_SELECTID: + state.select_id = cmd->select_id.select_id; + state.select_buf = cmd->select_id.select_buf; + break; + case DRW_CMD_DRAW: + if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) || + cmd->draw.batch->inst) { + draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0); + } + else { + draw_call_batching_do(shgroup, &state, &cmd->draw); + } + break; + case DRW_CMD_DRAW_PROCEDURAL: + draw_call_single_do(shgroup, + &state, + cmd->procedural.batch, + cmd->procedural.handle, + 0, + cmd->procedural.vert_count, + 1); + break; + case DRW_CMD_DRAW_INSTANCE: + draw_call_single_do(shgroup, + &state, + cmd->instance.batch, + cmd->instance.handle, + 0, + 0, + cmd->instance.inst_count); + break; + case DRW_CMD_DRAW_RANGE: + draw_call_single_do(shgroup, + &state, + cmd->range.batch, + (DRWResourceHandle)0, + cmd->range.vert_first, + cmd->range.vert_count, + 1); + break; } - - draw_geometry_execute( - shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count); } - /* Reset state */ - glFrontFace(GL_CCW); + + draw_call_batching_finish(shgroup, &state); } if (use_tfeedback) { @@ -1065,6 +1404,17 @@ static void drw_draw_pass_ex(DRWPass *pass, DST.shader = NULL; } + if (DST.batch) { + DST.batch->program_in_use = false; + DST.batch = NULL; + } + + /* Fix T67342 for some reason. AMD Pro driver bug. */ + if ((DST.state & DRW_STATE_BLEND_CUSTOM) != 0 && + GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) { + drw_state_set(DST.state & ~DRW_STATE_BLEND_CUSTOM); + } + /* HACK: Rasterized discard can affect clear commands which are not * part of a DRWPass (as of now). So disable rasterized discard here * if it has been enabled. */ diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 7aa2e007f79..58643eb12a8 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -41,11 +41,9 @@ #include "BKE_object.h" #include "BKE_paint.h" -#include "DRW_render.h" - #include "view3d_intern.h" -#include "draw_view.h" +#include "draw_manager.h" /* ******************** region info ***************** */ @@ -60,18 +58,17 @@ void DRW_draw_region_info(void) } /* ************************* Background ************************** */ +void DRW_clear_background() +{ + GPU_clear_color(0.0, 0.0, 0.0, 0.0); + GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT); +} void DRW_draw_background(bool do_alpha_checker) { - /* Just to make sure */ - glDepthMask(GL_TRUE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0xFF); - + drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL); if (do_alpha_checker) { /* Transparent render, do alpha checker. */ - GPU_depth_test(false); - GPU_matrix_push(); GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); @@ -79,18 +76,11 @@ void DRW_draw_background(bool do_alpha_checker) imm_draw_box_checker_2d(-1.0f, -1.0f, 1.0f, 1.0f); GPU_matrix_pop(); - - GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT); - - GPU_depth_test(true); } - else if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + else { float m[4][4]; unit_m4(m); - /* Gradient background Color */ - GPU_depth_test(false); - GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); uint color = GPU_vertformat_attr_add( @@ -103,8 +93,8 @@ void DRW_draw_background(bool do_alpha_checker) immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR_DITHER); - UI_GetThemeColor3ubv(TH_BACK_GRAD, col_lo); UI_GetThemeColor3ubv(TH_BACK, col_hi); + UI_GetThemeColor3ubv(UI_GetThemeValue(TH_SHOW_BACK_GRAD) ? TH_BACK_GRAD : TH_BACK, col_lo); immBegin(GPU_PRIM_TRI_FAN, 4); immAttr3ubv(color, col_lo); @@ -119,16 +109,6 @@ void DRW_draw_background(bool do_alpha_checker) immUnbindProgram(); GPU_matrix_pop(); - - GPU_clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT); - - GPU_depth_test(true); - } - else { - /* Solid background Color */ - UI_ThemeClearColorAlpha(TH_BACK, 1.0f); - - GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT); } } diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h index 715c3c0d40c..7be186f1c72 100644 --- a/source/blender/draw/intern/draw_view.h +++ b/source/blender/draw/intern/draw_view.h @@ -24,6 +24,7 @@ #define __DRAW_VIEW_H__ void DRW_draw_region_info(void); +void DRW_clear_background(void); void DRW_draw_background(bool do_alpha_checker); void DRW_draw_cursor(void); void DRW_draw_gizmo_3d(void); diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index e68e03c2438..afaaba0712f 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -126,7 +126,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) datatoc_edit_curve_overlay_normals_vert_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, NULL}, + .defs = (const char *[]){sh_cfg_data->def, "#define IN_PLACE_INSTANCES\n", NULL}, }); } @@ -270,7 +270,7 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) geom = DRW_cache_curve_edge_wire_get(ob); if (geom) { - DRW_shgroup_call(wire_shgrp, geom, ob); + DRW_shgroup_call_no_cull(wire_shgrp, geom, ob); } if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) { @@ -280,12 +280,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) geom = DRW_cache_curve_edge_overlay_get(ob); if (geom) { - DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob); + DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob); } geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles); if (geom) { - DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob); + DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob); } } } @@ -294,12 +294,12 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) if (BKE_object_is_in_editmode(ob)) { struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob); if (geom) { - DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob); + DRW_shgroup_call_no_cull(stl->g_data->overlay_edge_shgrp, geom, ob); } geom = DRW_cache_curve_vert_overlay_get(ob, false); if (geom) { - DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob); + DRW_shgroup_call_no_cull(stl->g_data->overlay_vert_shgrp, geom, ob); } } } diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index 83a271a3ccd..9957dbae3fb 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -55,6 +55,7 @@ extern char datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl[]; extern char datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl[]; extern char datatoc_edit_normals_vert_glsl[]; extern char datatoc_edit_normals_geom_glsl[]; +extern char datatoc_edit_mesh_skin_root_vert_glsl[]; extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; @@ -89,7 +90,6 @@ typedef struct EDIT_MESH_PassList { typedef struct EDIT_MESH_FramebufferList { struct GPUFrameBuffer *occlude_wire_fb; - struct GPUFrameBuffer *ghost_wire_fb; } EDIT_MESH_FramebufferList; typedef struct EDIT_MESH_StorageList { @@ -104,8 +104,6 @@ typedef struct EDIT_MESH_Data { EDIT_MESH_StorageList *stl; } EDIT_MESH_Data; -#define MAX_SHADERS 16 - /** Can only contain shaders (freed as array). */ typedef struct EDIT_MESH_Shaders { /* weight */ @@ -117,6 +115,7 @@ typedef struct EDIT_MESH_Shaders { GPUShader *overlay_edge_flat; GPUShader *overlay_face; GPUShader *overlay_facedot; + GPUShader *overlay_skin_root; GPUShader *overlay_mix; GPUShader *overlay_facefill; @@ -144,6 +143,7 @@ typedef struct EDIT_MESH_ComponentShadingGroupList { DRWShadingGroup *faces; DRWShadingGroup *faces_cage; DRWShadingGroup *facedots; + DRWShadingGroup *skin_roots; } EDIT_MESH_ComponentShadingGroupList; typedef struct EDIT_MESH_PrivateData { @@ -159,12 +159,6 @@ typedef struct EDIT_MESH_PrivateData { EDIT_MESH_ComponentShadingGroupList edit_shgrps; EDIT_MESH_ComponentShadingGroupList edit_in_front_shgrps; - DRWShadingGroup *vert_shgrp_in_front; - DRWShadingGroup *edge_shgrp_in_front; - DRWShadingGroup *face_shgrp_in_front; - DRWShadingGroup *face_cage_shgrp_in_front; - DRWShadingGroup *facedot_shgrp_in_front; - DRWShadingGroup *facefill_occluded_shgrp; DRWShadingGroup *facefill_occluded_cage_shgrp; DRWShadingGroup *mesh_analysis_shgrp; @@ -275,6 +269,12 @@ static void EDIT_MESH_engine_init(void *vedata) .frag = (const char *[]){lib, datatoc_edit_mesh_overlay_facefill_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); + sh_data->overlay_skin_root = GPU_shader_create_from_arrays({ + .vert = (const char *[]){lib, datatoc_edit_mesh_skin_root_vert_glsl, NULL}, + .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg_data->def, NULL}, + }); + MEM_freeN(lib); sh_data->overlay_mix = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl, @@ -350,6 +350,7 @@ static void edit_mesh_create_overlay_passes(float face_alpha, GPUShader *edge_sh = (select_vert) ? sh_data->overlay_edge : sh_data->overlay_edge_flat; GPUShader *face_sh = sh_data->overlay_face; GPUShader *facedot_sh = sh_data->overlay_facedot; + GPUShader *skin_root_sh = sh_data->overlay_skin_root; /* Faces */ passes->faces = DRW_pass_create("Edit Mesh Faces", DRW_STATE_WRITE_COLOR | statemod); @@ -397,6 +398,10 @@ static void edit_mesh_create_overlay_passes(float face_alpha, if (rv3d->rflag & RV3D_CLIPPING) { DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES); } + + grp = shgrps->skin_roots = DRW_shgroup_create(skin_root_sh, passes->verts); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); } if (select_face) { grp = shgrps->facedots = DRW_shgroup_create(facedot_sh, passes->verts); @@ -641,21 +646,24 @@ static void EDIT_MESH_cache_init(void *vedata) static void edit_mesh_add_ob_to_pass(Scene *scene, Object *ob, + DRWShadingGroup *skin_roots_shgrp, DRWShadingGroup *vert_shgrp, DRWShadingGroup *edge_shgrp, DRWShadingGroup *face_shgrp, DRWShadingGroup *face_cage_shgrp, DRWShadingGroup *facedot_shgrp) { - struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter; + struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots; ToolSettings *tsettings = scene->toolsettings; bool has_edit_mesh_cage = false; + bool has_skin_roots = false; /* TODO: Should be its own function. */ Mesh *me = (Mesh *)ob->data; BMEditMesh *embm = me->edit_mesh; if (embm) { has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final); + has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1; } face_shgrp = (has_edit_mesh_cage) ? face_cage_shgrp : face_shgrp; @@ -668,6 +676,21 @@ static void edit_mesh_add_ob_to_pass(Scene *scene, if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) { geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data); DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob); + + if (has_skin_roots) { + DRWShadingGroup *grp = DRW_shgroup_create_sub(skin_roots_shgrp); + /* We need to upload the matrix. But the ob can be temporary allocated so we cannot + * use direct reference to ob->obmat. */ + DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[0]", ob->obmat[0]); + DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[1]", ob->obmat[1]); + DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[2]", ob->obmat[2]); + DRW_shgroup_uniform_vec4_copy(grp, "editModelMat[3]", ob->obmat[3]); + + skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data); + /* NOTE(fclem) We cannot use ob here since it would offset the instance attribs with + * base instance offset. */ + DRW_shgroup_call(grp, skin_roots, NULL); + } } if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0) { @@ -730,6 +753,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) if (g_data->do_zbufclip) { edit_mesh_add_ob_to_pass(scene, ob, + g_data->edit_shgrps.skin_roots, g_data->edit_shgrps.verts, g_data->edit_shgrps.edges, g_data->facefill_occluded_shgrp, @@ -739,6 +763,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) else if (do_in_front) { edit_mesh_add_ob_to_pass(scene, ob, + g_data->edit_in_front_shgrps.skin_roots, g_data->edit_in_front_shgrps.verts, g_data->edit_in_front_shgrps.edges, g_data->edit_in_front_shgrps.faces, @@ -748,6 +773,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) else { edit_mesh_add_ob_to_pass(scene, ob, + g_data->edit_shgrps.skin_roots, g_data->edit_shgrps.verts, g_data->edit_shgrps.edges, g_data->edit_shgrps.faces, diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index ba5ecb143ae..70bccb4849c 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -122,8 +122,9 @@ typedef struct OBJECT_PassList { struct DRWPass *bone_axes[2]; struct DRWPass *particle; struct DRWPass *lightprobes; - struct DRWPass *camera_images_back; - struct DRWPass *camera_images_front; + struct DRWPass *camera_images_back_alpha_under; + struct DRWPass *camera_images_back_alpha_over; + struct DRWPass *camera_images_front_alpha_over; } OBJECT_PassList; typedef struct OBJECT_FramebufferList { @@ -286,15 +287,10 @@ typedef struct OBJECT_PrivateData { DRWShadingGroup *outlines_transform; /* Lightprobes */ - DRWCallBuffer *lightprobes_cube_select; - DRWCallBuffer *lightprobes_cube_select_dupli; - DRWCallBuffer *lightprobes_cube_active; - DRWCallBuffer *lightprobes_cube_transform; - - DRWCallBuffer *lightprobes_planar_select; - DRWCallBuffer *lightprobes_planar_select_dupli; - DRWCallBuffer *lightprobes_planar_active; - DRWCallBuffer *lightprobes_planar_transform; + DRWShadingGroup *probe_outlines_transform; + DRWShadingGroup *probe_outlines_select; + DRWShadingGroup *probe_outlines_select_dupli; + DRWShadingGroup *probe_outlines_active; /* Objects Centers */ DRWCallBuffer *center_active; @@ -303,17 +299,6 @@ typedef struct OBJECT_PrivateData { DRWCallBuffer *center_selected_lib; DRWCallBuffer *center_deselected_lib; - /* Outlines id offset (accessed as an array) */ - int id_ofs_active; - int id_ofs_select; - int id_ofs_select_dupli; - int id_ofs_transform; - - int id_ofs_prb_active; - int id_ofs_prb_select; - int id_ofs_prb_select_dupli; - int id_ofs_prb_transform; - bool xray_enabled; bool xray_enabled_and_not_wire; } OBJECT_PrivateData; /* Transient data */ @@ -417,7 +402,10 @@ static void OBJECT_engine_init(void *vedata) if (!sh_data->outline_resolve) { /* Outline */ sh_data->outline_prepass = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_gpu_shader_3D_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_object_outline_prepass_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -431,7 +419,7 @@ static void OBJECT_engine_init(void *vedata) datatoc_object_outline_prepass_geom_glsl, NULL}, .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg_data->def, NULL}, + .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL}, }); sh_data->outline_resolve = DRW_shader_create_fullscreen( @@ -539,10 +527,11 @@ static void OBJECT_engine_init(void *vedata) /* Lightprobes */ sh_data->lightprobe_grid = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, datatoc_common_globals_lib_glsl, datatoc_object_lightprobe_grid_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_flat_id_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -697,12 +686,12 @@ static void OBJECT_engine_free(void) } static DRWShadingGroup *shgroup_outline(DRWPass *pass, - const int *ofs, + int outline_id, GPUShader *sh, eGPUShaderConfig sh_cfg) { DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - DRW_shgroup_uniform_int(grp, "baseId", ofs, 1); + DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES); @@ -741,128 +730,89 @@ static DRWShadingGroup *shgroup_points(DRWPass *pass, return grp; } -static int *shgroup_theme_id_to_probe_outline_counter(OBJECT_StorageList *stl, - int theme_id, - const int base_flag) -{ - if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) { - switch (theme_id) { - case TH_ACTIVE: - case TH_SELECT: - return &stl->g_data->id_ofs_prb_select_dupli; - case TH_TRANSFORM: - default: - return &stl->g_data->id_ofs_prb_transform; - } - } - - switch (theme_id) { - case TH_ACTIVE: - return &stl->g_data->id_ofs_prb_active; - case TH_SELECT: - return &stl->g_data->id_ofs_prb_select; - case TH_TRANSFORM: - default: - return &stl->g_data->id_ofs_prb_transform; - } -} - -static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl, - int theme_id, - const int base_flag) +static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl, + int theme_id, + const int base_flag) { if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) { switch (theme_id) { case TH_ACTIVE: case TH_SELECT: - return &stl->g_data->id_ofs_select_dupli; + return stl->g_data->outlines_select_dupli; case TH_TRANSFORM: + return stl->g_data->outlines_transform; default: - return &stl->g_data->id_ofs_transform; + return NULL; } } switch (theme_id) { case TH_ACTIVE: - return &stl->g_data->id_ofs_active; - case TH_SELECT: - return &stl->g_data->id_ofs_select; - case TH_TRANSFORM: - default: - return &stl->g_data->id_ofs_transform; - } -} - -static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl, - int theme_id) -{ - /* does not increment counter */ - switch (theme_id) { - case TH_ACTIVE: - return stl->g_data->lightprobes_planar_active; + return stl->g_data->outlines_active; case TH_SELECT: - return stl->g_data->lightprobes_planar_select; + return stl->g_data->outlines_select; case TH_TRANSFORM: + return stl->g_data->outlines_transform; default: - return stl->g_data->lightprobes_planar_transform; + return NULL; } } -static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl, +static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OBJECT_StorageList *stl, int theme_id, const int base_flag) { - /* does not increment counter */ + if (UNLIKELY(DRW_state_is_select())) { + return stl->g_data->probe_outlines_select; + } + if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) { switch (theme_id) { case TH_ACTIVE: case TH_SELECT: - return stl->g_data->lightprobes_cube_select_dupli; + return stl->g_data->probe_outlines_select_dupli; case TH_TRANSFORM: + return stl->g_data->probe_outlines_transform; default: - return stl->g_data->lightprobes_cube_transform; + return NULL; } } switch (theme_id) { case TH_ACTIVE: - return stl->g_data->lightprobes_cube_active; + return stl->g_data->probe_outlines_active; case TH_SELECT: - return stl->g_data->lightprobes_cube_select; + return stl->g_data->probe_outlines_select; case TH_TRANSFORM: + return stl->g_data->probe_outlines_transform; default: - return stl->g_data->lightprobes_cube_transform; + return NULL; } } -static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OBJECT_StorageList *stl, - int theme_id, - const int base_flag) +static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag) { - int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id, base_flag); - *counter += 1; - if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) { switch (theme_id) { case TH_ACTIVE: case TH_SELECT: - return stl->g_data->outlines_select_dupli; + return 2; case TH_TRANSFORM: - return stl->g_data->outlines_transform; + return 0; default: - return NULL; + return -1; } } switch (theme_id) { case TH_ACTIVE: - return stl->g_data->outlines_active; + return 3; case TH_SELECT: - return stl->g_data->outlines_select; + return 1; case TH_TRANSFORM: - return stl->g_data->outlines_transform; + return 0; default: - return NULL; + return -1; } } @@ -1042,13 +992,19 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, } } -/* Draw Camera Background Images */ +/* -------------------------------------------------------------------- */ +/** \name Camera Background Images + * \{ */ typedef struct CameraEngineData { DrawData dd; ListBase bg_data; } CameraEngineData; + typedef struct CameraEngineBGData { + CameraBGImage *camera_image; + GPUTexture *texture; float transform_mat[4][4]; + bool premultiplied; } CameraEngineBGData; static void camera_engine_data_free(DrawData *dd) @@ -1083,6 +1039,26 @@ static void camera_background_images_stereo_setup(Scene *scene, iuser->flag &= ~IMA_SHOW_STEREO; } } +static void camera_background_images_add_shgroup(DRWPass *pass, + CameraEngineBGData *bg_data, + GPUShader *shader, + GPUBatch *batch) +{ + CameraBGImage *camera_image = bg_data->camera_image; + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + DRW_shgroup_uniform_float_copy( + grp, "depth", camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND ? 0.000001f : 0.999999f); + DRW_shgroup_uniform_float_copy(grp, "alpha", camera_image->alpha); + DRW_shgroup_uniform_texture(grp, "image", bg_data->texture); + DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", bg_data->premultiplied); + DRW_shgroup_uniform_float_copy( + grp, "flipX", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0); + DRW_shgroup_uniform_float_copy( + grp, "flipY", (camera_image->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0); + DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat); + DRW_shgroup_call(grp, batch, NULL); +} static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data, OBJECT_PassList *psl, @@ -1306,25 +1282,46 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data, scale_m4, uv2img_space); - DRWPass *pass = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? psl->camera_images_front : - psl->camera_images_back; - GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm : - sh_data->object_camera_image; - DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + /* Keep the references so we can reverse the loop */ + bg_data->camera_image = bgpic; + bg_data->texture = tex; + bg_data->premultiplied = premultiplied; + } - DRW_shgroup_uniform_float_copy( - grp, "depth", (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) ? 0.000001 : 0.999999); - DRW_shgroup_uniform_float_copy(grp, "alpha", bgpic->alpha); - DRW_shgroup_uniform_texture(grp, "image", tex); - DRW_shgroup_uniform_bool_copy(grp, "imagePremultiplied", premultiplied); + /* Mark the rest bg_data's to be reused in the next drawing call */ + LinkData *last_node = list_node ? list_node->prev : camera_engine_data->bg_data.last; + while (list_node != NULL) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + bg_data->texture = NULL; + bg_data->camera_image = NULL; + list_node = list_node->next; + } - DRW_shgroup_uniform_float_copy( - grp, "flipX", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0); - DRW_shgroup_uniform_float_copy( - grp, "flipY", (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0); - DRW_shgroup_uniform_mat4(grp, "TransformMat", bg_data->transform_mat); + GPUShader *shader = DRW_state_do_color_management() ? sh_data->object_camera_image_cm : + sh_data->object_camera_image; + /* loop 1: camera images alpha under */ + for (list_node = last_node; list_node; list_node = list_node->prev) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + CameraBGImage *camera_image = bg_data->camera_image; + if ((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) == 0) { + camera_background_images_add_shgroup( + psl->camera_images_back_alpha_under, bg_data, shader, batch); + } + } - DRW_shgroup_call(grp, batch, NULL); + /* loop 2: camera images alpha over */ + for (list_node = camera_engine_data->bg_data.first; list_node; list_node = list_node->next) { + CameraEngineBGData *bg_data = (CameraEngineBGData *)list_node->data; + CameraBGImage *camera_image = bg_data->camera_image; + if (camera_image == NULL) { + break; + } + camera_background_images_add_shgroup((camera_image->flag & CAM_BGIMG_FLAG_FOREGROUND) ? + psl->camera_images_front_alpha_over : + psl->camera_images_back_alpha_over, + bg_data, + shader, + batch); } } } @@ -1337,6 +1334,7 @@ static void camera_background_images_free_textures(void) } BLI_freelistN(&e_data.movie_clips); } +/* \} */ static void OBJECT_cache_init(void *vedata) { @@ -1346,7 +1344,8 @@ static void OBJECT_cache_init(void *vedata) DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); OBJECT_PrivateData *g_data; const DRWContextState *draw_ctx = DRW_context_state_get(); - OBJECT_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + eGPUShaderConfig cfg = draw_ctx->sh_cfg; + OBJECT_Shaders *sh_data = &e_data.sh_data[cfg]; const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH); const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f); @@ -1367,59 +1366,25 @@ static void OBJECT_cache_init(void *vedata) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - psl->outlines = DRW_pass_create("Outlines Depth Pass", state); + psl->lightprobes = DRW_pass_create("Outlines Probe Pass", state); GPUShader *sh = sh_data->outline_prepass; + g_data->probe_outlines_transform = shgroup_outline(psl->lightprobes, 0, sh, cfg); + g_data->probe_outlines_select = shgroup_outline(psl->lightprobes, 1, sh, cfg); + g_data->probe_outlines_select_dupli = shgroup_outline(psl->lightprobes, 2, sh, cfg); + g_data->probe_outlines_active = shgroup_outline(psl->lightprobes, 3, sh, cfg); + + psl->outlines = DRW_pass_create("Outlines Depth Pass", state); + if (g_data->xray_enabled_and_not_wire) { sh = sh_data->outline_prepass_wire; } - g_data->outlines_select = shgroup_outline( - psl->outlines, &g_data->id_ofs_select, sh, draw_ctx->sh_cfg); - g_data->outlines_select_dupli = shgroup_outline( - psl->outlines, &g_data->id_ofs_select_dupli, sh, draw_ctx->sh_cfg); - g_data->outlines_transform = shgroup_outline( - psl->outlines, &g_data->id_ofs_transform, sh, draw_ctx->sh_cfg); - g_data->outlines_active = shgroup_outline( - psl->outlines, &g_data->id_ofs_active, sh, draw_ctx->sh_cfg); - - g_data->id_ofs_select = 0; - g_data->id_ofs_select_dupli = 0; - g_data->id_ofs_active = 0; - g_data->id_ofs_transform = 0; - } - - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state); - struct GPUBatch *sphere = DRW_cache_sphere_get(); - struct GPUBatch *quad = DRW_cache_quad_get(); - - /* Cubemap */ - g_data->lightprobes_cube_select = buffer_instance_outline( - pass, sphere, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg); - g_data->lightprobes_cube_select_dupli = buffer_instance_outline( - pass, sphere, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg); - g_data->lightprobes_cube_active = buffer_instance_outline( - pass, sphere, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg); - g_data->lightprobes_cube_transform = buffer_instance_outline( - pass, sphere, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg); - - /* Planar */ - g_data->lightprobes_planar_select = buffer_instance_outline( - pass, quad, &g_data->id_ofs_prb_select, draw_ctx->sh_cfg); - g_data->lightprobes_planar_select_dupli = buffer_instance_outline( - pass, quad, &g_data->id_ofs_prb_select_dupli, draw_ctx->sh_cfg); - g_data->lightprobes_planar_active = buffer_instance_outline( - pass, quad, &g_data->id_ofs_prb_active, draw_ctx->sh_cfg); - g_data->lightprobes_planar_transform = buffer_instance_outline( - pass, quad, &g_data->id_ofs_prb_transform, draw_ctx->sh_cfg); - - g_data->id_ofs_prb_select = 0; - g_data->id_ofs_prb_select_dupli = 0; - g_data->id_ofs_prb_active = 0; - g_data->id_ofs_prb_transform = 0; + g_data->outlines_transform = shgroup_outline(psl->outlines, 0, sh, cfg); + g_data->outlines_select = shgroup_outline(psl->outlines, 1, sh, cfg); + g_data->outlines_select_dupli = shgroup_outline(psl->outlines, 2, sh, cfg); + g_data->outlines_active = shgroup_outline(psl->outlines, 3, sh, cfg); } { @@ -1438,7 +1403,6 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu); - DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4); DRW_shgroup_call(grp, quad, NULL); /* This is the bleed pass if do_outline_expand is false. */ @@ -1512,9 +1476,15 @@ static void OBJECT_cache_init(void *vedata) /* Camera background images */ { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA; - psl->camera_images_back = DRW_pass_create("Camera Images Back", state); - psl->camera_images_front = DRW_pass_create("Camera Images Front", state); + psl->camera_images_back_alpha_over = DRW_pass_create( + "Camera Images Back Over", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL); + psl->camera_images_back_alpha_under = DRW_pass_create( + "Camera Images Back Under", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL); + psl->camera_images_front_alpha_over = DRW_pass_create( + "Camera Images Front Over", + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA_PREMUL); } for (int i = 0; i < 2; i++) { @@ -1965,9 +1935,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye } if (la->mode & LA_SHOW_CONE) { - - DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat); - DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat); + if (!DRW_state_is_select()) { + DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat); + } } } else { @@ -1981,8 +1952,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye } if (la->mode & LA_SHOW_CONE) { - DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat); - DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat); + if (!DRW_state_is_select()) { + DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat); + } } } @@ -2695,12 +2668,21 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl, DRW_object_wire_theme_get(ob, view_layer, &color); /* Small cube showing voxel size. */ + float min[3]; + madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min); float voxel_cubemat[4][4] = {{0.0f}}; - voxel_cubemat[0][0] = 1.0f / (float)sds->res[0]; - voxel_cubemat[1][1] = 1.0f / (float)sds->res[1]; - voxel_cubemat[2][2] = 1.0f / (float)sds->res[2]; + /* scale small cube to voxel size */ + voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0]; + voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1]; + voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2]; voxel_cubemat[3][0] = voxel_cubemat[3][1] = voxel_cubemat[3][2] = -1.0f; voxel_cubemat[3][3] = 1.0f; + /* translate small cube to corner */ + voxel_cubemat[3][0] = min[0]; + voxel_cubemat[3][1] = min[1]; + voxel_cubemat[3][2] = min[2]; + voxel_cubemat[3][3] = 1.0f; + /* move small cube into the domain (otherwise its centered on vertex of domain object) */ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f); mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat); @@ -2736,6 +2718,9 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl, DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z); DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale); DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth); + DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size); + DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0); + DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); DRW_shgroup_call_procedural_lines(grp, ob, line_count); @@ -2766,15 +2751,6 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat); } -typedef struct OBJECT_LightProbeEngineData { - DrawData dd; - - float increment_x[3]; - float increment_y[3]; - float increment_z[3]; - float corner[3]; -} OBJECT_LightProbeEngineData; - static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, OBJECT_StorageList *stl, OBJECT_PassList *psl, @@ -2791,13 +2767,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl; - OBJECT_LightProbeEngineData *prb_data = (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure( - &ob->id, &draw_engine_object_type, sizeof(OBJECT_LightProbeEngineData), NULL, NULL); - if (DRW_state_is_select() || do_outlines) { - int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id, ob->base_flag); - if (prb->type == LIGHTPROBE_TYPE_GRID) { + float corner[3]; + float increment[3][3]; /* Update transforms */ float cell_dim[3], half_cell_dim[3]; cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x); @@ -2807,65 +2780,41 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f); /* First cell. */ - copy_v3_fl(prb_data->corner, -1.0f); - add_v3_v3(prb_data->corner, half_cell_dim); - mul_m4_v3(ob->obmat, prb_data->corner); + copy_v3_fl(corner, -1.0f); + add_v3_v3(corner, half_cell_dim); + mul_m4_v3(ob->obmat, corner); /* Opposite neighbor cell. */ - copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f); - add_v3_v3(prb_data->increment_x, half_cell_dim); - add_v3_fl(prb_data->increment_x, -1.0f); - mul_m4_v3(ob->obmat, prb_data->increment_x); - sub_v3_v3(prb_data->increment_x, prb_data->corner); - - copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f); - add_v3_v3(prb_data->increment_y, half_cell_dim); - add_v3_fl(prb_data->increment_y, -1.0f); - mul_m4_v3(ob->obmat, prb_data->increment_y); - sub_v3_v3(prb_data->increment_y, prb_data->corner); - - copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]); - add_v3_v3(prb_data->increment_z, half_cell_dim); - add_v3_fl(prb_data->increment_z, -1.0f); - mul_m4_v3(ob->obmat, prb_data->increment_z); - sub_v3_v3(prb_data->increment_z, prb_data->corner); + copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f); + copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f); + copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]); + + for (int i = 0; i < 3; i++) { + add_v3_v3(increment[i], half_cell_dim); + add_v3_fl(increment[i], -1.0f); + mul_m4_v3(ob->obmat, increment[i]); + sub_v3_v3(increment[i], corner); + } + int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag); uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; DRWShadingGroup *grp = DRW_shgroup_create(sh_data->lightprobe_grid, psl->lightprobes); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id); - DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */ - DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1); - DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1); - DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1); - DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1); - DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1); + DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id); + DRW_shgroup_uniform_vec3_copy(grp, "corner", corner); + DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]); + DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]); + DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]); + DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_state_enable(grp, DRW_STATE_CLIP_PLANES); } DRW_shgroup_call_procedural_points(grp, NULL, cell_count); - *call_id += 1; } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { - float draw_size = 1.0f; - float probe_cube_mat[4][4]; - // prb_data->draw_size = prb->data_draw_size * 0.1f; - // unit_m4(prb_data->probe_cube_mat); - // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]); - - DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp( + else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { + DRWShadingGroup *grp = shgroup_theme_id_to_probe_outline_or_null( stl, theme_id, ob->base_flag); - /* TODO remove or change the drawing of the cube probes. This line draws nothing on purpose - * to keep the call ids correct. */ - zero_m4(probe_cube_mat); - DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat); - *call_id += 1; - } - else if (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) { - float draw_size = 1.0f; - DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id); - DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat); - *call_id += 1; + DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob); } } @@ -3138,13 +3087,11 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, switch (GS(ob_data->name)) { case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); + BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize); break; case ID_CU: { Curve *cu = (Curve *)ob_data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } + BKE_curve_texspace_ensure(cu); texcoloc = cu->loc; texcosize = cu->size; break; @@ -3176,7 +3123,8 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, DRW_buffer_add_entry(sgl->texspace, color, &one, tmp); } -static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id) +static void DRW_shgroup_bounds( + OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id, char boundtype, bool around_origin) { float color[4], center[3], size[3], tmp[4][4], final_mat[4][4], one = 1.0f; BoundBox bb_local; @@ -3202,10 +3150,16 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the } UI_GetThemeColor4fv(theme_id, color); - BKE_boundbox_calc_center_aabb(bb, center); BKE_boundbox_calc_size_aabb(bb, size); - switch (ob->boundtype) { + if (around_origin) { + zero_v3(center); + } + else { + BKE_boundbox_calc_center_aabb(bb, center); + } + + switch (boundtype) { case OB_BOUND_BOX: size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); @@ -3258,6 +3212,27 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the } } +static void DRW_shgroup_collision(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id) +{ + switch (ob->rigidbody_object->shape) { + case RB_SHAPE_BOX: + DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_BOX, true); + break; + case RB_SHAPE_SPHERE: + DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_SPHERE, true); + break; + case RB_SHAPE_CONE: + DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CONE, true); + break; + case RB_SHAPE_CYLINDER: + DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CYLINDER, true); + break; + case RB_SHAPE_CAPSULE: + DRW_shgroup_bounds(sgl, ob, theme_id, OB_BOUND_CAPSULE, true); + break; + } +} + static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, Object *ob, OBJECT_PassList *psl) @@ -3606,6 +3581,10 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) if (hide_object_extra) { break; } + if ((ob->base_flag & BASE_FROM_DUPLI) && (ob->transflag & OB_DUPLICOLLECTION) && + ob->instance_collection) { + break; + } DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg); break; case OB_SPEAKER: @@ -3683,7 +3662,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) if (theme_id == TH_UNDEFINED) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); } - DRW_shgroup_bounds(sgl, ob, theme_id); + DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false); } /* Helpers for when we're transforming origins. */ @@ -3742,7 +3721,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) /* Don't draw bounding box again if draw type is bound box. */ if ((ob->dtx & OB_DRAWBOUNDOX) && (ob->dt != OB_BOUNDBOX) && !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE)) { - DRW_shgroup_bounds(sgl, ob, theme_id); + DRW_shgroup_bounds(sgl, ob, theme_id, ob->boundtype, false); } if (ob->dtx & OB_AXIS) { @@ -3752,6 +3731,10 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) DRW_buffer_add_entry(sgl->empties.empty_axes, color, &axes_size, ob->obmat); } + if (ob->rigidbody_object) { + DRW_shgroup_collision(sgl, ob, theme_id); + } + if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && (((SmokeModifierData *)md)->domain != NULL)) { @@ -3782,55 +3765,33 @@ static void OBJECT_draw_scene(void *vedata) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - int id_len_select = g_data->id_ofs_select; - int id_len_select_dupli = g_data->id_ofs_select_dupli; - int id_len_active = g_data->id_ofs_active; - int id_len_transform = g_data->id_ofs_transform; - - int id_len_prb_select = g_data->id_ofs_prb_select; - int id_len_prb_select_dupli = g_data->id_ofs_prb_select_dupli; - int id_len_prb_active = g_data->id_ofs_prb_active; - int id_len_prb_transform = g_data->id_ofs_prb_transform; - - int outline_calls = id_len_select + id_len_select_dupli + id_len_active + id_len_transform; - outline_calls += id_len_prb_select + id_len_prb_select_dupli + id_len_prb_active + - id_len_prb_transform; + int do_outlines = !DRW_pass_is_empty(psl->outlines) || !DRW_pass_is_empty(psl->lightprobes); float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - DRW_draw_pass(psl->camera_images_back); + DRW_draw_pass(psl->camera_images_back_alpha_under); + DRW_draw_pass(psl->camera_images_back_alpha_over); /* Don't draw Transparent passes in MSAA buffer. */ // DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */ - DRW_draw_pass(stl->g_data->sgl.transp_shapes); + DRW_draw_pass(g_data->sgl.transp_shapes); MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl); - DRW_draw_pass(stl->g_data->sgl.bone_solid); - DRW_draw_pass(stl->g_data->sgl.bone_wire); - DRW_draw_pass(stl->g_data->sgl.bone_outline); - DRW_draw_pass(stl->g_data->sgl.non_meshes); + DRW_draw_pass(g_data->sgl.bone_solid); + DRW_draw_pass(g_data->sgl.bone_wire); + DRW_draw_pass(g_data->sgl.bone_outline); + DRW_draw_pass(g_data->sgl.non_meshes); DRW_draw_pass(psl->particle); - DRW_draw_pass(stl->g_data->sgl.bone_axes); + DRW_draw_pass(g_data->sgl.bone_axes); MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl); - DRW_draw_pass(stl->g_data->sgl.image_empties); + DRW_draw_pass(g_data->sgl.image_empties); - if (DRW_state_is_fbo() && outline_calls > 0) { + if (DRW_state_is_fbo() && do_outlines) { DRW_stats_group_start("Outlines"); - g_data->id_ofs_active = 1; - g_data->id_ofs_select = g_data->id_ofs_active + id_len_active + id_len_prb_active + 1; - g_data->id_ofs_select_dupli = g_data->id_ofs_select + id_len_select + id_len_prb_select + 1; - g_data->id_ofs_transform = g_data->id_ofs_select_dupli + id_len_select_dupli + - id_len_prb_select_dupli + 1; - - g_data->id_ofs_prb_active = g_data->id_ofs_active + id_len_active; - g_data->id_ofs_prb_select = g_data->id_ofs_select + id_len_select; - g_data->id_ofs_prb_select_dupli = g_data->id_ofs_select_dupli + id_len_select_dupli; - g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_len_transform; - /* Render filled polygon on a separate framebuffer */ GPU_framebuffer_bind(fbl->outlines_fb); GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f); @@ -3865,7 +3826,7 @@ static void OBJECT_draw_scene(void *vedata) } /* Combine with scene buffer last */ - if (outline_calls > 0) { + if (do_outlines) { DRW_draw_pass(psl->outlines_resolve); } } @@ -3917,7 +3878,7 @@ static void OBJECT_draw_scene(void *vedata) batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path); - DRW_draw_pass(psl->camera_images_front); + DRW_draw_pass(psl->camera_images_front_alpha_over); camera_background_images_free_textures(); DRW_draw_pass(psl->ob_center); diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index a5b1133abf4..9106e89663d 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -23,8 +23,6 @@ #include "DNA_mesh_types.h" #include "DNA_view3d_types.h" -#include "BIF_glutil.h" - #include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_object.h" @@ -77,7 +75,6 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *face_wires_shgrp; DRWShadingGroup *face_wires_xray_shgrp; DRWView *view_wires; - BLI_mempool *wire_color_mempool; View3DOverlay overlay; float wire_step_param; bool clear_stencil; @@ -208,10 +205,6 @@ static void overlay_cache_init(void *vedata) if (v3d->shading.type == OB_WIRE) { g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES; - - if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) { - g_data->wire_color_mempool = BLI_mempool_create(sizeof(float[3]), 0, 512, 0); - } } { @@ -246,17 +239,11 @@ static void overlay_cache_init(void *vedata) geometry_shader_uniforms(g_data->face_wires_shgrp); geometry_shader_uniforms(g_data->face_wires_xray_shgrp); } - if (rv3d->rflag & RV3D_CLIPPING) { - DRW_shgroup_state_enable(g_data->face_wires_shgrp, DRW_STATE_CLIP_PLANES); - DRW_shgroup_state_enable(g_data->face_wires_xray_shgrp, DRW_STATE_CLIP_PLANES); - } - g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f; } } static void overlay_wire_color_get(const View3D *v3d, - const OVERLAY_PrivateData *pd, const Object *ob, const bool use_coloring, float **rim_col, @@ -305,8 +292,10 @@ static void overlay_wire_color_get(const View3D *v3d, if (v3d->shading.type == OB_WIRE) { if (ELEM(v3d->shading.wire_color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_RANDOM_COLOR)) { - *wire_col = BLI_mempool_alloc(pd->wire_color_mempool); - *rim_col = BLI_mempool_alloc(pd->wire_color_mempool); + /* Theses stays valid until next call. So we need to copy them when using them as uniform. */ + static float wire_col_val[3], rim_col_val[3]; + *wire_col = wire_col_val; + *rim_col = rim_col_val; if (v3d->shading.wire_color_type == V3D_SHADING_OBJECT_COLOR) { linearrgb_to_srgb_v3_v3(*wire_col, ob->color); @@ -400,7 +389,8 @@ static void overlay_cache_populate(void *vedata, Object *ob) if ((!pd->show_overlays) || (((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) || ob->type != OB_MESH) { - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d); + const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES); const bool is_wire = (ob->dt < OB_SOLID); const bool is_xray = (ob->dtx & OB_DRAWXRAY); @@ -419,6 +409,10 @@ static void overlay_cache_populate(void *vedata, Object *ob) shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp); } + if (draw_ctx->rv3d->rflag & RV3D_CLIPPING) { + DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES); + } + float wire_step_param = 10.0f; if (!use_sculpt_pbvh) { wire_step_param = (all_wires) ? 1.0f : pd->wire_step_param; @@ -427,9 +421,9 @@ static void overlay_cache_populate(void *vedata, Object *ob) if (!(DRW_state_is_select() || DRW_state_is_depth())) { float *rim_col, *wire_col; - overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col); - DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1); - DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1); + overlay_wire_color_get(v3d, ob, use_coloring, &rim_col, &wire_col); + DRW_shgroup_uniform_vec3_copy(shgrp, "wireColor", wire_col); + DRW_shgroup_uniform_vec3_copy(shgrp, "rimColor", rim_col); DRW_shgroup_stencil_mask(shgrp, (is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF); } @@ -506,12 +500,6 @@ static void overlay_draw_scene(void *vedata) /* TODO(fclem): find a way to unify the multisample pass together * (non meshes + armature + wireframe) */ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl); - - /* XXX TODO(fclem) do not discard data after drawing! Store them per viewport. */ - if (stl->g_data->wire_color_mempool) { - BLI_mempool_destroy(stl->g_data->wire_color_mempool); - stl->g_data->wire_color_mempool = NULL; - } } static void overlay_engine_free(void) diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index 1b196cd8bb7..9749619cffe 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -156,7 +156,8 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) const DRWContextState *draw_ctx = DRW_context_state_get(); if ((ob == draw_ctx->obact) && - (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) || !ob->sculpt->modifiers_active)) { + (BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) || + ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) { PBVH *pbvh = ob->sculpt->pbvh; if (pbvh && pbvh_has_mask(pbvh)) { DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false); diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl index e559224eb9e..d147b193ccf 100644 --- a/source/blender/draw/modes/shaders/common_globals_lib.glsl +++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl @@ -34,6 +34,7 @@ layout(std140) uniform globalsBlock vec4 colorVNormal; vec4 colorLNormal; vec4 colorFaceDot; + vec4 colorSkinRoot; vec4 colorDeselect; vec4 colorOutline; vec4 colorLightNoAlpha; diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl index 20a54947db7..76089d1ae41 100644 --- a/source/blender/draw/modes/shaders/common_view_lib.glsl +++ b/source/blender/draw/modes/shaders/common_view_lib.glsl @@ -1,4 +1,5 @@ #define COMMON_VIEW_LIB +#define DRW_RESOURCE_CHUNK_LEN 512 /* keep in sync with DRWManager.view_data */ layout(std140) uniform viewBlock @@ -23,8 +24,77 @@ layout(std140) uniform viewBlock _world_clip_planes_calc_clip_distance(p, clipPlanes) #endif +uniform int resourceChunk; + +#ifdef GPU_VERTEX_SHADER +# ifdef GL_ARB_shader_draw_parameters +# define baseInstance gl_BaseInstanceARB +# else /* no ARB_shader_draw_parameters */ +uniform int baseInstance; +# endif + +# ifdef IN_PLACE_INSTANCES +/* When drawing instances of an object at the same position. */ +# define instanceId 0 +# elif defined(GPU_DEPRECATED_AMD_DRIVER) +/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format, + * the gl_InstanceID is incremented by the 2 bit component of the attrib. + * Ignore gl_InstanceID then. */ +# define instanceId 0 +# else +# define instanceId gl_InstanceID +# endif + +# define resource_id (baseInstance + instanceId) + +/* Use this to declare and pass the value if + * the fragment shader uses the resource_id. */ +# define RESOURCE_ID_VARYING flat out int resourceIDFrag; +# define RESOURCE_ID_VARYING_GEOM flat out int resourceIDGeom; +# define PASS_RESOURCE_ID resourceIDFrag = resource_id; +# define PASS_RESOURCE_ID_GEOM resourceIDGeom = resource_id; +#endif + +/* If used in a fragment / geometry shader, we pass + * resource_id as varying. */ +#ifdef GPU_GEOMETRY_SHADER +# define RESOURCE_ID_VARYING \ + flat out int resourceIDFrag; \ + flat in int resourceIDGeom[]; + +# define resource_id resourceIDGeom +# define PASS_RESOURCE_ID(i) resourceIDFrag = resource_id[i]; +#endif + +#ifdef GPU_FRAGMENT_SHADER +flat in int resourceIDFrag; +# define resource_id resourceIDFrag +#endif + +#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) +struct ObjectMatrices { + mat4 drw_modelMatrix; + mat4 drw_modelMatrixInverse; +}; + +layout(std140) uniform modelBlock +{ + ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN]; +}; + +# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix) +# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse) + +#else /* GPU_INTEL */ +/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage. + * So for now we just force using the legacy path. */ +/* Note that this is also a workaround of a problem on osx (amd or nvidia) + * and older amd driver on windows. */ uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; +#endif + +#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id) /** Transform shortcuts. */ /* Rule of thumb: Try to reuse world positions and normals because converting though viewspace diff --git a/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl new file mode 100644 index 00000000000..5187571b27b --- /dev/null +++ b/source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl @@ -0,0 +1,30 @@ +/* Need dedicated obmat since we use instancing attribs + * (we cannot let have baseinstance mess them). */ +uniform vec4 editModelMat[4]; +uniform vec3 screen_vecs[2]; + +/* ---- Instantiated Attrs ---- */ +in vec2 pos; + +/* ---- Per instance Attrs ---- */ +in float size; +in vec3 local_pos; + +flat out vec4 finalColor; + +void main() +{ + mat4 obmat = mat4(editModelMat[0], editModelMat[1], editModelMat[2], editModelMat[3]); + /* Could be optimized... but it is only for a handful of verts so not a priority. */ + mat3 imat = inverse(mat3(obmat)); + vec3 right = normalize(imat * vec3(screen_vecs[0])); + vec3 up = normalize(imat * vec3(screen_vecs[1])); + vec3 screen_pos = (right * pos.x + up * pos.y) * size; + vec4 pos_4d = obmat * vec4(local_pos + screen_pos, 1.0); + gl_Position = ViewProjectionMatrix * pos_4d; + finalColor = colorSkinRoot; + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(pos_4d.xyz); +#endif +} diff --git a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl index 5d8ad3c79ea..7804ebdb8c9 100644 --- a/source/blender/draw/modes/shaders/object_camera_image_frag.glsl +++ b/source/blender/draw/modes/shaders/object_camera_image_frag.glsl @@ -19,5 +19,7 @@ void main() #endif color.a *= alpha; + color.rgb *= color.a; + fragColor = color; } diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl index d27d55c3fd6..144024a7d5d 100644 --- a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl +++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl @@ -1,18 +1,11 @@ -uniform mat4 ViewProjectionMatrix; - -uniform float sphere_size; uniform ivec3 grid_resolution; uniform vec3 corner; uniform vec3 increment_x; uniform vec3 increment_y; uniform vec3 increment_z; -uniform vec3 screen_vecs[2]; - -uniform int call_id; /* we don't want the builtin callId which would be 0. */ -uniform int baseId; -flat out uint finalId; +flat out int objectId; void main() { @@ -29,7 +22,8 @@ void main() gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0); gl_PointSize = 2.0f; - finalId = uint(baseId + call_id); + /* ID 0 is nothing (background) */ + objectId = resource_handle + 1; #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(ws_cell_location); diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl index 7668a0c2c94..7b86d477a39 100644 --- a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl +++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl @@ -7,30 +7,9 @@ uniform usampler2D outlineId; uniform sampler2D outlineDepth; uniform sampler2D sceneDepth; -uniform int idOffsets[4]; - uniform float alphaOcclu; uniform vec2 viewportSize; -vec4 convert_id_to_color(int id) -{ - if (id == 0) { - return vec4(0.0); - } - if (id < idOffsets[1]) { - return colorActive; - } - else if (id < idOffsets[2]) { - return colorSelect; - } - else if (id < idOffsets[3]) { - return colorDupliSelect; - } - else { - return colorTransform; - } -} - void main() { ivec2 texel = ivec2(gl_FragCoord.xy); @@ -85,7 +64,24 @@ void main() const float epsilon = 3.0 / 8388608.0; bool occluded = (ref_depth > scene_depth + epsilon); - FragColor = convert_id_to_color(int(ref_id)); + /* WATCH: Keep in sync with outlineId of the prepass. */ + uint color_id = ref_id >> 14u; + if (ref_id == 0u) { + FragColor = vec4(0.0); + } + else if (color_id == 1u) { + FragColor = colorSelect; + } + else if (color_id == 2u) { + FragColor = colorDupliSelect; + } + else if (color_id == 3u) { + FragColor = colorActive; + } + else { + FragColor = colorTransform; + } + FragColor.a *= (occluded) ? alphaOcclu : 1.0; FragColor.a = (outline) ? FragColor.a : 0.0; } diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl index c3447456ea6..5d6c4881b5b 100644 --- a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl +++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl @@ -1,10 +1,18 @@ -uniform int callId; -uniform int baseId; + +/* Should be 2 bits only [0..3]. */ +uniform int outlineId; + +flat in int objectId; /* using uint because 16bit uint can contain more ids than int. */ out uint outId; +/* Replace top 2 bits (of the 16bit output) by outlineId. + * This leaves 16K different IDs to create outlines between objects. + * SHIFT = (32 - (16 - 2)) */ +#define SHIFT 18u + void main() { - outId = uint(baseId + callId); + outId = (uint(outlineId) << 14u) | ((uint(objectId) << SHIFT) >> SHIFT); } diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl index 5a3eb38fb6b..b32913dcd60 100644 --- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl +++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl @@ -2,12 +2,15 @@ layout(lines_adjacency) in; layout(line_strip, max_vertices = 2) out; -in vec4 pPos[]; in vec3 vPos[]; +in int objectId_g[]; + +flat out int objectId; void vert_from_gl_in(int v) { - gl_Position = pPos[v]; + gl_Position = gl_in[v].gl_Position; + objectId = objectId_g[v]; #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_set_clip_distance(gl_in[v].gl_ClipDistance); #endif diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl index e34afe95b5e..7740f9a4af2 100644 --- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl +++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl @@ -1,16 +1,27 @@ in vec3 pos; -out vec4 pPos; +#ifdef USE_GEOM out vec3 vPos; +out int objectId_g; +# define objectId objectId_g +#else + +flat out int objectId; +#endif void main() { vec3 world_pos = point_object_to_world(pos); +#ifdef USE_GEOM vPos = point_world_to_view(world_pos); - pPos = point_world_to_ndc(world_pos); +#endif + gl_Position = point_world_to_ndc(world_pos); /* Small bias to always be on top of the geom. */ - pPos.z -= 1e-3; + gl_Position.z -= 1e-3; + + /* ID 0 is nothing (background) */ + objectId = resource_handle + 1; #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl index e96a789b8b1..64f88bd74fa 100644 --- a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl +++ b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl @@ -6,6 +6,13 @@ uniform float displaySize = 1.0; uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ +/* SmokeDomainSettings.cell_size */ +uniform vec3 cellSize; +/* SmokeDomainSettings.p0 */ +uniform vec3 domainOriginOffset; +/* SmokeDomainSettings.res_min */ +uniform ivec3 adaptiveCellOffset; + flat out vec4 finalColor; const vec3 corners[4] = vec3[4](vec3(0.0, 0.2, -0.5), @@ -66,7 +73,6 @@ void main() #endif ivec3 volume_size = textureSize(velocityX, 0); - float voxel_size = 1.0 / float(max(max(volume_size.x, volume_size.y), volume_size.z)); ivec3 cell_ofs = ivec3(0); ivec3 cell_div = volume_size; @@ -89,8 +95,7 @@ void main() cell_co.z = cell / (cell_div.x * cell_div.y); cell_co += cell_ofs; - vec3 pos = (vec3(cell_co) + 0.5) / vec3(volume_size); - pos = pos * 2.0 - 1.0; + vec3 pos = domainOriginOffset + cellSize * (vec3(cell_co + adaptiveCellOffset) + 0.5); vec3 velocity; velocity.x = texelFetch(velocityX, cell_co, 0).r; @@ -102,9 +107,9 @@ void main() #ifdef USE_NEEDLE mat3 rot_mat = rotation_from_vector(velocity); vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]]; - pos += rotated_pos * length(velocity) * displaySize * voxel_size; + pos += rotated_pos * length(velocity) * displaySize * cellSize; #else - pos += (((gl_VertexID % 2) == 1) ? velocity : vec3(0.0)) * displaySize * voxel_size; + pos += ((gl_VertexID % 2) == 1) ? velocity * displaySize * cellSize : vec3(0.0); #endif vec3 world_pos = point_object_to_world(pos); diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index d80b96f0d74..8951677b32f 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3411,7 +3411,7 @@ static void acf_nlatrack_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, flo } /* set color for nla track */ - UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color); + UI_GetThemeColorShade3fv(TH_NLA_TRACK, ((nonSolo == false) ? 20 : -20), r_color); } /* name for nla track entries */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index afd2cdc2a2b..0fc137295d0 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3339,7 +3339,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Select Channel keyframes"; + ot->name = "Select Channel Keyframes"; ot->idname = "ANIM_OT_channel_select_keys"; ot->description = "Select all keyframes of channel under mouse"; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 48493c9e961..f73c8a5b71a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1818,7 +1818,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* Layer visibility - we check both object and base, * since these may not be in sync yet. */ - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { continue; } @@ -3017,7 +3017,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m */ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { /* layer visibility - we check both object and base, since these may not be in sync yet */ - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return false; } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 8c873eb6b45..36583ecf060 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -486,7 +486,7 @@ static void draw_marker( float name_y = UI_DPI_FAC * 18; /* Give an offset to the marker name when selected, * or when near the current frame (5 frames range, starting from the current one). */ - if ((marker->flag & SELECT) || (IN_RANGE_INCL(marker->frame, cfra - 4, cfra))) { + if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) { name_y += UI_DPI_FAC * 10; } draw_marker_name(fstyle, marker, xpos, name_y); @@ -1148,33 +1148,48 @@ static void deselect_markers(ListBase *markers) } /* select/deselect TimeMarker at current frame */ -static void select_timeline_marker_frame(ListBase *markers, int frame, bool extend) +static int select_timeline_marker_frame(ListBase *markers, + int frame, + bool extend, + bool wait_to_deselect_others) { - TimeMarker *marker, *marker_first = NULL; + TimeMarker *marker, *marker_selected = NULL; + int ret_val = OPERATOR_FINISHED; + + if (extend) { + wait_to_deselect_others = false; + } /* support for selection cycling */ for (marker = markers->first; marker; marker = marker->next) { if (marker->frame == frame) { if (marker->flag & SELECT) { - marker_first = marker->next; + marker_selected = marker->next; break; } } } - /* if extend is not set, then deselect markers */ - if (extend == false) { - deselect_markers(markers); + if (wait_to_deselect_others && marker_selected) { + ret_val = OPERATOR_RUNNING_MODAL; } + /* if extend is not set, then deselect markers */ + else { + if (extend == false) { + deselect_markers(markers); + } - LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { - /* this way a not-extend select will always give 1 selected marker */ - if (marker->frame == frame) { - marker->flag ^= SELECT; - break; + LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_selected) { + /* this way a not-extend select will always give 1 selected marker */ + if (marker->frame == frame) { + marker->flag ^= SELECT; + break; + } } + LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_selected); } - LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first); + + return ret_val; } static void select_marker_camera_switch( @@ -1221,17 +1236,17 @@ static void select_marker_camera_switch( #endif } -static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) +static int ed_marker_select( + bContext *C, const int mval[2], bool extend, bool camera, bool wait_to_deselect_others) { ListBase *markers = ED_context_get_markers(C); - ARegion *ar = CTX_wm_region(C); View2D *v2d = UI_view2d_fromcontext(C); + int ret_val = OPERATOR_FINISHED; - float mouse_region_x = event->x - ar->winrct.xmin; - if (region_position_is_over_marker(v2d, markers, mouse_region_x)) { - float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mouse_region_x); + if (region_position_is_over_marker(v2d, markers, mval[0])) { + float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mval[0]); int cfra = ED_markers_find_nearest_marker_time(markers, frame_at_mouse_position); - select_timeline_marker_frame(markers, cfra, extend); + ret_val = select_timeline_marker_frame(markers, cfra, extend, wait_to_deselect_others); select_marker_camera_switch(C, camera, extend, markers, cfra); } @@ -1243,17 +1258,22 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_val | OPERATOR_PASS_THROUGH; } -static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int ed_marker_select_exec(bContext *C, wmOperator *op) { const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); bool camera = false; #ifdef DURIAN_CAMERA_SWITCH camera = RNA_boolean_get(op->ptr, "camera"); #endif - return ed_marker_select(C, event, extend, camera); + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + return ed_marker_select(C, mval, extend, camera, wait_to_deselect_others); } static void MARKER_OT_select(wmOperatorType *ot) @@ -1266,12 +1286,15 @@ static void MARKER_OT_select(wmOperatorType *ot) ot->idname = "MARKER_OT_select"; /* api callbacks */ - ot->invoke = ed_marker_select_invoke; ot->poll = ed_markers_poll_markers_exist; + ot->exec = ed_marker_select_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); #ifdef DURIAN_CAMERA_SWITCH diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index bd4886817cd..30bf837f6c0 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -36,6 +36,7 @@ #include "BKE_scene.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "DEG_depsgraph_query.h" #include "GPU_batch.h" @@ -67,6 +68,37 @@ typedef struct MPathTarget { /* ........ */ +/* update scene for current frame */ +static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph) +{ + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +Depsgraph *animviz_depsgraph_build(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + ListBase *targets) +{ + /* Allocate dependency graph. */ + Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT); + + /* Make a flat array of IDs for the DEG API. */ + const int num_ids = BLI_listbase_count(targets); + ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS"); + int current_id_index = 0; + for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) { + ids[current_id_index++] = &mpt->ob->id; + } + + /* Build graph from all requested IDs. */ + DEG_graph_build_from_ids(depsgraph, bmain, scene, view_layer, ids, num_ids); + MEM_freeN(ids); + + /* Update once so we can access pointers of evaluated animation data. */ + motionpaths_calc_update_scene(bmain, depsgraph); + return depsgraph; +} + /* get list of motion paths to be baked for the given object * - assumes the given list is ready to be used */ @@ -106,24 +138,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* ........ */ -/* update scene for current frame */ -static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph) -{ - /* Do all updates - * - if this is too slow, resort to using a more efficient way - * that doesn't force complete update, but for now, this is the - * most accurate way! - * - * TODO(segey): Bring back partial updates, which became impossible - * with the new depsgraph due to unsorted nature of bases. - * - * TODO(sergey): Use evaluation context dedicated to motion paths. - */ - BKE_scene_graph_update_for_newframe(depsgraph, bmain); -} - -/* ........ */ - /* perform baking for the targets on the current frame */ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) { @@ -201,6 +215,135 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) } } +/* Get pointer to animviz settings for the given target. */ +static bAnimVizSettings *animviz_target_settings_get(MPathTarget *mpt) +{ + if (mpt->pchan != NULL) { + return &mpt->ob->pose->avs; + } + return &mpt->ob->avs; +} + +static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra) +{ + *r_sfra = INT_MAX; + *r_efra = INT_MIN; + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { + *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame); + *r_efra = max_ii(*r_efra, mpt->mpath->end_frame); + } +} + +static int motionpath_get_prev_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame) +{ + /* If the current frame is outside of the configured motion path range we ignore update of this + * motion path by using invalid frame range where start frame is above the end frame. */ + if (current_frame <= mpt->mpath->start_frame) { + return INT_MAX; + } + + float current_frame_float = current_frame; + DLRBT_Node *node = BLI_dlrbTree_search_prev(fcu_keys, compare_ak_cfraPtr, ¤t_frame_float); + if (node == NULL) { + return mpt->mpath->start_frame; + } + + ActKeyColumn *key_data = (ActKeyColumn *)node; + return key_data->cfra; +} + +static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt, + DLRBT_Tree *fcu_keys, + int current_frame) +{ + int frame = motionpath_get_prev_keyframe(mpt, fcu_keys, current_frame); + return motionpath_get_prev_keyframe(mpt, fcu_keys, frame); +} + +static int motionpath_get_next_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame) +{ + /* If the current frame is outside of the configured motion path range we ignore update of this + * motion path by using invalid frame range where start frame is above the end frame. */ + if (current_frame >= mpt->mpath->end_frame) { + return INT_MIN; + } + + float current_frame_float = current_frame; + DLRBT_Node *node = BLI_dlrbTree_search_next(fcu_keys, compare_ak_cfraPtr, ¤t_frame_float); + if (node == NULL) { + return mpt->mpath->end_frame; + } + + ActKeyColumn *key_data = (ActKeyColumn *)node; + return key_data->cfra; +} + +static int motionpath_get_next_next_keyframe(MPathTarget *mpt, + DLRBT_Tree *fcu_keys, + int current_frame) +{ + int frame = motionpath_get_next_keyframe(mpt, fcu_keys, current_frame); + return motionpath_get_next_keyframe(mpt, fcu_keys, frame); +} + +static bool motionpath_check_can_use_keyframe_range(MPathTarget *UNUSED(mpt), + AnimData *adt, + ListBase *fcurve_list) +{ + if (adt == NULL || fcurve_list == NULL) { + return false; + } + /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA + * or drivers or modifiers on the f-curves. */ + return true; +} + +static void motionpath_calculate_update_range(MPathTarget *mpt, + AnimData *adt, + ListBase *fcurve_list, + int current_frame, + int *r_sfra, + int *r_efra) +{ + /* Similar to the case when there is only a single keyframe: need to update en entire range to + * a constant value. */ + if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) { + *r_sfra = mpt->mpath->start_frame; + *r_efra = mpt->mpath->end_frame; + return; + } + + *r_sfra = INT_MAX; + *r_efra = INT_MIN; + + /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a + * widest range from them. This is because it's possible to have more narrow keyframe on a + * channel which wasn't edited. + * Could be optimized further by storing some flags about which channels has been modified so + * we ignore all others (which can potentially make an update range unnecessary wide). */ + for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) { + DLRBT_Tree fcu_keys; + BLI_dlrbTree_init(&fcu_keys); + fcurve_to_keylist(adt, fcu, &fcu_keys, 0); + + int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, current_frame); + int fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, current_frame); + + /* Extend range furher, since accelleration compensation propagates even further away. */ + if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) { + fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, fcu_sfra); + fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, fcu_efra); + } + + if (fcu_sfra <= fcu_efra) { + *r_sfra = min_ii(*r_sfra, fcu_sfra); + *r_efra = max_ii(*r_efra, fcu_efra); + } + + BLI_dlrbTree_free(&fcu_keys); + } +} + /* Perform baking of the given object's and/or its bones' transforms to motion paths * - scene: current scene * - ob: object whose flagged motionpaths should get calculated @@ -211,39 +354,36 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, Main *bmain, Scene *scene, ListBase *targets, - bool restore, - bool current_frame_only) + eAnimvizCalcRange range, + bool restore) { - /* sanity check */ + /* Sanity check. */ if (ELEM(NULL, targets, targets->first)) { return; } - /* Compute frame range to bake within. - * TODO: this method could be improved... - * 1) max range for standard baking - * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */ - int sfra = INT_MAX; - int efra = INT_MIN; - - for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { - /* try to increase area to do (only as much as needed) */ - sfra = MIN2(sfra, mpt->mpath->start_frame); - efra = MAX2(efra, mpt->mpath->end_frame); - } - - if (efra <= sfra) { - return; - } - - /* Limit frame range if we are updating just the current frame. */ - /* set frame values */ - int cfra = CFRA; - if (current_frame_only) { - if (cfra < sfra || cfra > efra) { - return; - } - sfra = efra = cfra; + const int cfra = CFRA; + int sfra = INT_MAX, efra = INT_MIN; + switch (range) { + case ANIMVIZ_CALC_RANGE_CURRENT_FRAME: + motionpath_get_global_framerange(targets, &sfra, &efra); + if (sfra > efra) { + return; + } + if (cfra < sfra || cfra > efra) { + return; + } + sfra = efra = cfra; + break; + case ANIMVIZ_CALC_RANGE_CHANGED: + /* Nothing to do here, will be handled later when iterating through the targets. */ + break; + case ANIMVIZ_CALC_RANGE_FULL: + motionpath_get_global_framerange(targets, &sfra, &efra); + if (sfra > efra) { + return; + } + break; } /* get copies of objects/bones to get the calculated results from @@ -271,16 +411,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, /* build list of all keyframes in active action for object or pchan */ BLI_dlrbTree_init(&mpt->keys); + ListBase *fcurve_list = NULL; if (adt) { - bAnimVizSettings *avs; - /* get pointer to animviz settings for each target */ - if (mpt->pchan) { - avs = &mpt->ob->pose->avs; - } - else { - avs = &mpt->ob->avs; - } + bAnimVizSettings *avs = animviz_target_settings_get(mpt); /* it is assumed that keyframes for bones are all grouped in a single group * unless an option is set to always use the whole action @@ -289,13 +423,28 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name); if (agrp) { + fcurve_list = &agrp->channels; agroup_to_keylist(adt, agrp, &mpt->keys, 0); } } else { + fcurve_list = &adt->action->curves; action_to_keylist(adt, adt->action, &mpt->keys, 0); } } + + if (range == ANIMVIZ_CALC_RANGE_CHANGED) { + int mpt_sfra, mpt_efra; + motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra); + if (mpt_sfra <= mpt_efra) { + sfra = min_ii(sfra, mpt_sfra); + efra = max_ii(efra, mpt_efra); + } + } + } + + if (sfra > efra) { + return; } /* calculate path over requested range */ @@ -306,7 +455,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, efra, efra - sfra + 1); for (CFRA = sfra; CFRA <= efra; CFRA++) { - if (current_frame_only) { + if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) { /* For current frame, only update tagged. */ BKE_scene_graph_update_tagged(depsgraph, bmain); } @@ -324,7 +473,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, * may be a temporary one that works on a subset of the data. * We always have to restore the current frame though. */ CFRA = cfra; - if (!current_frame_only && restore) { + if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) { motionpaths_calc_update_scene(bmain, depsgraph); } @@ -334,16 +483,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, /* clear recalc flags from targets */ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { - bAnimVizSettings *avs; bMotionPath *mpath = mpt->mpath; /* get pointer to animviz settings for each target */ - if (mpt->pchan) { - avs = &mpt->ob->pose->avs; - } - else { - avs = &mpt->ob->avs; - } + bAnimVizSettings *avs = animviz_target_settings_get(mpt); /* clear the flag requesting recalculation of targets */ avs->recalc &= ~ANIMVIZ_RECALC_PATHS; diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 7b9e6a10f44..64f7fe034dc 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -62,13 +62,11 @@ /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, * for the given Animation Data block. This assumes that all the destinations are valid. - * - * - add: 0 - don't add anything if not found, - * 1 - add new Driver FCurve (with keyframes for visual tweaking), - * 2 - add new Driver FCurve (with generator, for script backwards compatibility) - * -1 - add new Driver FCurve without driver stuff (for pasting) */ -FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add) +FCurve *verify_driver_fcurve(ID *id, + const char rna_path[], + const int array_index, + eDriverFCurveCreationMode creation_mode) { AnimData *adt; FCurve *fcu; @@ -80,7 +78,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde /* init animdata if none available yet */ adt = BKE_animdata_from_id(id); - if ((adt == NULL) && (add)) { + if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) { adt = BKE_animdata_add_id(id); } if (adt == NULL) { @@ -94,9 +92,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde */ fcu = list_find_fcurve(&adt->drivers, rna_path, array_index); - if ((fcu == NULL) && (add)) { + if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) { /* use default settings to make a F-Curve */ - fcu = alloc_driver_fcurve(rna_path, array_index, add); + fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode); /* just add F-Curve to end of driver list */ BLI_addtail(&adt->drivers, fcu); @@ -106,12 +104,14 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde return fcu; } -struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add) +struct FCurve *alloc_driver_fcurve(const char rna_path[], + const int array_index, + eDriverFCurveCreationMode creation_mode) { FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve"); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; /* store path - make copy, and store that */ if (rna_path) { @@ -119,18 +119,12 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, } fcu->array_index = array_index; - /* If add is negative, don't init this data yet, - * since it will be filled in by the pasted driver. */ - if (add > 0) { - BezTriple *bezt; - size_t i; - + if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) { /* add some new driver data */ fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); /* F-Modifier or Keyframes? */ - // FIXME: replace these magic numbers with defines - if (add == 2) { + if (creation_mode == DRIVER_FCURVE_GENERATOR) { /* Python API Backwards compatibility hack: * Create FModifier so that old scripts won't break * for now before 2.7 series -- (September 4, 2013) @@ -142,14 +136,10 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, * - These are configured to 0,0 and 1,1 to give a 1-1 mapping * which can be easily tweaked from there. */ - insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); - insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); - - /* configure this curve to extrapolate */ - for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) { - bezt->h1 = bezt->h2 = HD_VECT; - } - + insert_vert_fcurve( + fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF); + insert_vert_fcurve( + fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF); fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; calchandles_fcurve(fcu); } @@ -177,7 +167,8 @@ static int add_driver_with_target(ReportList *UNUSED(reports), int driver_type) { FCurve *fcu; - short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; + short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR : + DRIVER_FCURVE_KEYFRAMES; const char *prop_name = RNA_property_identifier(src_prop); /* Create F-Curve with Driver */ @@ -593,7 +584,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports), * Note: here is one of the places where we don't want new F-Curve + Driver added! * so 'add' var must be 0 */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 0); + fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY); if (fcu) { BLI_remlink(&adt->drivers, fcu); free_fcurve(fcu); @@ -653,7 +644,7 @@ bool ANIM_copy_driver( } /* try to get F-Curve with Driver */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 0); + fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY); /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ ANIM_drivers_copybuf_free(); @@ -711,7 +702,7 @@ bool ANIM_paste_driver( } /* create Driver F-Curve, but without data which will be copied across... */ - fcu = verify_driver_fcurve(id, rna_path, array_index, -1); + fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY); if (fcu) { /* copy across the curve data from the buffer curve @@ -855,7 +846,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch ANIM_driver_vars_copybuf_free(); /* Create a dummy driver F-Curve. */ - FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1); + FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES); ChannelDriver *driver = fcu->driver; /* Create a variable. */ diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index c174ce83bea..479e7192b0e 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -545,8 +545,7 @@ int actkeyblock_get_valid_hold(ActKeyColumn *ac) return 0; } - const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | - ACTKEYBLOCK_FLAG_ANY_HOLD); + const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD); return (ac->block.flag & ~ac->block.conflict) & hold_mask; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 0f8b8742659..8203a9131fa 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -202,7 +202,7 @@ FCurve *verify_fcurve(Main *bmain, fcu = MEM_callocN(sizeof(FCurve), "FCurve"); fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + fcu->auto_smoothing = U.auto_smoothing_new; if (BLI_listbase_is_empty(&act->curves)) { fcu->flag |= FCURVE_ACTIVE; /* first one added active */ } diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index eff621d7b71..c37f9ce126b 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -251,12 +251,13 @@ void *get_bone_from_selectbuffer(Base **bases, /* x and y are mouse coords (area space) */ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; rcti rect; unsigned int buffer[MAXPICKBUF]; short hits; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); // rect.xmin = ... mouseco! rect.xmin = rect.xmax = xy[0]; @@ -648,8 +649,9 @@ bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint ba bool ED_armature_edit_deselect_all_visible_multi(bContext *C) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &bases_len); @@ -674,12 +676,13 @@ static int ebone_select_flag(EditBone *ebone) bool ED_armature_edit_select_pick( bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; EditBone *nearBone = NULL; int selmask; Base *basact = NULL; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 8f4896c0b82..ad115896a43 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -182,12 +182,25 @@ static bool pose_has_protected_selected(Object *ob, short warn) /* ********************************************** */ /* Motion Paths */ +static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range) +{ + switch (range) { + case POSE_PATH_CALC_RANGE_CURRENT_FRAME: + return ANIMVIZ_CALC_RANGE_CURRENT_FRAME; + case POSE_PATH_CALC_RANGE_CHANGED: + return ANIMVIZ_CALC_RANGE_CHANGED; + case POSE_PATH_CALC_RANGE_FULL: + return ANIMVIZ_CALC_RANGE_FULL; + } + return ANIMVIZ_CALC_RANGE_FULL; +} + /* For the object with pose/action: update paths for those that have got them * This should selectively update paths that exist... * * To be called from various tools that do incremental updates */ -void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only) +void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range) { /* Transform doesn't always have context available to do update. */ if (C == NULL) { @@ -195,12 +208,12 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre } Main *bmain = CTX_data_main(C); - /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some - * nested pointers, like animation data. */ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ListBase targets = {NULL, NULL}; + ViewLayer *view_layer = CTX_data_view_layer(C); + + Depsgraph *depsgraph; bool free_depsgraph = false; + ListBase targets = {NULL, NULL}; /* set flag to force recalc, then grab the relevant bones to target */ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS; animviz_get_object_motionpaths(ob, &targets); @@ -210,7 +223,21 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre TIMEIT_START(pose_path_calc); #endif - animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only); + /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead + * of building all the relations and so on for a temporary one. */ + if (range == POSE_PATH_CALC_RANGE_CURRENT_FRAME) { + /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some + * nested pointers, like animation data. */ + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + free_depsgraph = false; + } + else { + depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets); + free_depsgraph = true; + } + + animviz_calc_motionpaths( + depsgraph, bmain, scene, &targets, pose_path_convert_range(range), !free_depsgraph); #ifdef DEBUG_TIME TIMEIT_END(pose_path_calc); @@ -218,13 +245,13 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre BLI_freelistN(&targets); - if (!current_frame_only) { + if (range != POSE_PATH_CALC_RANGE_CURRENT_FRAME) { /* Tag armature object for copy on write - so paths will draw/redraw. * For currently frame only we update evaluated object directly. */ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); } - /* Free temporary depsgraph instance */ + /* Free temporary depsgraph. */ if (free_depsgraph) { DEG_graph_free(depsgraph); } @@ -293,7 +320,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op) /* calculate the bones that now have motionpaths... */ /* TODO: only make for the selected bones? */ - ED_pose_recalculate_paths(C, scene, ob, false); + ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL); #ifdef DEBUG_TIME TIMEIT_END(recalc_pose_paths); @@ -371,7 +398,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op)) /* calculate the bones that now have motionpaths... */ /* TODO: only make for the selected bones? */ - ED_pose_recalculate_paths(C, scene, ob, false); + ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index a59067e60c1..c3a7d45f598 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -368,8 +368,9 @@ bool ED_pose_deselect_all_multi_ex(Base **bases, bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer, vc.v3d, diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 6274eb549da..7ed41b5b4d0 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -368,30 +368,14 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo switch (pso->mode) { case POSESLIDE_PUSH: /* make the current pose more pronounced */ { - /* perform a weighted average here, favoring the middle pose - * - numerator should be larger than denominator to 'expand' the result - * - perform this weighting a number of times given by the percentage... - */ - /* TODO: maybe a sensitivity ctrl on top of this is needed */ - int iters = (int)ceil(10.0f * pso->percentage); - - while (iters-- > 0) { - (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f; - } + /* Slide the pose away from the breakdown pose in the timeline */ + (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; break; } case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ { - /* perform a weighted average here, favoring the middle pose - * - numerator should be smaller than denominator to 'relax' the result - * - perform this weighting a number of times given by the percentage... - */ - /* TODO: maybe a sensitivity ctrl on top of this is needed */ - int iters = (int)ceil(10.0f * pso->percentage); - - while (iters-- > 0) { - (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f; - } + /* Slide the pose towards the breakdown pose in the timeline */ + (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; break; } case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ @@ -1003,7 +987,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p pose_slide_refresh(C, pso); /* set cursor to indicate modal */ - WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); /* header print */ pose_slide_draw_status(pso); diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 52a3f7711c4..55c9b661074 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -543,16 +543,14 @@ static void set_pose_keys(Object *ob) * \param chan: Bone that pose to paste comes from * \param selOnly: Only paste on selected bones * \param flip: Flip on x-axis - * \return Whether the bone that we pasted to if we succeeded + * \return The channel of the bone that was pasted to, or NULL if no paste was performed. */ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bool selOnly, const bool flip) { - bPoseChannel *pchan; char name[MAXBONENAME]; - short paste_ok; /* get the name - if flipping, we must flip this first */ if (flip) { @@ -567,131 +565,126 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, * 2) if selection-masking is on, channel is selected - * only selected bones get pasted on, allowing making both sides symmetrical. */ - pchan = BKE_pose_channel_find_name(ob->pose, name); - - if (selOnly) { - paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED)); + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name); + if (pchan == NULL) { + return NULL; } - else { - paste_ok = (pchan != NULL); + if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) { + return NULL; } - /* continue? */ - if (paste_ok) { - /* only loc rot size - * - only copies transform info for the pose - */ - copy_v3_v3(pchan->loc, chan->loc); - copy_v3_v3(pchan->size, chan->size); - pchan->flag = chan->flag; - - /* check if rotation modes are compatible (i.e. do they need any conversions) */ - if (pchan->rotmode == chan->rotmode) { - /* copy the type of rotation in use */ - if (pchan->rotmode > 0) { - copy_v3_v3(pchan->eul, chan->eul); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - copy_v3_v3(pchan->rotAxis, chan->rotAxis); - pchan->rotAngle = chan->rotAngle; - } - else { - copy_qt_qt(pchan->quat, chan->quat); - } - } - else if (pchan->rotmode > 0) { - /* quat/axis-angle to euler */ - if (chan->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle); - } - else { - quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat); - } + /* only loc rot size + * - only copies transform info for the pose + */ + copy_v3_v3(pchan->loc, chan->loc); + copy_v3_v3(pchan->size, chan->size); + pchan->flag = chan->flag; + + /* check if rotation modes are compatible (i.e. do they need any conversions) */ + if (pchan->rotmode == chan->rotmode) { + /* copy the type of rotation in use */ + if (pchan->rotmode > 0) { + copy_v3_v3(pchan->eul, chan->eul); } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - /* quat/euler to axis angle */ - if (chan->rotmode > 0) { - eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode); - } - else { - quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat); - } + copy_v3_v3(pchan->rotAxis, chan->rotAxis); + pchan->rotAngle = chan->rotAngle; } else { - /* euler/axis-angle to quat */ - if (chan->rotmode > 0) { - eulO_to_quat(pchan->quat, chan->eul, chan->rotmode); - } - else { - axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); - } + copy_qt_qt(pchan->quat, chan->quat); + } + } + else if (pchan->rotmode > 0) { + /* quat/axis-angle to euler */ + if (chan->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle); + } + else { + quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat); + } + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + /* quat/euler to axis angle */ + if (chan->rotmode > 0) { + eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode); + } + else { + quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat); + } + } + else { + /* euler/axis-angle to quat */ + if (chan->rotmode > 0) { + eulO_to_quat(pchan->quat, chan->eul, chan->rotmode); } + else { + axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle); + } + } - /* B-Bone posing options should also be included... */ - pchan->curve_in_x = chan->curve_in_x; - pchan->curve_in_y = chan->curve_in_y; - pchan->curve_out_x = chan->curve_out_x; - pchan->curve_out_y = chan->curve_out_y; - - pchan->roll1 = chan->roll1; - pchan->roll2 = chan->roll2; - pchan->ease1 = chan->ease1; - pchan->ease2 = chan->ease2; - pchan->scale_in_x = chan->scale_in_x; - pchan->scale_in_y = chan->scale_in_y; - pchan->scale_out_x = chan->scale_out_x; - pchan->scale_out_y = chan->scale_out_y; - - /* paste flipped pose? */ - if (flip) { - pchan->loc[0] *= -1; - - pchan->curve_in_x *= -1; - pchan->curve_out_x *= -1; - pchan->roll1 *= -1; // XXX? - pchan->roll2 *= -1; // XXX? - - /* has to be done as eulers... */ - if (pchan->rotmode > 0) { - pchan->eul[1] *= -1; - pchan->eul[2] *= -1; - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - float eul[3]; + /* B-Bone posing options should also be included... */ + pchan->curve_in_x = chan->curve_in_x; + pchan->curve_in_y = chan->curve_in_y; + pchan->curve_out_x = chan->curve_out_x; + pchan->curve_out_y = chan->curve_out_y; + + pchan->roll1 = chan->roll1; + pchan->roll2 = chan->roll2; + pchan->ease1 = chan->ease1; + pchan->ease2 = chan->ease2; + pchan->scale_in_x = chan->scale_in_x; + pchan->scale_in_y = chan->scale_in_y; + pchan->scale_out_x = chan->scale_out_x; + pchan->scale_out_y = chan->scale_out_y; + + /* paste flipped pose? */ + if (flip) { + pchan->loc[0] *= -1; - axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle); - eul[1] *= -1; - eul[2] *= -1; - eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT); - } - else { - float eul[3]; + pchan->curve_in_x *= -1; + pchan->curve_out_x *= -1; + pchan->roll1 *= -1; // XXX? + pchan->roll2 *= -1; // XXX? - normalize_qt(pchan->quat); - quat_to_eul(eul, pchan->quat); - eul[1] *= -1; - eul[2] *= -1; - eul_to_quat(pchan->quat, eul); - } + /* has to be done as eulers... */ + if (pchan->rotmode > 0) { + pchan->eul[1] *= -1; + pchan->eul[2] *= -1; } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + float eul[3]; - /* ID properties */ - if (chan->prop) { - if (pchan->prop) { - /* if we have existing properties on a bone, just copy over the values of - * matching properties (i.e. ones which will have some impact) on to the - * target instead of just blinding replacing all [ - */ - IDP_SyncGroupValues(pchan->prop, chan->prop); - } - else { - /* no existing properties, so assume that we want copies too? */ - pchan->prop = IDP_CopyProperty(chan->prop); - } + axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle); + eul[1] *= -1; + eul[2] *= -1; + eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT); + } + else { + float eul[3]; + + normalize_qt(pchan->quat); + quat_to_eul(eul, pchan->quat); + eul[1] *= -1; + eul[2] *= -1; + eul_to_quat(pchan->quat, eul); + } + } + + /* ID properties */ + if (chan->prop) { + if (pchan->prop) { + /* if we have existing properties on a bone, just copy over the values of + * matching properties (i.e. ones which will have some impact) on to the + * target instead of just blinding replacing all [ + */ + IDP_SyncGroupValues(pchan->prop, chan->prop); + } + else { + /* no existing properties, so assume that we want copies too? */ + pchan->prop = IDP_CopyProperty(chan->prop); } } - /* return whether paste went ahead */ return pchan; } @@ -831,7 +824,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op) /* Recalculate paths if any of the bones have paths... */ if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { - ED_pose_recalculate_paths(C, scene, ob, false); + ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL); } /* Notifiers for updates, */ @@ -1112,7 +1105,7 @@ static int pose_clear_transform_generic_exec(bContext *C, /* now recalculate paths */ if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { - ED_pose_recalculate_paths(C, scene, ob_iter, false); + ED_pose_recalculate_paths(C, scene, ob_iter, POSE_PATH_CALC_RANGE_FULL); } BLI_freelistN(&dsources); diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index fbaf2c896d0..8d2d7d790d2 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -32,6 +32,7 @@ #include "DNA_scene_types.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_idprop.h" #include "BKE_layer.h" @@ -223,6 +224,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob) { DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + + AnimData *adt = BKE_animdata_from_id(&ob->id); + if (adt && adt->action) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } } /* reset changes made to current pose */ @@ -327,7 +333,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, if (ob->id.tag & LIB_TAG_DOIT) { if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) { // ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear - ED_pose_recalculate_paths(C, scene, ob, false); + /* TODO(sergey): Should ensure we can use more narrow update range here. */ + ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL); } } } diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 3d2ac009072..81c9c759188 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -33,10 +33,7 @@ #include "WM_types.h" #include "ED_curve.h" -#include "ED_object.h" #include "ED_screen.h" -#include "ED_select_utils.h" -#include "ED_transform.h" #include "curve_intern.h" diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 7e878d0f905..994d844287c 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -56,13 +56,11 @@ #include "WM_api.h" #include "WM_types.h" -#include "ED_keyframes_edit.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "ED_types.h" -#include "ED_util.h" #include "ED_view3d.h" #include "ED_curve.h" @@ -4876,6 +4874,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot) bool ED_curve_editnurb_select_pick( bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Nurb *nu; BezTriple *bezt = NULL; @@ -4884,7 +4883,7 @@ bool ED_curve_editnurb_select_pick( short hand; view3d_operator_needs_opengl(C); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, mval); if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) { @@ -5635,9 +5634,10 @@ static int add_vertex_exec(bContext *C, wmOperator *op) static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) { Curve *cu; @@ -7136,7 +7136,6 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) copy_v3_v3(curve->loc, loc); copy_v3_v3(curve->size, size); - zero_v3(curve->rot); curve->texflag &= ~CU_AUTOSPACE; diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 4912ae5451d..d97223de9b8 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -44,7 +44,6 @@ #include "ED_object.h" #include "ED_screen.h" -#include "ED_undo.h" #include "ED_view3d.h" #include "ED_curve.h" diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index c7c19aa2d02..4c4bac6a249 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -31,7 +31,6 @@ #include "BKE_curve.h" #include "BKE_fcurve.h" #include "BKE_report.h" -#include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -575,9 +574,10 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) BLI_assert(op->customdata == NULL); struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); if (is_invoke) { - ED_view3d_viewcontext_init(C, &cdd->vc); + ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph); if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) { MEM_freeN(cdd); BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport"); @@ -586,7 +586,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) } else { cdd->vc.bmain = CTX_data_main(C); - cdd->vc.depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + cdd->vc.depsgraph = depsgraph; cdd->vc.scene = CTX_data_scene(C); cdd->vc.view_layer = CTX_data_view_layer(C); cdd->vc.obedit = CTX_data_edit_object(C); @@ -1064,7 +1064,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) cdd->draw_handle_view = ED_region_draw_cb_activate( cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW); - WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR); + WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH); { View3D *v3d = cdd->vc.v3d; diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index d0abcf32107..9df79a082e1 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -37,7 +37,6 @@ #include "BKE_fcurve.h" #include "BKE_layer.h" #include "BKE_report.h" -#include "BKE_object.h" #include "WM_api.h" #include "WM_types.h" @@ -278,8 +277,9 @@ bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len) bool ED_curve_deselect_all_multi(struct bContext *C) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &bases_len); @@ -684,6 +684,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot) static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Nurb *nu; BezTriple *bezt; @@ -693,7 +694,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent Base *basact = NULL; view3d_operator_needs_opengl(C); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, event->mval); if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) { @@ -1960,6 +1961,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Nurb *nu_dst; BezTriple *bezt_dst; @@ -1969,7 +1971,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE Base *basact = NULL; view3d_operator_needs_opengl(C); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, event->mval); if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) { diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index 835abd1a630..f21b4f06246 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -40,9 +40,7 @@ #include "DEG_depsgraph.h" -#include "ED_object.h" #include "ED_undo.h" -#include "ED_util.h" #include "ED_curve.h" #include "WM_types.h" diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 781eb2634fb..e11807d818f 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -60,7 +60,6 @@ #include "ED_curve.h" #include "ED_object.h" #include "ED_screen.h" -#include "ED_util.h" #include "ED_view3d.h" #include "UI_interface.h" @@ -1877,6 +1876,7 @@ void ED_curve_editfont_make(Object *obedit) memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo)); + ef->pos = cu->pos; if (ef->pos > ef->len) { ef->pos = ef->len; } @@ -1884,7 +1884,6 @@ void ED_curve_editfont_make(Object *obedit) cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0]; /* Other vars */ - ef->pos = cu->pos; ef->selstart = cu->selstart; ef->selend = cu->selend; @@ -2201,6 +2200,7 @@ void FONT_OT_unlink(wmOperatorType *ot) bool ED_curve_editfont_select_pick( bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; ViewContext vc; @@ -2212,7 +2212,7 @@ bool ED_curve_editfont_select_pick( const float dist = ED_view3d_select_dist_px(); float dist_sq_best = dist * dist; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index 2f8f15bc6c7..ae858ec4c24 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -29,7 +29,6 @@ #include "DNA_curve_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "BKE_context.h" #include "BKE_font.h" @@ -39,7 +38,6 @@ #include "ED_object.h" #include "ED_curve.h" -#include "ED_util.h" #include "WM_types.h" #include "WM_api.h" diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 765362b374e..8a3a078bdd2 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -645,6 +645,8 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.sculpt.clay_strips brush.sculpt.crease brush.sculpt.draw + brush.sculpt.draw_sharp + brush.sculpt.elastic_deform brush.sculpt.fill brush.sculpt.flatten brush.sculpt.grab @@ -653,6 +655,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.sculpt.mask brush.sculpt.nudge brush.sculpt.pinch + brush.sculpt.pose brush.sculpt.rotate brush.sculpt.scrape brush.sculpt.simplify @@ -736,6 +739,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.sculpt.border_hide ops.sculpt.border_mask ops.sculpt.lasso_mask + ops.sculpt.mesh_filter ops.transform.bone_envelope ops.transform.bone_size ops.transform.edge_slide diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c index 1a132c2957a..ecbc503e084 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c @@ -258,9 +258,9 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2 static int gizmo_button2d_cursor_get(wmGizmo *gz) { if (RNA_boolean_get(gz->ptr, "show_drag")) { - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } - return CURSOR_STD; + return WM_CURSOR_DEFAULT; } static void gizmo_button2d_free(wmGizmo *gz) diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c index ba3b8c2602e..ef4fd23b64d 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c @@ -752,30 +752,30 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz) int highlight_part = gz->highlight_part; if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) { - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } switch (highlight_part) { case ED_GIZMO_CAGE2D_PART_TRANSLATE: - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: - return CURSOR_X_MOVE; + return WM_CURSOR_X_MOVE; case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: - return CURSOR_Y_MOVE; + return WM_CURSOR_Y_MOVE; /* TODO diagonal cursor */ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; case ED_GIZMO_CAGE2D_PART_ROTATE: - return BC_CROSSCURSOR; + return WM_CURSOR_CROSS; default: - return CURSOR_STD; + return WM_CURSOR_DEFAULT; } } diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c index 406f76bc65e..723be3cfe6b 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c @@ -424,10 +424,10 @@ static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz) static int gizmo_cage3d_get_cursor(wmGizmo *gz) { if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) { - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } - return CURSOR_STD; + return WM_CURSOR_DEFAULT; } typedef struct RectTransformInteraction { diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index 37ee95d5058..5342f8695b2 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -412,7 +412,7 @@ static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop) static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz)) { - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 22f1753a810..7a10547f35c 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1560,10 +1560,10 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) static void gpencil_draw_cursor_set(tGPsdata *p) { if (p->paintmode == GP_PAINTMODE_ERASER) { - WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ + WM_cursor_modal_set(p->win, WM_CURSOR_ERASER); } else { - WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR); + WM_cursor_modal_set(p->win, WM_CURSOR_PAINT_BRUSH); } } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 2a2e7c21df4..af9cadfb938 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -52,6 +52,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_material.h" #include "BKE_object_deform.h" #include "BKE_report.h" @@ -109,6 +110,7 @@ typedef struct tGP_BrushEditData { /* Is the brush currently painting? */ bool is_painting; bool is_weight_mode; + bool is_transformed; /* Start of new sculpt stroke */ bool first; @@ -532,7 +534,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) // XXX: screen-space strokes in 3D space will suffer! if (gso->sa->spacetype == SPACE_VIEW3D) { RegionView3D *rv3d = gso->ar->regiondata; - float *rvec = gso->scene->cursor.location; + float *rvec = gso->object->loc; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); float mval_f[2]; @@ -657,7 +659,7 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) * See: gpencil_paint.c :: gp_stroke_convertcoords() */ RegionView3D *rv3d = gso->ar->regiondata; - const float *rvec = gso->scene->cursor.location; + const float *rvec = gso->object->loc; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); float mval_f[2]; @@ -1326,9 +1328,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) if (!BLI_findlink(&ob->defbase, gso->vrgroup)) { gso->vrgroup = -1; } + /* Check if some modifier can transform the stroke. */ + gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob); } else { gso->vrgroup = -1; + gso->is_transformed = false; } gso->sa = CTX_wm_area(C); @@ -1397,7 +1402,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) gpsculpt_brush_header_set(C, gso); /* setup cursor drawing */ - // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); + // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS); if (gso->sa->spacetype != SPACE_VIEW3D) { ED_gpencil_toggle_brush_cursor(C, true, NULL); } @@ -1463,7 +1468,7 @@ static bool gpsculpt_brush_poll(bContext *C) /* Init Sculpt Stroke ---------------------------------- */ -static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) +static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) { bGPdata *gpd = gso->gpd; @@ -1487,9 +1492,11 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame. */ - // XXX: should this be allowed when framelock is enabled? if (gpf->framenum != cfra) { BKE_gpencil_frame_addcopy(gpl, cfra); + /* Need tag to recalculate evaluated data to avoid crashes. */ + DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } } } @@ -1504,12 +1511,17 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) * For strokes with one point only this is impossible to calculate because there isn't a * valid reference point. */ -static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc, +static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso, bGPDstroke *gps_eval, bGPDspoint *pt_eval, int idx_eval) { + /* If multiframe or no modifiers, return 0. */ + if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) { + return 0.0f; + } + GP_SpaceConversion *gsc = &gso->gsc; bGPDstroke *gps_orig = gps_eval->runtime.gps_orig; bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig]; bGPDspoint *pt_prev_eval = NULL; @@ -1564,12 +1576,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ? gso->gp_brush->size * gso->pressure : gso->gp_brush->size; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); + bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDspoint *pt_active = NULL; bGPDspoint *pt1, *pt2; bGPDspoint *pt = NULL; int pc1[2] = {0}; int pc2[2] = {0}; int i; + int index; bool include_last = false; bool changed = false; float rot_eval = 0.0f; @@ -1579,6 +1595,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ @@ -1586,9 +1603,9 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, round_v2i_v2fl(mval_i, gso->mval); if (len_v2v2_int(mval_i, pc1) <= radius) { /* apply operation to this point */ - if (pt->runtime.pt_orig != NULL) { - rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, 0); - changed = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1); + if (pt_active != NULL) { + rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0); + changed = apply(gso, gps_active, rot_eval, 0, radius, pc1); } } } @@ -1631,9 +1648,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, /* To each point individually... */ pt = &gps->points[i]; - if (pt->runtime.pt_orig != NULL) { - rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i); - ok = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1); + pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + index = (!is_multiedit) ? pt->runtime.idx_orig : i; + if (pt_active != NULL) { + rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); + ok = apply(gso, gps_active, rot_eval, index, radius, pc1); } /* Only do the second point if this is the last segment, @@ -1646,9 +1665,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, */ if (i + 1 == gps->totpoints - 1) { pt = &gps->points[i + 1]; - if (pt->runtime.pt_orig != NULL) { - rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i + 1); - ok |= apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc2); + pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1; + if (pt_active != NULL) { + rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1); + ok |= apply(gso, gps_active, rot_eval, index, radius, pc2); include_last = false; } } @@ -1665,10 +1686,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, * (but wasn't added then, to avoid double-ups). */ pt = &gps->points[i]; - if (pt->runtime.pt_orig != NULL) { - rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i); - changed |= apply( - gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1); + pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + index = (!is_multiedit) ? pt->runtime.idx_orig : i; + if (pt_active != NULL) { + rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); + changed |= apply(gso, gps_active, rot_eval, index, radius, pc1); include_last = false; } } @@ -1688,6 +1710,7 @@ static bool gpsculpt_brush_do_frame(bContext *C, { bool changed = false; Object *ob = CTX_data_active_object(C); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ @@ -1720,18 +1743,19 @@ static bool gpsculpt_brush_do_frame(bContext *C, case GP_SCULPT_TYPE_GRAB: /* Grab points */ { - if (gps->runtime.gps_orig != NULL) { + bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + if (gps_active != NULL) { if (gso->first) { /* First time this brush stroke is being applied: * 1) Prepare data buffers (init/clear) for this stroke * 2) Use the points now under the cursor */ - gp_brush_grab_stroke_init(gso, gps->runtime.gps_orig); + gp_brush_grab_stroke_init(gso, gps_active); changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points); } else { /* Apply effect to the stored points */ - gp_brush_grab_apply_cached(gso, gps->runtime.gps_orig, diff_mat); + gp_brush_grab_apply_cached(gso, gps_active, diff_mat); changed |= true; } } @@ -1862,8 +1886,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) } /* affect strokes in this frame */ - changed |= gpsculpt_brush_do_frame( - C, gso, gpl, (gpf == gpl->actframe) ? gpf_eval : gpf, diff_mat); + changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat); } } } @@ -2079,7 +2102,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve ARegion *ar = CTX_wm_region(C); /* ensure that we'll have a new frame to draw on */ - gpsculpt_brush_init_stroke(gso); + gpsculpt_brush_init_stroke(C, gso); /* apply first dab... */ gso->is_painting = true; @@ -2194,7 +2217,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even gso->is_painting = true; gso->first = true; - gpsculpt_brush_init_stroke(gso); + gpsculpt_brush_init_stroke(C, gso); gpsculpt_brush_apply_event(C, op, event); break; diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index d72f61c64b1..67ffc6adc9f 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -492,51 +492,44 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) bGPdata *gpd_src = (bGPdata *)ob_src->data; bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src); - /* sanity checks */ + /* Sanity checks. */ if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) { return OPERATOR_CANCELLED; } - /* cannot copy itself and check destination type */ + /* Cannot copy itself and check destination type. */ if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) { return OPERATOR_CANCELLED; } bGPdata *gpd_dst = (bGPdata *)ob_dst->data; - /* make copy of layer */ - bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src); - gpl_dst->prev = gpl_dst->next = NULL; - BLI_addtail(&gpd_dst->layers, gpl_dst); - BLI_uniquename(&gpd_dst->layers, - gpl_dst, - DATA_("GP_Layer"), - '.', - offsetof(bGPDlayer, info), - sizeof(gpl_dst->info)); + /* Create new layer. */ + bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true); + /* Need to copy some variables (not all). */ + gpl_dst->onion_flag = gpl_src->onion_flag; + gpl_dst->thickness = gpl_src->thickness; + gpl_dst->line_change = gpl_src->line_change; + copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor); + gpl_dst->opacity = gpl_src->opacity; - /* copy frames */ - BLI_listbase_clear(&gpl_dst->frames); + /* Create all frames. */ for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) { if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) { continue; } - /* make a copy of source frame */ - bGPDframe *gpf_dst = MEM_dupallocN(gpf_src); - gpf_dst->prev = gpf_dst->next = NULL; - BLI_addtail(&gpl_dst->frames, gpf_dst); + /* Create new frame. */ + bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); - /* copy strokes */ - BLI_listbase_clear(&gpf_dst->strokes); + /* Copy strokes. */ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke */ + /* Make copy of source stroke. */ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); - /* check if material is in destination object, - * otherwise add the slot with the material - */ + /* Check if material is in destination object, + * otherwise add the slot with the material. */ Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1); if (ma_src != NULL) { int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src); @@ -545,7 +538,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) gps_dst->mat_nr = idx; } - /* add new stroke to frame */ + /* Add new stroke to frame. */ BLI_addtail(&gpf_dst->strokes, gps_dst); } } @@ -568,7 +561,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) }; /* identifiers */ - ot->name = "Duplicate Layer to new Object"; + ot->name = "Duplicate Layer to New Object"; ot->idname = "GPENCIL_OT_layer_duplicate_object"; ot->description = "Make a copy of the active Grease Pencil layer to new object"; @@ -799,7 +792,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op) void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot) { /* identifiers */ - ot->name = "Clean Loose points"; + ot->name = "Clean Loose Points"; ot->idname = "GPENCIL_OT_frame_clean_loose"; ot->description = "Remove loose points"; @@ -1587,7 +1580,9 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot) /* ******************* Brush create presets ************************** */ static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op)) { - BKE_brush_gpencil_presets(C); + Main *bmain = CTX_data_main(C); + ToolSettings *ts = CTX_data_tool_settings(C); + BKE_brush_gpencil_presets(bmain, ts); /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a5e9fe9b166..91ecbed7b5b 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -237,11 +237,38 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); const int mode = RNA_int_get(op->ptr, "mode"); + bool changed = false; + + if (ts->gpencil_selectmode_edit == mode) { + return OPERATOR_FINISHED; + } /* Just set mode */ ts->gpencil_selectmode_edit = mode; + /* If the mode is Stroke, extend selection. */ + if ((ob) && (ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE)) { + bGPdata *gpd = (bGPdata *)ob->data; + /* Extend selection to all points in all selected strokes. */ + CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { + if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) { + changed = true; + bGPDspoint *pt; + for (int i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + pt->flag |= GP_SPOINT_SELECT; + } + } + } + CTX_DATA_END; + if (changed) { + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } + } + + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); @@ -328,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { - BKE_brush_gpencil_presets(C); + BKE_brush_gpencil_presets(bmain, ts); } BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint); } diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index ea93f861c6e..993ec15248f 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1394,7 +1394,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW); } - WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH); gpencil_fill_status_indicators(C, tgpf); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 0bbabafb2b0..7ff6243b0d2 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -214,6 +214,8 @@ typedef struct tGPDprimitive { int sel_cp; /** flag to determine operations in progress */ int flag; + /** flag to determine operations previous mode */ + int prev_flag; /** recorded mouse-position */ float mval[2]; /** previous recorded mouse-position */ @@ -467,6 +469,7 @@ enum { GP_STROKE_CIRCLE = 2, GP_STROKE_ARC = 3, GP_STROKE_CURVE = 4, + GP_STROKE_POLYLINE = 5, }; enum { @@ -672,7 +675,9 @@ struct GP_EditableStrokes_Iter { ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* get evaluated frame with modifiers applied */ \ - bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \ + bGPDframe *gpf_eval_ = (!is_multiedit_) ? \ + &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \ + gpf_; \ /* loop over strokes */ \ for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \ /* skip strokes that are invalid for current view */ \ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 86de9a75a56..1438c33a972 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -560,7 +560,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW); /* set cursor to indicate modal */ - WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); /* update shift indicator in header */ gpencil_interpolate_status_indicators(C, tgpi); diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 930911ffac5..36cef3ccdc0 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -35,6 +35,7 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_main.h" #include "BKE_material.h" #include "WM_api.h" @@ -97,6 +98,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps, static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints) { + Main *bmain = CTX_data_main(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); @@ -111,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ - BKE_brush_gpencil_presets(C); + BKE_brush_gpencil_presets(bmain, ts); } Brush *brush = paint->brush; diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index af49587f9ad..3d56cb0fcb1 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -54,6 +54,9 @@ #include "ED_object.h" #include "ED_gpencil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* Free all of a gp-colors */ @@ -111,6 +114,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) ob = BKE_object_add_for_data( bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false); zero_v3(ob->loc); + DEG_relations_tag_update(bmain); /* added object */ /* convert grease pencil palettes (version >= 2.78) to materials and weights */ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 0a4b068a926..f29e782c618 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -598,6 +598,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) float sco[2] = {0.0f}; float a[2], b[2], c[2], d[2]; float pressure = 0.0f; + float strength = 0.0f; const float average_fac = 1.0f / steps; /* Compute smoothed coordinate by taking the ones nearby */ @@ -605,21 +606,25 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) copy_v2_v2(a, &pta->x); madd_v2_v2fl(sco, a, average_fac); pressure += pta->pressure * average_fac; + strength += pta->strength * average_fac; } if (ptb) { copy_v2_v2(b, &ptb->x); madd_v2_v2fl(sco, b, average_fac); pressure += ptb->pressure * average_fac; + strength += ptb->strength * average_fac; } if (ptc) { copy_v2_v2(c, &ptc->x); madd_v2_v2fl(sco, c, average_fac); pressure += ptc->pressure * average_fac; + strength += ptc->strength * average_fac; } if (ptd) { copy_v2_v2(d, &ptd->x); madd_v2_v2fl(sco, d, average_fac); pressure += ptd->pressure * average_fac; + strength += ptd->strength * average_fac; } /* Based on influence factor, blend between original and optimal smoothed coordinate. */ @@ -627,10 +632,156 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) copy_v2_v2(&ptc->x, c); /* Interpolate pressure. */ ptc->pressure = interpf(ptc->pressure, pressure, inf); + /* Interpolate strength. */ + ptc->strength = interpf(ptc->strength, strength, inf); +} + +/* Helper: Apply smooth to segment from Index to Index */ +static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx) +{ + const short num_points = to_idx - from_idx; + /* Do nothing if not enough points to smooth out */ + if ((num_points < 3) || (inf == 0.0f)) { + return; + } + + if (from_idx <= 2) { + return; + } + + tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer; + const float average_fac = 0.25f; + + for (int i = from_idx; i < to_idx + 1; i++) { + + tGPspoint *pta = i >= 3 ? &points[i - 3] : NULL; + tGPspoint *ptb = i >= 2 ? &points[i - 2] : NULL; + tGPspoint *ptc = i >= 1 ? &points[i - 1] : &points[i]; + tGPspoint *ptd = &points[i]; + + float sco[2] = {0.0f}; + + /* Compute smoothed coordinate by taking the ones nearby */ + if (pta) { + madd_v2_v2fl(sco, &pta->x, average_fac); + } + else { + madd_v2_v2fl(sco, &ptc->x, average_fac); + } + + if (ptb) { + madd_v2_v2fl(sco, &ptb->x, average_fac); + } + else { + madd_v2_v2fl(sco, &ptc->x, average_fac); + } + + madd_v2_v2fl(sco, &ptc->x, average_fac); + + madd_v2_v2fl(sco, &ptd->x, average_fac); + + /* Based on influence factor, blend between original and optimal smoothed coordinate. */ + interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf); + } +} + +/* Smooth all the sections created with fake events to avoid abrupt transitions. + * + * As the fake events add points between two real events, this produces a straight line, but if + * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt + * angles. + * This function reads these segments and finds the real points and smooth with the surrounding + * points. */ +static void gp_smooth_fake_segments(tGPsdata *p) +{ + bGPdata *gpd = p->gpd; + Brush *brush = p->brush; + + if (brush->gpencil_settings->input_samples < 2) { + return; + } + + tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer; + tGPspoint *pt = NULL; + /* Index where segment starts. */ + int from_idx = 0; + /* Index where segment ends. */ + int to_idx = 0; + + bool doit = false; + /* Loop all points except the extremes. */ + for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) { + pt = &points[i]; + bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE); + to_idx = i; + + /* Detect fake points in the stroke. */ + if ((!doit) && (is_fake)) { + from_idx = i; + doit = true; + } + /* If detect control point after fake points, select a segment with same length in both sides, + * except if it is more than stroke length. */ + if ((doit) && (!is_fake)) { + if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) { + to_idx = i + (i - from_idx); + /* Smooth this segments (need loop to get cumulative smooth). */ + for (int r = 0; r < 5; r++) { + gp_smooth_segment(gpd, 0.1f, from_idx, to_idx); + } + } + else { + break; + } + /* Reset to new segments. */ + from_idx = i; + doit = false; + } + } +} + +/* Smooth the section added with fake events when pen moves very fast. */ +static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after) +{ + bGPdata *gpd = p->gpd; + const short totpoints = size_after - size_before - 1; + /* Do nothing if not enough data to smooth out. */ + if (totpoints < 1) { + return; + } + + /* Back two points to get smoother effect. */ + size_before -= 2; + CLAMP_MIN(size_before, 1); + + tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer; + /* Extreme points. */ + const tGPspoint *pta = &points[size_before - 1]; + const tGPspoint *ptb = &points[size_after - 1]; + tGPspoint *pt1, *pt2; + int i; + + /* Get total length of the segment to smooth. */ + float totlen = 0.0f; + for (i = size_before; i < size_after; i++) { + pt1 = &points[i - 1]; + pt2 = &points[i]; + totlen += len_v2v2(&pt1->x, &pt2->x); + } + /* Smooth interpolating the position of the points. */ + float pointlen = 0.0f; + for (i = size_before; i < size_after - 1; i++) { + pt1 = &points[i - 1]; + pt2 = &points[i]; + pointlen += len_v2v2(&pt1->x, &pt2->x); + pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen); + pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen); + } } /* add current stroke-point to buffer (returns whether point was successfully added) */ -static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) +static short gp_stroke_addpoint( + tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; @@ -689,6 +840,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* get pointer to destination point */ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used); + /* Set if point was created by fake events. */ + if (is_fake) { + pt->tflag |= GP_TPOINT_FAKE; + } + else { + pt->tflag &= ~GP_TPOINT_FAKE; + } + /* store settings */ /* pressure */ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) { @@ -846,7 +1005,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure bGPDspoint *pts; MDeformVert *dvert = NULL; - /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ + /* First time point is adding to temporary buffer (need to allocate new point in stroke) */ if (gpd->runtime.sbuffer_used == 0) { gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); if (gps->dvert != NULL) { @@ -937,6 +1096,22 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) (!is_depth); int i, totelem; + /* For very low pressure at the end, truncate stroke. */ + if (p->paintmode == GP_PAINTMODE_DRAW) { + int last_i = gpd->runtime.sbuffer_used - 1; + while (last_i > 0) { + ptc = (tGPspoint *)gpd->runtime.sbuffer + last_i; + if (ptc->pressure > 0.001f) { + break; + } + else { + gpd->runtime.sbuffer_used = last_i - 1; + CLAMP_MIN(gpd->runtime.sbuffer_used, 1); + } + + last_i--; + } + } /* Since strokes are so fine, * when using their depth we need a margin otherwise they might get missed. */ int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; @@ -1187,6 +1362,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } } + /* Smooth any point created with fake events when the mouse/pen move very fast. */ + gp_smooth_fake_segments(p); + pt = gps->points; dvert = gps->dvert; @@ -1834,6 +2012,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft) /* initialize a drawing brush */ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1842,7 +2021,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ - BKE_brush_gpencil_presets(C); + BKE_brush_gpencil_presets(bmain, ts); changed = true; } /* be sure curves are initializated */ @@ -2489,10 +2668,10 @@ static void gpencil_draw_cursor_set(tGPsdata *p) #if 0 Brush *brush = p->brush; if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) { - WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ + WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */ } else { - WM_cursor_modal_set(p->win, CURSOR_NONE); + WM_cursor_modal_set(p->win, WM_CURSOR_NONE); } #endif } @@ -2569,7 +2748,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) /* ------------------------------- */ /* create a new stroke point at the point indicated by the painting context */ -static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) +static void gpencil_draw_apply( + bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake) { bGPdata *gpd = p->gpd; tGPspoint *pt = NULL; @@ -2598,7 +2778,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra } /* try to add point */ - short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { @@ -2612,12 +2792,12 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra /* XXX We only need to reuse previous point if overflow! */ if (ok == GP_STROKEADD_OVERFLOW) { p->inittime = p->ocurtime; - gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); + gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake); } else { p->inittime = p->curtime; } - gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -2823,8 +3003,13 @@ static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide) } /* handle draw event */ -static void gpencil_draw_apply_event( - bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) +static void gpencil_draw_apply_event(bContext *C, + wmOperator *op, + const wmEvent *event, + Depsgraph *depsgraph, + float x, + float y, + const bool is_fake) { tGPsdata *p = op->customdata; GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; @@ -2977,10 +3162,10 @@ static void gpencil_draw_apply_event( /* create fake events */ float tmp[2]; copy_v2_v2(tmp, p->mval); - gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false); if (len_v2v2(p->mval, p->mvalo)) { sub_v2_v2v2(pt, p->mval, p->mvalo); - gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false); } copy_v2_v2(p->mval, tmp); } @@ -3011,7 +3196,7 @@ static void gpencil_draw_apply_event( RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ - gpencil_draw_apply(C, op, p, depsgraph); + gpencil_draw_apply(C, op, p, depsgraph, is_fake); /* force refresh */ /* just active area for now, since doing whole screen is too slow */ @@ -3077,7 +3262,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } /* apply this data as necessary now (as per usual) */ - gpencil_draw_apply(C, op, p, depsgraph); + gpencil_draw_apply(C, op, p, depsgraph, false); } RNA_END; @@ -3211,7 +3396,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event if (paintmode != GP_PAINTMODE_ERASER) { bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) { - BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide"); + BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden"); return OPERATOR_CANCELLED; } } @@ -3250,8 +3435,6 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* TODO: set any additional settings that we can take from the events? * TODO? if tablet is erasing, force eraser to be on? */ - /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */ - /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); @@ -3272,7 +3455,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); + gpencil_draw_apply_event( + C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -3389,24 +3573,21 @@ static void gpencil_move_last_stroke_to_back(bContext *C) BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps); } -/* add events for missing mouse movements when the artist draw very fast */ -static void gpencil_add_missing_events(bContext *C, - wmOperator *op, - const wmEvent *event, - tGPsdata *p) +/* Add fake events for missing mouse movements when the artist draw very fast */ +static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p) { Brush *brush = p->brush; GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); int input_samples = brush->gpencil_settings->input_samples; - + bool added_events = false; /* ensure sampling when using circular guide */ if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) { input_samples = GP_MAX_INPUT_SAMPLES; } if (input_samples == 0) { - return; + return added_events; } RegionView3D *rv3d = p->ar->regiondata; @@ -3456,7 +3637,8 @@ static void gpencil_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, 0.5f); sub_v2_v2v2(pt, b, pt); /* create fake event */ - gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true); + added_events = true; } else if (dist >= factor) { int slices = 2 + (int)((dist - 1.0) / factor); @@ -3465,9 +3647,11 @@ static void gpencil_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, n * i); sub_v2_v2v2(pt, b, pt); /* create fake event */ - gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); + gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true); + added_events = true; } } + return added_events; } /* events handling during interactive drawing part of operator */ @@ -3476,6 +3660,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) tGPsdata *p = op->customdata; ToolSettings *ts = CTX_data_tool_settings(C); GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide; + tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer; + /* default exit state - pass through to support MMB view nav, etc. */ int estate = OPERATOR_PASS_THROUGH; @@ -3500,7 +3686,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* special mode for editing control points */ if (p->paintmode == GP_PAINTMODE_SET_CP) { wmWindow *win = p->win; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); bool drawmode = false; switch (event->type) { @@ -3598,7 +3784,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* toggle painting mode upon mouse-button movement - * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only) + * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox + * only) * - RIGHTMOUSE = polyline (hotkey) / eraser (all) * (Disabling RIGHTMOUSE case here results in bugs like [#32647]) * also making sure we have a valid event value, to not exit too early @@ -3772,11 +3959,23 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ + int size_before = p->gpd->runtime.sbuffer_used; + bool added_events = false; if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) { - gpencil_add_missing_events(C, op, event, p); + added_events = gpencil_add_fake_events(C, op, event, p); } - gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f); + gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false); + int size_after = p->gpd->runtime.sbuffer_used; + + /* Last point of the event is always real (not fake). */ + tGPspoint *pt = &points[size_after - 1]; + pt->tflag &= ~GP_TPOINT_FAKE; + + /* Smooth the fake events to get smoother strokes, specially at ends. */ + if (added_events) { + gp_smooth_fake_events(p, size_before, size_after); + } /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 8d4c75d2e8c..bf7b2edb025 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -90,6 +90,7 @@ #define IN_MOVE 3 #define IN_BRUSH_SIZE 4 #define IN_BRUSH_STRENGTH 5 +#define IN_POLYLINE 6 #define SELECT_NONE 0 #define SELECT_START 1 @@ -184,6 +185,29 @@ static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const float x, cons } } +/* Helper to constrain a primitive */ +static void gpencil_primitive_constrain(tGPDprimitive *tgpi, bool line_mode) +{ + float x = tgpi->end[0] - tgpi->origin[0]; + float y = tgpi->end[1] - tgpi->origin[1]; + + if (line_mode) { + float angle = fabsf(atan2f(y, x)); + if (angle < 0.4f || angle > (M_PI - 0.4f)) { + tgpi->end[1] = tgpi->origin[1]; + } + else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) { + tgpi->end[0] = tgpi->origin[0]; + } + else { + gpencil_primitive_to_square(tgpi, x, y); + } + } + else { + gpencil_primitive_to_square(tgpi, x, y); + } + } + /* Helper to rotate point around origin */ static void gp_rotate_v2_v2v2fl(float v[2], const float p[2], @@ -404,6 +428,11 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi "adjust subdivision number, Shift to align, Alt to center, E: extrude"), UI_MAX_DRAW_STR); } + else if (tgpi->type == GP_STROKE_POLYLINE) { + BLI_strncpy(msg_str, + TIP_("Line: ESC to cancel, LMB to set, Enter/MMB to confirm, Shift to align"), + UI_MAX_DRAW_STR); + } else if (tgpi->type == GP_STROKE_BOX) { BLI_strncpy(msg_str, TIP_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- " @@ -429,7 +458,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi UI_MAX_DRAW_STR); } - if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) { + if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX, GP_STROKE_POLYLINE)) { if (hasNumInput(&tgpi->num)) { char str_offs[NUM_STR_REP_LEN]; @@ -528,7 +557,7 @@ static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D) } /* create a line */ -static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D) +static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool editable) { const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges); const float step = 1.0f / (float)(tgpi->tot_edges - 1); @@ -540,15 +569,22 @@ static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D) a += step; } - float color[4]; - UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); - if (tgpi->tot_stored_edges) { - UI_GetThemeColor4fv(TH_REDALERT, color); - gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + if (editable) { + float color[4]; + UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); + gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL); + if (tgpi->tot_stored_edges) { + UI_GetThemeColor4fv(TH_REDALERT, color); + gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); + } + else { + gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + } } else { - gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL); + float color[4]; + UI_GetThemeColor4fv(TH_REDALERT, color); + gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL); } } @@ -693,7 +729,10 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gp_primitive_rectangle(tgpi, points2D); break; case GP_STROKE_LINE: - gp_primitive_line(tgpi, points2D); + gp_primitive_line(tgpi, points2D, true); + break; + case GP_STROKE_POLYLINE: + gp_primitive_line(tgpi, points2D, false); break; case GP_STROKE_CIRCLE: gp_primitive_circle(tgpi, points2D); @@ -1041,6 +1080,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive gp_primitive_update_strokes(C, tgpi); } +/* Initialise mouse points */ static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event) { copy_v2fl_v2i(tgpi->mval, event->mval); @@ -1134,7 +1174,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) /* if brush doesn't exist, create a new set (fix damaged files from old versions) */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { - BKE_brush_gpencil_presets(C); + BKE_brush_gpencil_presets(bmain, ts); } /* Set Draw brush. */ @@ -1164,6 +1204,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) /* set default edge count */ switch (tgpi->type) { + case GP_STROKE_POLYLINE: { + RNA_int_set(op->ptr, "edges", 8); + break; + } case GP_STROKE_LINE: { RNA_int_set(op->ptr, "edges", 8); break; @@ -1214,7 +1258,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent * op->flag |= OP_IS_MODAL_CURSOR_REGION; /* set cursor to indicate modal */ - WM_cursor_modal_set(win, BC_CROSSCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_CROSS); /* update sindicator in header */ gpencil_primitive_status_indicators(C, tgpi); @@ -1319,21 +1363,57 @@ static void gpencil_primitive_edit_event_handling( if (tgpi->flag == IN_CURVE_EDIT) { if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) { move = MOVE_ENDS; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } else if (tgpi->curve) { move = MOVE_CP; - WM_cursor_modal_set(win, BC_HANDCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_HAND); } else { - WM_cursor_modal_set(win, BC_CROSSCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_CROSS); } } else if (tgpi->flag == IN_PROGRESS) { - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } switch (event->type) { + case LEFTMOUSE: { + if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) { + /* set control points and enter edit mode */ + if ((ELEM(tgpi->type, GP_STROKE_POLYLINE))) { + gpencil_primitive_add_segment(tgpi); + copy_v2_v2(tgpi->start, tgpi->end); + copy_v2_v2(tgpi->origin, tgpi->start); + gp_primitive_update_cps(tgpi); + + tgpi->flag = IN_POLYLINE; + WM_cursor_modal_set(win, WM_CURSOR_CROSS); + } + else { + tgpi->flag = IN_CURVE_EDIT; + gp_primitive_update_cps(tgpi); + gpencil_primitive_update(C, op, tgpi); + } + } + else if ((event->val == KM_PRESS) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) { + /* find nearest cp based on stroke end points */ + if (move == MOVE_ENDS) { + tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END; + } + else if (move == MOVE_CP) { + tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2; + } + else { + tgpi->sel_cp = SELECT_NONE; + } + break; + } + else { + tgpi->sel_cp = SELECT_NONE; + } + break; + } case MOUSEMOVE: { if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) { if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) { @@ -1366,31 +1446,6 @@ static void gpencil_primitive_edit_event_handling( } break; } - case LEFTMOUSE: { - if ((event->val == KM_PRESS)) { - /* find nearest cp based on stroke end points */ - if (move == MOVE_ENDS) { - tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END; - } - else if (move == MOVE_CP) { - tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2; - } - else { - tgpi->sel_cp = SELECT_NONE; - } - break; - } - else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) { - /* set control points and enter edit mode */ - tgpi->flag = IN_CURVE_EDIT; - gp_primitive_update_cps(tgpi); - gpencil_primitive_update(C, op, tgpi); - } - else { - tgpi->sel_cp = SELECT_NONE; - } - break; - } case MKEY: { if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) { tgpi->flip ^= 1; @@ -1402,7 +1457,7 @@ static void gpencil_primitive_edit_event_handling( case EKEY: { if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) { tgpi->flag = IN_PROGRESS; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); gpencil_primitive_add_segment(tgpi); copy_v2_v2(tgpi->start, tgpi->end); copy_v2_v2(tgpi->origin, tgpi->start); @@ -1524,6 +1579,96 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e copy_v2_v2(tgpi->mvalo, tgpi->mval); return OPERATOR_RUNNING_MODAL; } + else if (tgpi->flag == IN_POLYLINE) { + + switch (event->type) { + + case ESCKEY: { + /* return to normal cursor and header status */ + ED_workspace_status_text(C, NULL); + WM_cursor_modal_restore(win); + + /* clean up temp data */ + gpencil_primitive_exit(C, op); + + /* canceled! */ + return OPERATOR_CANCELLED; + } + case LEFTMOUSE: { + if (event->val == KM_PRESS) { + WM_cursor_modal_set(win, WM_CURSOR_CROSS); + gpencil_primitive_add_segment(tgpi); + + gpencil_primitive_update(C, op, tgpi); + copy_v2_v2(tgpi->start, tgpi->end); + copy_v2_v2(tgpi->origin, tgpi->end); + } + break; + } + case SPACEKEY: /* confirm */ + case MIDDLEMOUSE: + case RETKEY: + case RIGHTMOUSE: { + if (event->val == KM_PRESS) { + tgpi->flag = IDLE; + tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0; + gp_primitive_update_strokes(C, tgpi); + gpencil_primitive_interaction_end(C, op, win, tgpi); + return OPERATOR_FINISHED; + } + break; + } + case MOUSEMOVE: { + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); + copy_v2_v2(tgpi->end, tgpi->mval); + + if (event->shift) { + gpencil_primitive_constrain(tgpi, true); + } + + gpencil_primitive_update(C, op, tgpi); + break; + } + case PADPLUSKEY: + case WHEELUPMOUSE: { + if ((event->val != KM_RELEASE)) { + tgpi->tot_edges = tgpi->tot_edges + 1; + CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); + gpencil_primitive_update(C, op, tgpi); + } + break; + } + case PADMINUS: + case WHEELDOWNMOUSE: { + if ((event->val != KM_RELEASE)) { + tgpi->tot_edges = tgpi->tot_edges - 1; + CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); + gpencil_primitive_update(C, op, tgpi); + } + break; + } + case FKEY: /* brush thickness/ brush strength */ + { + if ((event->val == KM_PRESS)) { + if (event->shift) { + tgpi->prev_flag = tgpi->flag; + tgpi->flag = IN_BRUSH_STRENGTH; + } + else { + tgpi->prev_flag = tgpi->flag; + tgpi->flag = IN_BRUSH_SIZE; + } + WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL); + } + break; + } + } + + copy_v2_v2(tgpi->mvalo, tgpi->mval); + return OPERATOR_RUNNING_MODAL; + } else if (tgpi->flag == IN_BRUSH_SIZE) { switch (event->type) { case MOUSEMOVE: @@ -1534,11 +1679,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case MIDDLEMOUSE: case LEFTMOUSE: tgpi->brush_size = 0; - tgpi->flag = IN_CURVE_EDIT; + tgpi->flag = tgpi->prev_flag; break; case RIGHTMOUSE: if (event->val == KM_RELEASE) { - tgpi->flag = IN_CURVE_EDIT; + tgpi->flag = tgpi->prev_flag; gpencil_primitive_size(tgpi, true); gpencil_primitive_update(C, op, tgpi); } @@ -1557,11 +1702,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case MIDDLEMOUSE: case LEFTMOUSE: tgpi->brush_strength = 0.0f; - tgpi->flag = IN_CURVE_EDIT; + tgpi->flag = tgpi->prev_flag; break; case RIGHTMOUSE: if (event->val == KM_RELEASE) { - tgpi->flag = IN_CURVE_EDIT; + tgpi->flag = tgpi->prev_flag; gpencil_primitive_strength(tgpi, true); gpencil_primitive_update(C, op, tgpi); } @@ -1570,7 +1715,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e copy_v2_v2(tgpi->mvalo, tgpi->mval); return OPERATOR_RUNNING_MODAL; } - else if (tgpi->flag != IDLE) { + else if (!ELEM(tgpi->flag, IDLE) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) { gpencil_primitive_edit_event_handling(C, op, win, event, tgpi); } @@ -1581,24 +1726,38 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e /* TODO: Ignore if not in main region yet */ tgpi->flag = IN_PROGRESS; gpencil_primitive_interaction_begin(tgpi, event); + if (ELEM(tgpi->type, GP_STROKE_POLYLINE)) { + tgpi->flag = IN_POLYLINE; + gpencil_primitive_update(C, op, tgpi); + return OPERATOR_RUNNING_MODAL; + } } - else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) { - tgpi->flag = IN_CURVE_EDIT; - } - else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) { + else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && + (!ELEM(tgpi->type, GP_STROKE_POLYLINE))) { /* set control points and enter edit mode */ tgpi->flag = IN_CURVE_EDIT; gp_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && - (tgpi->type != GP_STROKE_CURVE)) { + (!ELEM(tgpi->type, GP_STROKE_CURVE, GP_STROKE_POLYLINE))) { /* stop drawing primitive */ tgpi->flag = IDLE; gpencil_primitive_interaction_end(C, op, win, tgpi); /* done! */ return OPERATOR_FINISHED; } + else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) && + (ELEM(tgpi->type, GP_STROKE_POLYLINE))) { + /* set control points and enter edit mode */ + tgpi->flag = IN_POLYLINE; + gpencil_primitive_update(C, op, tgpi); + copy_v2_v2(tgpi->mvalo, tgpi->mval); + return OPERATOR_RUNNING_MODAL; + } + else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) { + tgpi->flag = IN_CURVE_EDIT; + } else { if (G.debug & G_DEBUG) { printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag); @@ -1618,7 +1777,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e /* exception to cancel current stroke when we have previous strokes in buffer */ if (tgpi->tot_stored_edges > 0) { tgpi->flag = IDLE; - tgpi->tot_edges = 0; + tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0; gp_primitive_update_strokes(C, tgpi); gpencil_primitive_interaction_end(C, op, win, tgpi); /* done! */ @@ -1665,7 +1824,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e { if ((event->val == KM_PRESS)) { tgpi->flag = IN_MOVE; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } break; } @@ -1673,12 +1832,14 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e { if ((event->val == KM_PRESS)) { if (event->shift) { + tgpi->prev_flag = tgpi->flag; tgpi->flag = IN_BRUSH_STRENGTH; } else { + tgpi->prev_flag = tgpi->flag; tgpi->flag = IN_BRUSH_SIZE; } - WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL); } break; } @@ -1704,7 +1865,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case TABKEY: { if (tgpi->flag == IN_CURVE_EDIT) { tgpi->flag = IN_PROGRESS; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); gp_primitive_update_cps(tgpi); gpencil_primitive_update(C, op, tgpi); } @@ -1712,7 +1873,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e } case MOUSEMOVE: /* calculate new position */ { - if (tgpi->flag == IN_CURVE_EDIT) { + if (ELEM(tgpi->flag, IN_CURVE_EDIT)) { break; } /* only handle mousemove if not doing numinput */ @@ -1725,26 +1886,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e } /* Keep square if shift key */ if (event->shift) { - float x = tgpi->end[0] - tgpi->origin[0]; - float y = tgpi->end[1] - tgpi->origin[1]; - if (tgpi->type == GP_STROKE_LINE || tgpi->curve) { - float angle = fabsf(atan2f(y, x)); - if (angle < 0.4f || angle > (M_PI - 0.4f)) { - tgpi->end[1] = tgpi->origin[1]; - } - else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) { - tgpi->end[0] = tgpi->origin[0]; - } - else { - gpencil_primitive_to_square(tgpi, x, y); - } - } - else { - gpencil_primitive_to_square(tgpi, x, y); - } + gpencil_primitive_constrain( + tgpi, (ELEM(tgpi->type, GP_STROKE_LINE, GP_STROKE_POLYLINE) || tgpi->curve)); } /* Center primitive if alt key */ - if (event->alt) { + if (event->alt && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) { tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]); tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]); } @@ -1796,6 +1942,7 @@ void GPENCIL_OT_primitive(wmOperatorType *ot) static EnumPropertyItem primitive_type[] = { {GP_STROKE_BOX, "BOX", 0, "Box", ""}, {GP_STROKE_LINE, "LINE", 0, "Line", ""}, + {GP_STROKE_POLYLINE, "POLYLINE", 0, "Polyline", ""}, {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""}, {GP_STROKE_ARC, "ARC", 0, "Arc", ""}, {GP_STROKE_CURVE, "CURVE", 0, "Curve", ""}, diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index b7b73c1b501..be265ed4bd5 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -832,7 +832,8 @@ void GPENCIL_OT_select_less(wmOperatorType *ot) * from gpencil_paint.c #gp_stroke_eraser_dostroke(). * It would be great to de-duplicate the logic here sometime, but that can wait. */ -static bool gp_stroke_do_circle_sel(bGPDlayer *gpl, +static bool gp_stroke_do_circle_sel(bGPdata *gpd, + bGPDlayer *gpl, bGPDstroke *gps, GP_SpaceConversion *gsc, const int mx, @@ -844,12 +845,14 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl, const int selectmode, const float scale) { + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); bGPDspoint *pt1 = NULL; bGPDspoint *pt2 = NULL; - bGPDstroke *gps_orig = gps->runtime.gps_orig; int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int i; bool changed = false; + bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDspoint *pt_active = NULL; if (gps->totpoints == 1) { bGPDspoint pt_temp; @@ -862,12 +865,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl, if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) { /* change selection */ if (select) { - gps_orig->points->flag |= GP_SPOINT_SELECT; - gps_orig->flag |= GP_STROKE_SELECT; + gps_active->points->flag |= GP_SPOINT_SELECT; + gps_active->flag |= GP_STROKE_SELECT; } else { - gps_orig->points->flag &= ~GP_SPOINT_SELECT; - gps_orig->flag &= ~GP_STROKE_SELECT; + gps_active->points->flag &= ~GP_SPOINT_SELECT; + gps_active->flag &= ~GP_STROKE_SELECT; } return true; @@ -907,20 +910,24 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl, */ hit = true; if (select) { - if (pt1->runtime.pt_orig != NULL) { - pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT; + pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + if (pt_active != NULL) { + pt_active->flag |= GP_SPOINT_SELECT; } - if (pt2->runtime.pt_orig != NULL) { - pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT; + pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2; + if (pt_active != NULL) { + pt_active->flag |= GP_SPOINT_SELECT; } changed = true; } else { - if (pt1->runtime.pt_orig != NULL) { - pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT; + pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + if (pt_active != NULL) { + pt_active->flag &= ~GP_SPOINT_SELECT; } - if (pt2->runtime.pt_orig != NULL) { - pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT; + pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2; + if (pt_active != NULL) { + pt_active->flag &= ~GP_SPOINT_SELECT; } changed = true; } @@ -935,28 +942,29 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl, /* if stroke mode expand selection */ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) { - if (pt1->runtime.pt_orig != NULL) { + pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + if (pt_active != NULL) { if (select) { - pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT; + pt_active->flag |= GP_SPOINT_SELECT; } else { - pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT; + pt_active->flag &= ~GP_SPOINT_SELECT; } } } } /* expand selection to segment */ - if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && - (pt1->runtime.pt_orig != NULL)) { + pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) { float r_hita[3], r_hitb[3]; bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT); ED_gpencil_select_stroke_segment( - gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb); + gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb); } /* Ensure that stroke selection is in sync with its points */ - BKE_gpencil_stroke_sync_selection(gps_orig); + BKE_gpencil_stroke_sync_selection(gps_active); } return changed; @@ -1016,8 +1024,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) /* find visible strokes, and select if hit */ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) { - changed |= gp_stroke_do_circle_sel( - gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale); + changed |= gp_stroke_do_circle_sel(gpd, + gpl, + gps, + &gsc, + mx, + my, + radius, + select, + &rect, + gpstroke_iter.diff_mat, + selectmode, + scale); } GP_EVALUATED_STROKES_END(gpstroke_iter); @@ -1090,6 +1108,8 @@ static int gpencil_generic_select_exec(bContext *C, ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)); const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); const float scale = ts->gp_sculpt.isect_threshold; @@ -1125,36 +1145,32 @@ static int gpencil_generic_select_exec(bContext *C, /* select/deselect points */ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) { + bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; bGPDspoint *pt; int i; bool hit = false; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->runtime.pt_orig == NULL) { + if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { continue; } + bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; /* convert point coords to screenspace */ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data); if (strokemode == false) { - const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0; + const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0; const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT); + SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT); changed = true; /* expand selection to segment */ if ((sel_op_result != -1) && (segmentmode)) { - bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT); + bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT); float r_hita[3], r_hitb[3]; - ED_gpencil_select_stroke_segment(gpl, - gps->runtime.gps_orig, - pt->runtime.pt_orig, - hit_select, - false, - scale, - r_hita, - r_hitb); + ED_gpencil_select_stroke_segment( + gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb); } } } @@ -1168,19 +1184,21 @@ static int gpencil_generic_select_exec(bContext *C, /* if stroke mode expand selection */ if (strokemode) { - const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig); + const bool is_select = BKE_gpencil_stroke_select_check(gps_active); const bool is_inside = hit; const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->runtime.pt_orig == NULL) { + if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { continue; } + bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + if (sel_op_result) { - pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT; + pt_active->flag |= GP_SPOINT_SELECT; } else { - pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT; + pt_active->flag &= ~GP_SPOINT_SELECT; } } changed = true; @@ -1188,7 +1206,7 @@ static int gpencil_generic_select_exec(bContext *C, } /* Ensure that stroke selection is in sync with its points */ - BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig); + BKE_gpencil_stroke_sync_selection(gps_active); } GP_EVALUATED_STROKES_END(gpstroke_iter); @@ -1369,6 +1387,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); ToolSettings *ts = CTX_data_tool_settings(C); const float scale = ts->gp_sculpt.isect_threshold; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ const float radius = 0.50f * U.widget_unit; @@ -1414,13 +1433,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) /* XXX: maybe we should go from the top of the stack down instead... */ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) { + bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; bGPDspoint *pt; int i; /* firstly, check for hit-point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { int xy[2]; - if (pt->runtime.pt_orig == NULL) { + if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { continue; } @@ -1437,8 +1457,8 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) /* only use this point if it is a better match than the current hit - T44685 */ if (pt_distance < hit_distance) { hit_layer = gpl; - hit_stroke = gps->runtime.gps_orig; - hit_point = pt->runtime.pt_orig; + hit_stroke = gps_active; + hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt; hit_distance = pt_distance; } } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 89a2a987f60..b194d28a8b8 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1391,7 +1391,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob) /* if not exist, create a new one */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ - BKE_brush_gpencil_presets(C); + BKE_brush_gpencil_presets(bmain, ts); } /* ensure a color exists and is assigned to object */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index cb6c66ed795..bf9b69f12e1 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -834,12 +834,28 @@ void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa); /* ************************************************ */ +typedef enum eAnimvizCalcRange { + /* Update motion paths at the current frame only. */ + ANIMVIZ_CALC_RANGE_CURRENT_FRAME, + + /* Try to limit updates to a close neighborhood of the current frame. */ + ANIMVIZ_CALC_RANGE_CHANGED, + + /* Update an entire range of the motion paths. */ + ANIMVIZ_CALC_RANGE_FULL, +} eAnimvizCalcRange; + +struct Depsgraph *animviz_depsgraph_build(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + struct ListBase *targets); + void animviz_calc_motionpaths(struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *scene, ListBase *targets, - bool restore, - bool current_frame_only); + eAnimvizCalcRange range, + bool restore); void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 173ba65fc47..7ac42967dda 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -284,10 +284,18 @@ bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility); void ED_pose_bone_select_tag_update(struct Object *ob); void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); + +/* Corresponds to eAnimvizCalcRange. */ +typedef enum ePosePathCalcRange { + POSE_PATH_CALC_RANGE_CURRENT_FRAME, + POSE_PATH_CALC_RANGE_CHANGED, + POSE_PATH_CALC_RANGE_FULL, +} ePosePathCalcRange; void ED_pose_recalculate_paths(struct bContext *C, struct Scene *scene, struct Object *ob, - bool current_frame_only); + ePosePathCalcRange range); + struct Object *ED_pose_object_from_context(struct bContext *C); /* meshlaplacian.c */ diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 37090ce3421..83890c1621c 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -98,6 +98,8 @@ struct rcti; struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile); short ED_fileselect_set_params(struct SpaceFile *sfile); +void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile); +void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, int temp_win_size[]); void ED_fileselect_reset_params(struct SpaceFile *sfile); diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 63ddc669ab2..0ff1b8bb40b 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -71,8 +71,15 @@ typedef struct tGPspoint { float uv_rot; /* uv rotation for dor mode */ float rnd[3]; /* rnd value */ bool rnd_dirty; /* rnd flag */ + short tflag; /* Internal flag */ } tGPspoint; +/* tGPspoint->flag */ +typedef enum etGPspoint_tFlag { + /* Created by Fake event (used when mouse/pen move very fast while drawing). */ + GP_TPOINT_FAKE = (1 << 0), +} etGPspoint_tFlag; + /* used to sort by zdepth gpencil objects in viewport */ /* TODO: this could be a system parameter in userprefs screen */ #define GP_CACHE_BLOCK_SIZE 16 diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 7d69f86dbf8..69742af9f50 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -77,6 +77,7 @@ void ED_image_mouse_pos(struct SpaceImage *sima, struct ARegion *ar, const int mval[2], float co[2]); +void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y); void ED_image_point_pos( struct SpaceImage *sima, struct ARegion *ar, float x, float y, float *xr, float *yr); void ED_image_point_pos__reverse(struct SpaceImage *sima, @@ -94,6 +95,7 @@ bool ED_space_image_paint_curve(const struct bContext *C); bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer); bool ED_space_image_maskedit_poll(struct bContext *C); bool ED_space_image_maskedit_mask_poll(struct bContext *C); +bool ED_space_image_cursor_poll(struct bContext *C); void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 42e5add2ef0..16b3c9c240a 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -310,15 +310,24 @@ extern EnumPropertyItem prop_driver_create_mapping_types[]; /* -------- */ +typedef enum eDriverFCurveCreationMode { + DRIVER_FCURVE_LOOKUP_ONLY = 0, /* Don't add anything if not found. */ + DRIVER_FCURVE_KEYFRAMES = 1, /* Add with keyframes, for visual tweaking. */ + DRIVER_FCURVE_GENERATOR = 2, /* Add with generator, for script backwards compatibility. */ + DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */ +} eDriverFCurveCreationMode; + /* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools, * although there are special cases where this approach is preferable. */ struct FCurve *verify_driver_fcurve(struct ID *id, const char rna_path[], const int array_index, - short add); + eDriverFCurveCreationMode creation_mode); -struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add); +struct FCurve *alloc_driver_fcurve(const char rna_path[], + const int array_index, + eDriverFCurveCreationMode creation_mode); /* -------- */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index d8d62ad6f08..fc7b0d8be8f 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -380,17 +380,17 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vert void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr); /* mesh_data.c */ -#if 0 -void ED_mesh_geometry_add( - struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces); -#endif -void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count); -void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_verts_remove(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count); -void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_loops_remove(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_polys_remove(struct Mesh *mesh, struct ReportList *reports, int count); + +void ED_mesh_geometry_clear(struct Mesh *mesh); void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index c481c19a552..38d75aa57e9 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -238,9 +238,17 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec /* object motion paths */ void ED_objects_clear_paths(struct bContext *C, bool only_selected); + +/* Corresponds to eAnimvizCalcRange. */ +typedef enum eObjectPathCalcRange { + OBJECT_PATH_CALC_RANGE_CURRENT_FRAME, + OBJECT_PATH_CALC_RANGE_CHANGED, + OBJECT_PATH_CALC_RANGE_FULL, +} eObjectPathCalcRange; + void ED_objects_recalculate_paths(struct bContext *C, struct Scene *scene, - bool current_frame_only); + eObjectPathCalcRange range); /* constraints */ struct ListBase *get_active_constraints(struct Object *ob); diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index 88cc8a85897..fec4beea809 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -40,13 +40,44 @@ void ED_imapaint_dirty_region( struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old); void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op); -/* paint_image_undo.c */ +/* image_undo.c */ void ED_image_undo_push_begin(const char *name, int paint_mode); +void ED_image_undo_push_begin_with_image(const char *name, + struct Image *image, + struct ImBuf *ibuf); + void ED_image_undo_push_end(void); void ED_image_undo_restore(struct UndoStep *us); void ED_image_undosys_type(struct UndoType *ut); +void *ED_image_paint_tile_find(struct ListBase *undo_tiles, + struct Image *ima, + struct ImBuf *ibuf, + int x_tile, + int y_tile, + unsigned short **r_mask, + bool validate); +void *ED_image_paint_tile_push(struct ListBase *undo_tiles, + struct Image *ima, + struct ImBuf *ibuf, + struct ImBuf **tmpibuf, + int x_tile, + int y_tile, + unsigned short **r_mask, + bool **r_valid, + bool use_thread_lock, + bool find_prev); +void ED_image_paint_tile_lock_init(void); +void ED_image_paint_tile_lock_end(void); + +struct ListBase *ED_image_paint_tile_list_get(void); + +#define ED_IMAGE_UNDO_TILE_BITS 6 +#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS) +#define ED_IMAGE_UNDO_TILE_NUMBER(size) \ + (((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS) + /* paint_curve_undo.c */ void ED_paintcurve_undo_push_begin(const char *name); void ED_paintcurve_undo_push_end(void); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 3ef3c0ba937..0c973f4ca88 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -40,12 +40,18 @@ int PE_start_edit(struct PTCacheEdit *edit); /* access */ struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys); -struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob); +struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); -int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]); +int PE_minmax(struct Depsgraph *depsgraph, + struct Scene *scene, + struct ViewLayer *view_layer, + float min[3], + float max[3]); struct ParticleEditSettings *PE_settings(struct Scene *scene); /* update calls */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index d0fab134dcc..c3e61f5f2b2 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -66,6 +66,7 @@ void ED_region_do_listen(struct wmWindow *win, void ED_region_do_layout(struct bContext *C, struct ARegion *ar); void ED_region_do_draw(struct bContext *C, struct ARegion *ar); void ED_region_exit(struct bContext *C, struct ARegion *ar); +void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar); void ED_region_pixelspace(struct ARegion *ar); void ED_region_update_rect(struct ARegion *ar); void ED_region_init(struct ARegion *ar); @@ -238,6 +239,15 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state); +ScrArea *ED_screen_temp_space_open(struct bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + eSpace_Type space_type, + int display_type, + bool dialog); void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg); void ED_screens_navigation_bar_tools_menu_create(struct bContext *C, diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index dc7b25392e8..28280fae3a8 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -521,7 +521,9 @@ int view3d_opengl_select(struct ViewContext *vc, /* view3d_select.c */ float ED_view3d_select_dist_px(void); -void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc); +void ED_view3d_viewcontext_init(struct bContext *C, + struct ViewContext *vc, + struct Depsgraph *depsgraph); void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact); void view3d_operator_needs_opengl(const struct bContext *C); void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index ffabace48c0..4e4db46adf6 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -858,9 +858,9 @@ DEF_ICON_BLANK(855) DEF_ICON_BLANK(856) DEF_ICON_BLANK(857) DEF_ICON_BLANK(858) -DEF_ICON_BLANK(859) -DEF_ICON_BLANK(860) -DEF_ICON_BLANK(861) +DEF_ICON(DESKTOP) +DEF_ICON(EXTERNAL_DRIVE) +DEF_ICON(NETWORK_DRIVE) /* SEQUENCE / IMAGE EDITOR */ DEF_ICON(SEQ_SEQUENCER) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 702d319817f..f5721c008b2 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -524,6 +524,7 @@ bool UI_but_is_tool(const uiBut *but); bool UI_but_is_utf8(const uiBut *but); #define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb) +bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title); bool UI_block_is_empty(const uiBlock *block); bool UI_block_can_add_separator(const uiBlock *block); @@ -1810,6 +1811,7 @@ void uiLayoutSetActivateInit(uiLayout *layout, bool active); void uiLayoutSetEnabled(uiLayout *layout, bool enabled); void uiLayoutSetRedAlert(uiLayout *layout, bool redalert); void uiLayoutSetAlignment(uiLayout *layout, char alignment); +void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size); void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect); void uiLayoutSetScaleX(uiLayout *layout, float scale); void uiLayoutSetScaleY(uiLayout *layout, float scale); @@ -1827,6 +1829,7 @@ bool uiLayoutGetActivateInit(uiLayout *layout); bool uiLayoutGetEnabled(uiLayout *layout); bool uiLayoutGetRedAlert(uiLayout *layout); int uiLayoutGetAlignment(uiLayout *layout); +bool uiLayoutGetFixedSize(uiLayout *layout); bool uiLayoutGetKeepAspect(uiLayout *layout); int uiLayoutGetWidth(uiLayout *layout); float uiLayoutGetScaleX(uiLayout *layout); @@ -2451,6 +2454,8 @@ void UI_widgetbase_draw_cache_end(void); void UI_theme_init_default(void); void UI_style_init_default(void); +void UI_interface_tag_script_reload(void); + /* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */ #define USE_UI_TOOLBAR_HACK diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index efa35c84b9e..8e04db8127e 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -234,6 +234,8 @@ typedef enum ThemeColorID { TH_DIS_MARKER, TH_PATH_BEFORE, TH_PATH_AFTER, + TH_PATH_KEYFRAME_BEFORE, + TH_PATH_KEYFRAME_AFTER, TH_CAMERA_PATH, TH_LOCK_MARKER, @@ -281,6 +283,7 @@ typedef enum ThemeColorID { TH_NLA_TWEAK, /* 'tweaking' track in NLA */ TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */ + TH_NLA_TRACK, TH_NLA_TRANSITION, TH_NLA_TRANSITION_SEL, TH_NLA_META, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index bc8d25e8d9e..d33023c69a1 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -50,6 +50,7 @@ set(SRC interface_eyedropper_datablock.c interface_eyedropper_depth.c interface_eyedropper_driver.c + interface_eyedropper_gpencil_color.c interface_handlers.c interface_icons.c interface_icons_event.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 27a33a38b15..54fd91e5361 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -786,6 +786,8 @@ static bool ui_but_update_from_old_block(const bContext *C, oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy); oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy); + SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); + /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { @@ -3389,7 +3391,7 @@ static void ui_but_build_drawstr_float(uiBut *but, double value) if (value == (double)FLT_MAX) { STR_CONCAT(but->drawstr, slen, "inf"); } - else if (value == (double)-FLT_MIN) { + else if (value == (double)-FLT_MAX) { STR_CONCAT(but->drawstr, slen, "-inf"); } else if (subtype == PROP_PERCENTAGE) { @@ -6689,3 +6691,8 @@ void UI_exit(void) ui_resources_free(); ui_but_clipboard_free(); } + +void UI_interface_tag_script_reload(void) +{ + ui_interface_tag_script_reload_queries(); +} diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 168c6051327..c8baa1a7c7b 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -243,7 +243,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str) } /* create driver */ - fcu = verify_driver_fcurve(id, path, but->rnaindex, 1); + fcu = verify_driver_fcurve(id, path, but->rnaindex, DRIVER_FCURVE_KEYFRAMES); if (fcu) { ChannelDriver *driver = fcu->driver; diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 580ff527bf6..ae6a71f17e6 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -63,7 +63,14 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) { /* Compute data path from context to property. */ + + /* If this returns null, we won't be able to bind shortcuts to these RNA properties. + * Support can be added at #wm_context_member_from_ptr. */ const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); + if (member_id == NULL) { + return NULL; + } + const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); const char *member_id_data_path = member_id; @@ -90,27 +97,35 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) return prop; } -static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **prop) +static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop) { if (but->optype) { /* Operator */ - *prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL; + *r_prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL; return but->optype->idname; } else if (but->rnaprop) { - if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) { + const PropertyType rnaprop_type = RNA_property_type(but->rnaprop); + + if (rnaprop_type == PROP_BOOLEAN) { /* Boolean */ - *prop = shortcut_property_from_rna(C, but); + *r_prop = shortcut_property_from_rna(C, but); + if (*r_prop == NULL) { + return NULL; + } return "WM_OT_context_toggle"; } - else if (RNA_property_type(but->rnaprop) == PROP_ENUM) { + else if (rnaprop_type == PROP_ENUM) { /* Enum */ - *prop = shortcut_property_from_rna(C, but); + *r_prop = shortcut_property_from_rna(C, but); + if (*r_prop == NULL) { + return NULL; + } return "WM_OT_context_menu_enum"; } } - *prop = NULL; + *r_prop = NULL; return NULL; } @@ -899,13 +914,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) if (is_array_component) { uiItemBooleanO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"), ICON_NONE, "UI_OT_copy_to_selected_button", "all", true); uiItemBooleanO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"), ICON_NONE, "UI_OT_copy_to_selected_button", "all", @@ -913,7 +928,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } else { uiItemBooleanO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"), ICON_NONE, "UI_OT_copy_to_selected_button", "all", @@ -928,7 +943,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) if (ptr->owner_id && !is_whole_array && ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) { uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"), ICON_NONE, "UI_OT_copy_as_driver_button"); } @@ -950,7 +965,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) but->search_func == ui_rna_collection_search_cb)) && ui_jump_to_target_button_poll(C)) { uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"), + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"), ICON_NONE, "UI_OT_jump_to_target_button"); uiItemS(layout); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 551e25a5986..72c31c7b39e 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -1849,9 +1849,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons cumap = (CurveMapping *)but->poin; } + float clip_size_x = BLI_rctf_size_x(&cumap->curr); + float clip_size_y = BLI_rctf_size_y(&cumap->curr); + + /* zero-sized curve */ + if (clip_size_x == 0.0f || clip_size_y == 0.0f) { + return; + } + /* calculate offset and zoom */ - float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr); - float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr); + float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / clip_size_x; + float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / clip_size_y; float offsx = cumap->curr.xmin - (1.0f / zoomx); float offsy = cumap->curr.ymin - (1.0f / zoomy); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 3c26c37b610..988dea270f5 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -69,6 +69,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver"); + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_gpencil_color"); return keymap; } diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 68c12fe7652..0cf357c508b 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -290,7 +290,7 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( { /* init */ if (eyedropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); @@ -332,7 +332,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot) /* identifiers */ ot->name = "Eyedropper"; ot->idname = "UI_OT_eyedropper_color"; - ot->description = "Sample a color from the Blender Window to store in a property"; + ot->description = "Sample a color from the Blender window to store in a property"; /* api callbacks */ ot->invoke = eyedropper_invoke; diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c index ffe93e48936..479cf9ccffe 100644 --- a/source/blender/editors/interface/interface_eyedropper_colorband.c +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -304,7 +304,7 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven { /* init */ if (eyedropper_colorband_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index 336fae45895..fd5a46e7716 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -314,7 +314,7 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED { /* init */ if (datadropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 2e51701e01d..8a48ca19db2 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -311,7 +311,7 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE { /* init */ if (depthdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c index e6fc52bc3bc..cc13367c190 100644 --- a/source/blender/editors/interface/interface_eyedropper_driver.c +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -180,7 +180,7 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS { /* init */ if (driverdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); /* add temp handler */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c new file mode 100644 index 00000000000..02d4596e93c --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -0,0 +1,324 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edinterface + * + * Eyedropper (RGB Color) + * + * Defines: + * - #UI_OT_eyedropper_gpencil_color + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "DNA_gpencil_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_report.h" + +#include "UI_interface.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_undo.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +typedef struct EyedropperGPencil { + struct ColorManagedDisplay *display; + /** color under cursor RGB */ + float color[3]; +} EyedropperGPencil; + +/* Helper: Draw status message while the user is running the operator */ +static void eyedropper_gpencil_status_indicators(bContext *C) +{ + char msg_str[UI_MAX_DRAW_STR]; + BLI_strncpy( + msg_str, TIP_("LMB: Stroke - Shift: Fill - Shift+Ctrl: Stroke + Fill"), UI_MAX_DRAW_STR); + + ED_workspace_status_text(C, msg_str); +} + +/* Initialize. */ +static bool eyedropper_gpencil_init(bContext *C, wmOperator *op) +{ + EyedropperGPencil *eye = MEM_callocN(sizeof(EyedropperGPencil), __func__); + + op->customdata = eye; + Scene *scene = CTX_data_scene(C); + + const char *display_device; + display_device = scene->display_settings.display_device; + eye->display = IMB_colormanagement_display_get_named(display_device); + + return true; +} + +/* Exit and free memory. */ +static void eyedropper_gpencil_exit(bContext *C, wmOperator *op) +{ + /* Clear status message area. */ + ED_workspace_status_text(C, NULL); + + MEM_SAFE_FREE(op->customdata); +} + +/* Set the material. */ +static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + Material *ma = NULL; + + const bool only_stroke = ((!event->ctrl) && (!event->shift)); + const bool only_fill = ((!event->ctrl) && (event->shift)); + const bool both = ((event->ctrl) && (event->shift)); + + float col_conv[4]; + bool found = false; + + /* Convert from linear rgb space to display space because grease pencil colors are in display + * space, and this conversion is needed to undo the conversion to linear performed by + * eyedropper_color_sample_fl. */ + if (eye->display) { + copy_v3_v3(col_conv, eye->color); + IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); + } + else { + copy_v3_v3(col_conv, eye->color); + } + + /* Look for a similar material in grease pencil slots. */ + short *totcol = give_totcolp(ob); + for (short i = 0; i < *totcol; i++) { + ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } + + MaterialGPencilStyle *gp_style = ma->gp_style; + if (gp_style != NULL) { + /* Check stroke color. */ + bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) && + (gp_style->flag & GP_STYLE_STROKE_SHOW); + /* Check fill color. */ + bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) && + (gp_style->flag & GP_STYLE_FILL_SHOW); + + if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) { + found = true; + } + else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) { + found = true; + } + else if ((both) && (found_stroke) && (found_fill)) { + found = true; + } + + /* Found existing material. */ + if (found) { + ob->actcol = i + 1; + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL); + WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); + return; + } + } + } + + /* If material was not found add a new material with stroke and/or fill color + * depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill) + */ + int idx; + Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx); + WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL); + DEG_relations_tag_update(bmain); + + BLI_assert(ma_new != NULL); + + MaterialGPencilStyle *gp_style_new = ma_new->gp_style; + BLI_assert(gp_style_new != NULL); + + /* Only create Stroke (default option). */ + if (only_stroke) { + /* Stroke color. */ + gp_style_new->flag |= GP_STYLE_STROKE_SHOW; + gp_style_new->flag &= ~GP_STYLE_FILL_SHOW; + copy_v3_v3(gp_style_new->stroke_rgba, col_conv); + zero_v4(gp_style_new->fill_rgba); + } + /* Fill Only. */ + else if (only_fill) { + /* Fill color. */ + gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW; + gp_style_new->flag |= GP_STYLE_FILL_SHOW; + zero_v4(gp_style_new->stroke_rgba); + copy_v3_v3(gp_style_new->fill_rgba, col_conv); + } + /* Stroke and Fill. */ + else if (both) { + gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW; + copy_v3_v3(gp_style_new->stroke_rgba, col_conv); + copy_v3_v3(gp_style_new->fill_rgba, col_conv); + } + /* Push undo for new created material. */ + ED_undo_push(C, "Add Grease Pencil Material"); +} + +/* Sample the color below cursor. */ +static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my) +{ + eyedropper_color_sample_fl(C, mx, my, eye->color); +} + +/* Cancel operator. */ +static void eyedropper_gpencil_cancel(bContext *C, wmOperator *op) +{ + eyedropper_gpencil_exit(C, op); +} + +/* Main modal status check. */ +static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperGPencil *eye = (EyedropperGPencil *)op->customdata; + /* Handle modal keymap */ + switch (event->type) { + case EVT_MODAL_MAP: { + switch (event->val) { + case EYE_MODAL_SAMPLE_BEGIN: { + return OPERATOR_RUNNING_MODAL; + } + case EYE_MODAL_CANCEL: { + eyedropper_gpencil_cancel(C, op); + return OPERATOR_CANCELLED; + } + case EYE_MODAL_SAMPLE_CONFIRM: { + eyedropper_gpencil_color_sample(C, eye, event->x, event->y); + + /* Create material. */ + eyedropper_gpencil_color_set(C, event, eye); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + eyedropper_gpencil_exit(C, op); + return OPERATOR_FINISHED; + break; + } + default: { + break; + } + } + break; + } + case MOUSEMOVE: + case INBETWEEN_MOUSEMOVE: { + eyedropper_gpencil_color_sample(C, eye, event->x, event->y); + break; + } + default: { + break; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int eyedropper_gpencil_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* Init. */ + if (eyedropper_gpencil_init(C, op)) { + /* Add modal temp handler. */ + WM_event_add_modal_handler(C, op); + /* Status message. */ + eyedropper_gpencil_status_indicators(C); + + return OPERATOR_RUNNING_MODAL; + } + else { + return OPERATOR_PASS_THROUGH; + } +} + +/* Repeat operator */ +static int eyedropper_gpencil_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_gpencil_init(C, op)) { + + /* cleanup */ + eyedropper_gpencil_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_PASS_THROUGH; + } +} + +static bool eyedropper_gpencil_poll(bContext *C) +{ + /* Only valid if the current active object is grease pencil. */ + Object *obact = CTX_data_active_object(C); + if ((obact == NULL) || (obact->type != OB_GPENCIL)) { + return false; + } + + /* Test we have a window below. */ + return (CTX_wm_window(C) != NULL); +} + +void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Eyedropper"; + ot->idname = "UI_OT_eyedropper_gpencil_color"; + ot->description = "Sample a color from the Blender Window and create Grease Pencil material"; + + /* api callbacks */ + ot->invoke = eyedropper_gpencil_invoke; + ot->modal = eyedropper_gpencil_modal; + ot->cancel = eyedropper_gpencil_cancel; + ot->exec = eyedropper_gpencil_exec; + ot->poll = eyedropper_gpencil_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index cc13c4004a4..83820c919c8 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -108,6 +108,7 @@ static int ui_do_but_EXIT(bContext *C, const wmEvent *event); static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b); static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str); +static void button_tooltip_timer_reset(bContext *C, uiBut *but); #ifdef USE_KEYNAV_LIMIT static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event); @@ -3258,7 +3259,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) ui_but_update(but); - WM_cursor_modal_set(win, BC_TEXTEDITCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT); #ifdef WITH_INPUT_IME if (is_num_but == false && BLT_lang_is_ime_supported()) { @@ -3967,8 +3968,11 @@ static bool ui_do_but_extra_operator_icon(bContext *C, uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event); if (op_icon) { + ED_region_tag_redraw(data->region); + button_tooltip_timer_reset(C, but); + ui_but_extra_operator_icon_apply(C, but, op_icon); - button_activate_exit(C, but, data, false, false); + /* Note: 'but', 'data' may now be freed, don't access. */ return true; } @@ -4217,9 +4221,8 @@ static int ui_do_but_TEX( } else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); + return WM_UI_HANDLER_BREAK; } - - return WM_UI_HANDLER_BREAK; } } else if (data->state == BUTTON_STATE_TEXT_EDITING) { @@ -4686,7 +4689,7 @@ static void ui_numedit_set_active(uiBut *but) } else { if (data->changed_cursor == false) { - WM_cursor_modal_set(data->window, CURSOR_X_MOVE); + WM_cursor_modal_set(data->window, WM_CURSOR_X_MOVE); data->changed_cursor = true; } } @@ -7494,6 +7497,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData"); data->wm = CTX_wm_manager(C); data->window = CTX_wm_window(C); + BLI_assert(ar != NULL); data->region = ar; #ifdef USE_CONT_MOUSE_CORRECT @@ -7565,7 +7569,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA if (but->type == UI_BTYPE_GRIP) { const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect)); - WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE); + WM_cursor_modal_set(data->window, horizontal ? WM_CURSOR_X_MOVE : WM_CURSOR_Y_MOVE); } else if (but->type == UI_BTYPE_NUM) { ui_numedit_set_active(but); @@ -8006,6 +8010,7 @@ void ui_but_execute_begin(struct bContext *UNUSED(C), *active_back = but->active; data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData_Fake"); but->active = data; + BLI_assert(ar != NULL); data->region = ar; } @@ -9817,9 +9822,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle if (but && (U.pie_menu_confirm > 0) && (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) { - if (but) { - return ui_but_pie_menu_apply(C, menu, but, true); - } + return ui_but_pie_menu_apply(C, menu, but, true); } retval = ui_but_pie_menu_apply(C, menu, but, true); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index b844e237366..1495fb7e716 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1583,7 +1583,6 @@ static struct { IconTextureDrawCall normal; IconTextureDrawCall border; bool enabled; - float mat[4][4]; } g_icon_draw_cache = {{{{{0}}}}}; void UI_icon_draw_cache_begin(void) diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index e1ce77b8b61..b7fd953ed63 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -171,12 +171,13 @@ void icon_draw_rect_input(float x, const bool simple_text = false; - if ((event_type >= AKEY) || (ZKEY <= event_type)) { + if ((event_type >= AKEY) && (event_type <= ZKEY)) { char str[2] = {'A' + (event_type - AKEY), '\0'}; icon_draw_rect_input_default_text(&rect, color, margin, str); } - if ((event_type >= F1KEY) || (F12KEY <= event_type)) { - char str[3] = {'F', '1' + (event_type - F1KEY), '\0'}; + else if ((event_type >= F1KEY) && (event_type <= F12KEY)) { + char str[4]; + SNPRINTF(str, "F%d", 1 + (event_type - F1KEY)); icon_draw_rect_input_default_text(&rect, color, margin, str); } else if (event_type == LEFTSHIFTKEY) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 5c73b41b778..81979b1fc8f 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -971,6 +971,9 @@ void UI_OT_eyedropper_depth(struct wmOperatorType *ot); /* interface_eyedropper_driver.c */ void UI_OT_eyedropper_driver(struct wmOperatorType *ot); +/* interface_eyedropper_gpencil_color.c */ +void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot); + /* interface_util.c */ /** @@ -993,4 +996,7 @@ void ui_rna_collection_search_cb(const struct bContext *C, /* interface_ops.c */ bool ui_jump_to_target_button_poll(struct bContext *C); +/* interface_queries.c */ +void ui_interface_tag_script_reload_queries(void); + #endif /* __INTERFACE_INTERN_H__ */ diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 6a707b56f36..a6f8ba4560d 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -130,8 +130,8 @@ typedef struct uiItem { } uiItem; enum { - UI_ITEM_FIXED = 1 << 0, - UI_ITEM_MIN = 1 << 1, + UI_ITEM_AUTO_FIXED_SIZE = 1 << 0, + UI_ITEM_FIXED_SIZE = 1 << 1, UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */ UI_ITEM_PROP_SEP = 1 << 3, @@ -307,7 +307,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool return unit_x; /* No icon or name. */ } if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) { - layout->item.flag |= UI_ITEM_MIN; + layout->item.flag |= UI_ITEM_FIXED_SIZE; } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; float margin = compact ? 1.25 : 1.50; @@ -3269,7 +3269,7 @@ static void ui_litem_estimate_row(uiLayout *litem) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); - min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); + min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE); litem->w += itemw; litem->h = MAX2(itemh, litem->h); @@ -3280,7 +3280,7 @@ static void ui_litem_estimate_row(uiLayout *litem) } if (min_size_flag) { - litem->item.flag |= UI_ITEM_MIN; + litem->item.flag |= UI_ITEM_FIXED_SIZE; } } @@ -3326,7 +3326,7 @@ static void ui_litem_layout_row(uiLayout *litem) extra_pixel = 0.0f; for (item = litem->items.first; item; item = item->next) { - if (item->flag & UI_ITEM_FIXED) { + if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) { continue; } @@ -3342,18 +3342,19 @@ static void ui_litem_layout_row(uiLayout *litem) x += neww; - bool min_flag = item->flag & UI_ITEM_MIN; + bool min_flag = item->flag & UI_ITEM_FIXED_SIZE; /* ignore min flag for rows with right or center alignment */ if (item->type != ITEM_BUTTON && ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) && - litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) { + litem->alignment == UI_LAYOUT_ALIGN_EXPAND && + ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) { min_flag = false; } if ((neww < minw || min_flag) && w != 0) { /* fixed size */ - item->flag |= UI_ITEM_FIXED; - if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) { + item->flag |= UI_ITEM_AUTO_FIXED_SIZE; + if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) { minw = itemw; } fixedw += minw; @@ -3362,7 +3363,7 @@ static void ui_litem_layout_row(uiLayout *litem) } else { /* keep free size */ - item->flag &= ~UI_ITEM_FIXED; + item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE; freew += itemw; } } @@ -3380,9 +3381,9 @@ static void ui_litem_layout_row(uiLayout *litem) ui_item_size(item, &itemw, &itemh); minw = ui_litem_min_width(itemw); - if (item->flag & UI_ITEM_FIXED) { + if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) { /* fixed minimum size items */ - if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) { + if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) { minw = itemw; } itemw = ui_item_fit( @@ -3423,7 +3424,7 @@ static void ui_litem_layout_row(uiLayout *litem) uiItem *last_item = litem->items.last; extra_pixel = litem->w - (x - litem->x); if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item && - last_item && last_item->flag & UI_ITEM_FIXED) { + last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) { ui_item_move(last_free_item, 0, extra_pixel); for (item = last_free_item->next; item; item = item->next) { ui_item_move(item, extra_pixel, extra_pixel); @@ -3449,7 +3450,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); - min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); + min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE); litem->w = MAX2(litem->w, itemw); litem->h += itemh; @@ -3460,7 +3461,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box) } if (min_size_flag) { - litem->item.flag |= UI_ITEM_MIN; + litem->item.flag |= UI_ITEM_FIXED_SIZE; } } @@ -4279,7 +4280,7 @@ static void ui_litem_layout_absolute(uiLayout *litem) static void ui_litem_estimate_split(uiLayout *litem) { ui_litem_estimate_row(litem); - litem->item.flag &= ~UI_ITEM_MIN; + litem->item.flag &= ~UI_ITEM_FIXED_SIZE; } static void ui_litem_layout_split(uiLayout *litem) @@ -5099,7 +5100,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) /* XXX uiBut hasn't scaled yet * we can flag the button as not expandable, depending on its size */ if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) { - bitem->item.flag |= UI_ITEM_MIN; + bitem->item.flag |= UI_ITEM_FIXED_SIZE; } if (layout->child_items_layout) { @@ -5119,6 +5120,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) } } +void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size) +{ + if (fixed_size) { + layout->item.flag |= UI_ITEM_FIXED_SIZE; + } + else { + layout->item.flag &= ~UI_ITEM_FIXED_SIZE; + } +} + +bool uiLayoutGetFixedSize(uiLayout *layout) +{ + return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0; +} + void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext) { layout->root->opcontext = opcontext; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index b3c46dda4c3..7ce4242c697 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -221,7 +221,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op) static void UI_OT_copy_as_driver_button(wmOperatorType *ot) { /* identifiers */ - ot->name = "Copy As New Driver"; + ot->name = "Copy as New Driver"; ot->idname = "UI_OT_copy_as_driver_button"; ot->description = "Create a new driver with this property as input, and copy it to the " @@ -453,7 +453,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op)) static void UI_OT_unset_property_button(wmOperatorType *ot) { /* identifiers */ - ot->name = "Unset property"; + ot->name = "Unset Property"; ot->idname = "UI_OT_unset_property_button"; ot->description = "Clear the property and use default or generated value in operators"; @@ -944,7 +944,7 @@ static int copy_to_selected_button_exec(bContext *C, wmOperator *op) static void UI_OT_copy_to_selected_button(wmOperatorType *ot) { /* identifiers */ - ot->name = "Copy To Selected"; + ot->name = "Copy to Selected"; ot->idname = "UI_OT_copy_to_selected_button"; ot->description = "Copy property from this object to selected objects or bones"; @@ -1092,7 +1092,7 @@ static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op)) static void UI_OT_jump_to_target_button(wmOperatorType *ot) { /* identifiers */ - ot->name = "Jump To Target"; + ot->name = "Jump to Target"; ot->idname = "UI_OT_jump_to_target_button"; ot->description = "Switch to the target object or bone"; @@ -1751,6 +1751,7 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_eyedropper_id); WM_operatortype_append(UI_OT_eyedropper_depth); WM_operatortype_append(UI_OT_eyedropper_driver); + WM_operatortype_append(UI_OT_eyedropper_gpencil_color); } /** diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 1c3d99d8bd2..34b1070f8b4 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -137,15 +137,15 @@ bool ui_but_has_array_value(const uiBut *but) PROP_COORDS)); } +static wmOperatorType *g_ot_tool_set_by_id = NULL; bool UI_but_is_tool(const uiBut *but) { /* very evil! */ if (but->optype != NULL) { - static wmOperatorType *ot = NULL; - if (ot == NULL) { - ot = WM_operatortype_find("WM_OT_tool_set_by_id", false); + if (g_ot_tool_set_by_id == NULL) { + g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false); } - if (but->optype == ot) { + if (but->optype == g_ot_tool_set_by_id) { return true; } } @@ -463,14 +463,33 @@ bool ui_block_is_popup_any(const uiBlock *block) return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block)); } -bool UI_block_is_empty(const uiBlock *block) +static const uiBut *ui_but_next_non_separator(const uiBut *but) { - for (const uiBut *but = block->buttons.first; but; but = but->next) { + for (; but; but = but->next) { if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) { - return false; + return but; } } - return true; + return NULL; +} + +bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title) +{ + const uiBut *but = block->buttons.first; + if (skip_title) { + /* Skip the first label, since popups often have a title, + * we may want to consider the block empty in this case. */ + but = ui_but_next_non_separator(but); + if (but && but->type == UI_BTYPE_LABEL) { + but = but->next; + } + } + return (ui_but_next_non_separator(but) == NULL); +} + +bool UI_block_is_empty(const uiBlock *block) +{ + return UI_block_is_empty_ex(block, false); } bool UI_block_can_add_separator(const uiBlock *block) @@ -596,3 +615,14 @@ ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manage Internal State + * \{ */ + +void ui_interface_tag_script_reload_queries(void) +{ + g_ot_tool_set_by_id = NULL; +} + +/** \} */ diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index ab3a86ec9e1..fed3c0b3d11 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -474,7 +474,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup) { - if (!UI_block_is_empty(pup->block)) { + if (!UI_block_is_empty_ex(pup->block, true)) { UI_popup_menu_end(C, pup); return true; } diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 028d99ac052..cd0421dde09 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -334,7 +334,8 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep } if (block) { - UI_block_active_only_flagged_buttons(C, CTX_wm_region(C), block); + uiPopupBlockHandle *handle = block->handle; + UI_block_active_only_flagged_buttons(C, handle->region, block); } return OPERATOR_INTERFACE; } diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 2073117d51c..63dee77e90e 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -765,7 +765,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, UI_but_tooltip_timer_remove(C, activebut); } /* standard cursor by default */ - WM_cursor_set(window, CURSOR_STD); + WM_cursor_set(window, WM_CURSOR_DEFAULT); /* create handle */ handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle"); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index aac018db24e..fe484676ddd 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3674,7 +3674,7 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Vectorscope Template +/** \name Vector-Scope Template * \{ */ void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 0ee2ed0f338..b3e039292e1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -4521,7 +4521,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect) } /* align with open menu */ - if (but->active && (but->type != UI_BTYPE_POPOVER)) { + if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) { int direction = ui_but_menu_direction(but); if (direction == UI_DIR_UP) { @@ -4638,9 +4638,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct case UI_BTYPE_SEARCH_MENU: wt = widget_type(UI_WTYPE_NAME); - if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) { - wt->wcol_theme = &btheme->tui.wcol_menu_back; - } break; case UI_BTYPE_TAB: @@ -4914,7 +4911,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol, { /* tsk, this isn't nice. */ const float unit_half = unit_size / 2; - const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect); + const float cent_x = mval_origin ? CLAMPIS(mval_origin[0], + rect->xmin + unit_size, + rect->xmax - unit_size) : + BLI_rcti_cent_x(rect); rect->ymax -= unit_half; rect->ymin += unit_half; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index bea9af99c2e..c6125478571 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -371,7 +371,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_OBCENTER_DIA: cp = &ts->obcenter_dia; break; - break; case TH_EDGE: cp = ts->edge; break; @@ -779,6 +778,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_PATH_AFTER: cp = ts->path_after; break; + case TH_PATH_KEYFRAME_BEFORE: + cp = ts->path_keyframe_before; + break; + case TH_PATH_KEYFRAME_AFTER: + cp = ts->path_keyframe_after; + break; case TH_CAMERA_PATH: cp = ts->camera_path; break; @@ -835,6 +840,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = ts->nla_tweakdupli; break; + case TH_NLA_TRACK: + cp = ts->nla_track; + break; case TH_NLA_TRANSITION: cp = ts->nla_transition; break; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 4bfff5f02cf..b1a060089ee 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1263,7 +1263,7 @@ void UI_view2d_view_restore(const bContext *C) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Gridline Drawing +/** \name Grid-Line Drawing * \{ */ /* Draw a constant grid in given 2d-region */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 032fb7e4cc2..5cf7cb4e7c4 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -256,13 +256,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltay", 0); if (v2d->keepofs & V2D_LOCKOFS_X) { - WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL); } else if (v2d->keepofs & V2D_LOCKOFS_Y) { - WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL); } else { - WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL); } /* add temp handler */ @@ -1113,13 +1113,13 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even } if (v2d->keepofs & V2D_LOCKOFS_X) { - WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL); } else if (v2d->keepofs & V2D_LOCKOFS_Y) { - WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL); } else { - WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL); } /* add temp handler */ diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index aac4da12658..573dfcde88a 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -604,6 +604,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr) uiItemL(row, IFACE_("Options:"), ICON_NONE); row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "relative_path", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, false); uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE); row = uiLayoutRow(box, false); @@ -691,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC, FILE_BLENDER, FILE_SAVE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c index 7e89ed9511f..837c5b1c6bd 100644 --- a/source/blender/editors/lattice/editlattice_select.c +++ b/source/blender/editors/lattice/editlattice_select.c @@ -89,8 +89,9 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len) bool ED_lattice_deselect_all_multi(struct bContext *C) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &bases_len); @@ -634,11 +635,12 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base) bool ED_lattice_select_pick( bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; BPoint *bp = NULL; Base *basact = NULL; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index b4ef2620895..7afd72f33c9 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -148,9 +148,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct")); } else { + double offset_val = (double)RNA_float_get(op->ptr, "offset"); bUnit_AsString2(offset_str, NUM_STR_REP_LEN, - (double)RNA_float_get(op->ptr, "offset"), + offset_val * sce->unit.scale_length, 3, B_UNIT_LENGTH, &sce->unit, diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 283e147b77b..4a511bbb5a2 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -455,7 +455,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot) 0.00001, 0.1); - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); + WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT); #ifdef USE_GIZMO WM_gizmogrouptype_append(MESH_GGT_bisect); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c index 7155348fed5..993898bddd5 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c @@ -522,7 +522,6 @@ typedef struct GizmoGroupData_SpinRedo { PropertyRNA *prop_axis_no; PropertyRNA *prop_angle; - float rotate_axis[3]; #ifdef USE_ANGLE_Z_ORIENT /* Apply 'orient_mat' for the final value. */ float orient_axis_relative[3]; diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 370cc6a2a6d..ec740447f93 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) /** * Use for intersect and boolean. */ -static void edbm_intersect_select(BMEditMesh *em) +static void edbm_intersect_select(BMEditMesh *em, bool do_select) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + if (do_select) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - BMIter iter; - BMEdge *e; + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BM_edge_select_set(em->bm, e, true); + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(em->bm, e, true); + } } } } @@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); } - if (has_isect) { - edbm_intersect_select(em); - } - else { + edbm_intersect_select(em, has_isect); + + if (!has_isect) { isect_len++; } } @@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) boolean_operation, eps); - if (has_isect) { - edbm_intersect_select(em); - } - else { + edbm_intersect_select(em, has_isect); + + if (!has_isect) { isect_len++; } } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 61f9dc43c0f..395c614f328 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2777,7 +2777,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) op->flag |= OP_IS_MODAL_CURSOR_REGION; /* add a modal handler for this operator - handles loop selection */ - WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE); WM_event_add_modal_handler(C, op); knifetool_update_mval_i(kcd, event->mval); @@ -2804,8 +2804,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) static const EnumPropertyItem modal_items[] = { {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""}, - {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""}, + {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""}, + {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""}, {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""}, diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index 3d34a4ad3b5..a709bd010aa 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -22,6 +22,7 @@ */ #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "BLI_math.h" @@ -142,10 +143,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op) /* select only tagged faces */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - /* not essential, but switch out of vertex mode since the - * selected regions wont be nicely isolated after flushing. - * note: call after de-select to avoid selection flushing */ - EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if (ob->type == OB_MESH) { + Mesh *me = (Mesh *)ob->data; + BMEditMesh *embm = me->edit_mesh; + if (embm) { + /* not essential, but switch out of vertex mode since the + * selected regions wont be nicely isolated after flushing. + * note: call after de-select to avoid selection flushing. + * note: do this on all participating meshes so this is in sync + * e.g. for later selection picking, see T68852.*/ + EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE); + } + } + } + CTX_DATA_END; BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 3be94cf99c1..3c3e91e8afe 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -386,7 +386,6 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) bool ok = true; if (is_interactive == false) { if (exec_data.base_index >= bases_len) { - return OPERATOR_CANCELLED; ok = false; } else { diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 6d51e1d3393..8d98a3bf231 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -101,16 +101,21 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) BMIter face_iter; /* Delete all unmasked faces */ + const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); + BLI_assert(cd_vert_mask_offset != -1); BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); float mask_threshold = RNA_float_get(op->ptr, "mask_threshold"); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - bool delete_face = false; + bool keep_face = true; BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) { - float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK); - delete_face = mask < mask_threshold; + const float mask = BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + if (mask < mask_threshold) { + keep_face = false; + break; + } } - BM_elem_flag_set(f, BM_ELEM_TAG, delete_face); + BM_elem_flag_set(f, BM_ELEM_TAG, !keep_face); } BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES); @@ -173,15 +178,16 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) } BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BKE_editmesh_free_derivedmesh(em); BKE_mesh_free(new_mesh); new_mesh = BKE_mesh_from_bmesh_nomain(bm, (&(struct BMeshToMeshParams){ .calc_object_remap = false, - })); + }), + mesh); - BM_mesh_free(bm); + BKE_editmesh_free(em); + MEM_freeN(em); if (new_mesh->totvert == 0) { BKE_mesh_free(new_mesh); @@ -195,8 +201,6 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits); BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true); - BKE_mesh_free(new_mesh); - if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) { BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob); } @@ -211,6 +215,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) } } + BKE_mesh_calc_normals(new_ob->data); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob); BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL); DEG_relations_tag_update(bmain); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index cad9e9a3d06..3e59a884696 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2642,8 +2642,9 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len) bool EDBM_mesh_deselect_all_multi(struct bContext *C) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &bases_len); @@ -4219,7 +4220,8 @@ void MESH_OT_select_nth(wmOperatorType *ot) void em_setup_viewcontext(bContext *C, ViewContext *vc) { - ED_view3d_viewcontext_init(C, vc); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_viewcontext_init(C, vc, depsgraph); if (vc->obedit) { vc->em = BKE_editmesh_from_object(vc->obedit); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 0c4db012786..a20ae5fc1ac 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3161,7 +3161,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi); + BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi); return OPERATOR_FINISHED; } @@ -3872,7 +3872,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot) /* internal */ RNA_def_int( - ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS); + ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM); } /** \} */ @@ -3946,6 +3946,61 @@ static Base *mesh_separate_tagged( return base_new; } +static Base *mesh_separate_arrays(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + Base *base_old, + BMesh *bm_old, + BMVert **verts, + uint verts_len, + BMEdge **edges, + uint edges_len, + BMFace **faces, + uint faces_len) +{ + Base *base_new; + Object *obedit = base_old->object; + BMesh *bm_new; + + bm_new = BM_mesh_create(&bm_mesh_allocsize_default, + &((struct BMeshCreateParams){ + .use_toolflags = true, + })); + + CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + + CustomData_bmesh_init_pool(&bm_new->vdata, verts_len, BM_VERT); + CustomData_bmesh_init_pool(&bm_new->edata, edges_len, BM_EDGE); + CustomData_bmesh_init_pool(&bm_new->ldata, faces_len * 3, BM_LOOP); + CustomData_bmesh_init_pool(&bm_new->pdata, faces_len, BM_FACE); + + base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH); + + /* normally would call directly after but in this case delay recalc */ + /* DAG_relations_tag_update(bmain); */ + + /* new in 2.5 */ + assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); + + ED_object_base_select(base_new, BA_SELECT); + + BM_mesh_copy_arrays(bm_old, bm_new, verts, verts_len, edges, edges_len, faces, faces_len); + + for (uint i = 0; i < verts_len; i++) { + BM_vert_kill(bm_old, verts[i]); + } + + BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0})); + + BM_mesh_free(bm_new); + ((Mesh *)base_new->object->data)->edit_mesh = NULL; + + return base_new; +} + static bool mesh_separate_selected( Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { @@ -3959,41 +4014,6 @@ static bool mesh_separate_selected( return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); } -/* flush a hflag to from verts to edges/faces */ -static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag) -{ - BMEdge *e; - BMLoop *l_iter; - BMLoop *l_first; - BMFace *f; - - BMIter eiter; - BMIter fiter; - - bool ok; - - BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e->v1, hflag) && BM_elem_flag_test(e->v2, hflag)) { - BM_elem_flag_enable(e, hflag); - } - else { - BM_elem_flag_disable(e, hflag); - } - } - BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - ok = true; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BM_elem_flag_test(l_iter->v, hflag)) { - ok = false; - break; - } - } while ((l_iter = l_iter->next) != l_first); - - BM_elem_flag_set(f, hflag, ok); - } -} - /** * Sets an object to a single material. from one of its slots. * @@ -4109,72 +4129,64 @@ static bool mesh_separate_material( static bool mesh_separate_loose( Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old) { - int i; - BMEdge *e; - BMVert *v_seed; - BMWalker walker; - bool result = false; - int max_iter = bm_old->totvert; + /* Without this, we duplicate the object mode mesh for each loose part. + * This can get very slow especially for large meshes with many parts + * which would duplicate the mesh on entering edit-mode. */ + const bool clear_object_data = true; - /* Clear all selected vertices */ - BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + bool result = false; - /* A "while (true)" loop should work here as each iteration should - * select and remove at least one vertex and when all vertices - * are selected the loop will break out. But guard against bad - * behavior by limiting iterations to the number of vertices in the - * original mesh.*/ - for (i = 0; i < max_iter; i++) { - int tot = 0; - /* Get a seed vertex to start the walk */ - v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0); + BMVert **vert_groups = MEM_mallocN(sizeof(*vert_groups) * bm_old->totvert, __func__); + BMEdge **edge_groups = MEM_mallocN(sizeof(*edge_groups) * bm_old->totedge, __func__); + BMFace **face_groups = MEM_mallocN(sizeof(*face_groups) * bm_old->totface, __func__); + + int(*groups)[3] = NULL; + int groups_len = BM_mesh_calc_edge_groups_as_arrays( + bm_old, vert_groups, edge_groups, face_groups, &groups); + if (groups_len <= 1) { + goto finally; + } + + if (clear_object_data) { + ED_mesh_geometry_clear(base_old->object->data); + } + + /* Separate out all groups except the first. */ + uint group_ofs[3] = {UNPACK3(groups[0])}; + for (int i = 1; i < groups_len; i++) { + Base *base_new = mesh_separate_arrays(bmain, + scene, + view_layer, + base_old, + bm_old, + vert_groups + group_ofs[0], + groups[i][0], + edge_groups + group_ofs[1], + groups[i][1], + face_groups + group_ofs[2], + groups[i][2]); + result |= (base_new != NULL); - /* No vertices available, can't do anything */ - if (v_seed == NULL) { - break; - } + group_ofs[0] += groups[i][0]; + group_ofs[1] += groups[i][1]; + group_ofs[2] += groups[i][2]; + } - /* Select the seed explicitly, in case it has no edges */ - if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) { - BM_elem_flag_enable(v_seed, BM_ELEM_TAG); - tot++; - } + Mesh *me_old = base_old->object->data; + BMEditMesh *em_old = me_old->edit_mesh; - /* Walk from the single vertex, selecting everything connected - * to it */ - BMW_init(&walker, - bm_old, - BMW_VERT_SHELL, - BMW_MASK_NOP, - BMW_MASK_NOP, - BMW_MASK_NOP, - BMW_FLAG_NOP, - BMW_NIL_LAY); + BM_mesh_elem_hflag_disable_all(em_old->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) { - if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) { - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - tot++; - } - if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); - tot++; - } - } - BMW_end(&walker); - - if (bm_old->totvert == tot) { - /* Every vertex selected, nothing to separate, work is done */ - break; - } + if (clear_object_data) { + BM_mesh_bm_to_me(NULL, em_old->bm, me_old, (&(struct BMeshToMeshParams){0})); + } - /* Flush the selection to get edge/face selections matching - * the vertex selection */ - bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); +finally: + MEM_freeN(vert_groups); + MEM_freeN(edge_groups); + MEM_freeN(face_groups); - /* Move selection into a separate object */ - result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL); - } + MEM_freeN(groups); return result; } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 569994bead1..7007ff29401 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -880,14 +880,14 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose) { - if (calc_edges_loose && mesh->totedge) { - BKE_mesh_calc_edges_loose(mesh); - } - if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) { BKE_mesh_calc_edges(mesh, calc_edges, true); } + if (calc_edges_loose && mesh->totedge) { + BKE_mesh_calc_edges_loose(mesh); + } + /* Default state is not to have tessface's so make sure this is the case. */ BKE_mesh_tessface_clear(mesh); @@ -1023,73 +1023,104 @@ static void mesh_add_polys(Mesh *mesh, int len) mesh->totpoly = totpoly; } -static void mesh_remove_verts(Mesh *mesh, int len) +/* -------------------------------------------------------------------- */ +/** \name Add Geometry + * \{ */ + +void ED_mesh_verts_add(Mesh *mesh, ReportList *reports, int count) { - int totvert; + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode"); + return; + } + mesh_add_verts(mesh, count); +} - if (len == 0) { +void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count) +{ + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode"); + return; + } + mesh_add_edges(mesh, count); +} + +void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count) +{ + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode"); return; } + mesh_add_loops(mesh, count); +} - totvert = mesh->totvert - len; - CustomData_free_elem(&mesh->vdata, totvert, len); +void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count) +{ + if (mesh->edit_mesh) { + BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode"); + return; + } + mesh_add_polys(mesh, count); +} - /* set final vertex list size */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Geometry + * \{ */ + +static void mesh_remove_verts(Mesh *mesh, int len) +{ + if (len == 0) { + return; + } + const int totvert = mesh->totvert - len; + CustomData_free_elem(&mesh->vdata, totvert, len); mesh->totvert = totvert; } static void mesh_remove_edges(Mesh *mesh, int len) { - int totedge; - if (len == 0) { return; } - - totedge = mesh->totedge - len; + const int totedge = mesh->totedge - len; CustomData_free_elem(&mesh->edata, totedge, len); - mesh->totedge = totedge; } -#if 0 -void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces) +static void mesh_remove_loops(Mesh *mesh, int len) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add geometry in edit mode"); + if (len == 0) { return; } - - if (verts) { - mesh_add_verts(mesh, verts); - } - if (edges) { - mesh_add_edges(mesh, edges); - } - if (faces) { - mesh_add_faces(mesh, faces); - } + const int totloop = mesh->totloop - len; + CustomData_free_elem(&mesh->ldata, totloop, len); + mesh->totloop = totloop; } -#endif -void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count) +static void mesh_remove_polys(Mesh *mesh, int len) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode"); + if (len == 0) { return; } - - mesh_add_edges(mesh, count); + const int totpoly = mesh->totpoly - len; + CustomData_free_elem(&mesh->pdata, totpoly, len); + mesh->totpoly = totpoly; } -void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count) +void ED_mesh_verts_remove(Mesh *mesh, ReportList *reports, int count) { if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode"); + BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode"); + return; + } + else if (count > mesh->totvert) { + BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains"); return; } - mesh_add_verts(mesh, count); + mesh_remove_verts(mesh, count); } void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count) @@ -1106,40 +1137,44 @@ void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count) mesh_remove_edges(mesh, count); } -void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count) +void ED_mesh_loops_remove(Mesh *mesh, ReportList *reports, int count) { if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode"); + BKE_report(reports, RPT_ERROR, "Cannot remove loops in edit mode"); return; } - else if (count > mesh->totvert) { - BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains"); + else if (count > mesh->totloop) { + BKE_report(reports, RPT_ERROR, "Cannot remove more loops than the mesh contains"); return; } - mesh_remove_verts(mesh, count); + mesh_remove_loops(mesh, count); } -void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count) +void ED_mesh_polys_remove(Mesh *mesh, ReportList *reports, int count) { if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode"); + BKE_report(reports, RPT_ERROR, "Cannot remove polys in edit mode"); + return; + } + else if (count > mesh->totpoly) { + BKE_report(reports, RPT_ERROR, "Cannot remove more polys than the mesh contains"); return; } - mesh_add_loops(mesh, count); + mesh_remove_polys(mesh, count); } -void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count) +void ED_mesh_geometry_clear(Mesh *mesh) { - if (mesh->edit_mesh) { - BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode"); - return; - } - - mesh_add_polys(mesh, count); + mesh_remove_verts(mesh, mesh->totvert); + mesh_remove_edges(mesh, mesh->totedge); + mesh_remove_loops(mesh, mesh->totloop); + mesh_remove_polys(mesh, mesh->totpoly); } +/** \} */ + void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail, char selectmode) { const char *elem_type; diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index c68f5963cbd..a918996563f 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -54,6 +54,7 @@ #include "BKE_multires.h" #include "BKE_object.h" #include "BKE_object_deform.h" +#include "BKE_object_facemap.h" #include "BKE_report.h" #include "DEG_depsgraph.h" @@ -267,6 +268,22 @@ static void join_mesh_single(Depsgraph *depsgraph, mpoly->loopstart += *loopofs; mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0; } + + /* Face maps. */ + int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP); + int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP); + + /* Remap to correct new face-map indices, if needed. */ + if (fmap_src) { + BLI_assert(fmap != NULL); + int *fmap_index_map; + int fmap_index_map_len; + fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len); + BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len); + if (fmap_index_map != NULL) { + MEM_freeN(fmap_index_map); + } + } } /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */ @@ -403,7 +420,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) key->type = KEY_RELATIVE; } - /* first pass over objects - copying materials and vertexgroups across */ + /* First pass over objects: Copying materials, vertex-groups & face-maps across. */ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { /* only act if a mesh, and not the one we're joining to */ if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) { @@ -422,6 +439,19 @@ int join_mesh_exec(bContext *C, wmOperator *op) ob->actdef = 1; } + /* Join this object's face maps to the base one's. */ + for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) { + /* See if this group exists in the object (if it doesn't, add it to the end) */ + if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) { + bFaceMap *fmap_new = MEM_callocN(sizeof(bFaceMap), "join faceMap"); + memcpy(fmap_new, fmap, sizeof(bFaceMap)); + BLI_addtail(&ob->fmaps, fmap_new); + } + } + if (ob->fmaps.first && ob->actfmap == 0) { + ob->actfmap = 1; + } + if (me->totvert) { /* Add this object's materials to the base one's if they don't exist already * (but only if limits not exceeded yet) */ @@ -1110,7 +1140,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, return false; } - ED_view3d_viewcontext_init(C, &vc); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ED_view3d_select_id_validate(&vc); if (dist_px) { @@ -1291,7 +1322,8 @@ bool ED_mesh_pick_vert( return false; } - ED_view3d_viewcontext_init(C, &vc); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ED_view3d_select_id_validate(&vc); if (use_zbuf) { diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 18ff7ae1a5e..64ae75a0ee8 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -693,13 +693,14 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot) * stiffness circle) */ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); static MetaElem *startelem = NULL; ViewContext vc; int a, hits; unsigned int buffer[MAXPICKBUF]; rcti rect; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); BLI_rcti_init_pt_radius(&rect, mval, 12); @@ -835,8 +836,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese bool ED_mball_deselect_all_multi(bContext *C) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &bases_len); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 3d5ec3d4ed5..716ff94bbae 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1030,7 +1030,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv return OPERATOR_CANCELLED; } /* handled below */ - id_us_min((ID *)ima); + id_us_min(&ima->id); Object *ob = NULL; Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval); @@ -1071,7 +1071,7 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Add Empty Image/Drop Image To Empty"; + ot->name = "Add Empty Image/Drop Image to Empty"; ot->description = "Add an empty image type to scene with data"; ot->idname = "OBJECT_OT_drop_named_image"; @@ -2147,6 +2147,7 @@ static int convert_exec(bContext *C, wmOperator *op) const bool gpencil_lines = RNA_boolean_get(op->ptr, "gpencil_lines"); const bool use_collections = RNA_boolean_get(op->ptr, "use_collections"); int a, mballConverted = 0; + bool gpencilConverted = false; /* don't forget multiple users! */ @@ -2387,20 +2388,20 @@ static int convert_exec(bContext *C, wmOperator *op) } else if (target == OB_GPENCIL) { if (ob->type != OB_CURVE) { + ob->flag &= ~OB_DONE; BKE_report( op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported."); } else { - /* Create a new grease pencil object only if it was not created before. - * All curves selected are converted as strokes of the same grease pencil object. + /* Create a new grease pencil object and copy transformations. * Nurbs Surface are not supported. */ - if (gpencil_ob == NULL) { - const float *cur = scene->cursor.location; - ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; - gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits); - } + ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; + gpencil_ob = ED_gpencil_add_object(C, scene, ob->loc, local_view_bits); + copy_v3_v3(gpencil_ob->rot, ob->rot); + copy_v3_v3(gpencil_ob->scale, ob->scale); BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true); + gpencilConverted = true; } } } @@ -2500,6 +2501,17 @@ static int convert_exec(bContext *C, wmOperator *op) } FOREACH_SCENE_OBJECT_END; } + /* Remove curves converted to Grease Pencil object. */ + if (gpencilConverted) { + FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) { + if (ob_curve->type == OB_CURVE) { + if (ob_curve->flag & OB_DONE) { + ED_object_base_free_and_unlink(bmain, scene, ob_curve); + } + } + } + FOREACH_SCENE_OBJECT_END; + } } // XXX ED_object_editmode_enter(C, 0); @@ -2585,7 +2597,7 @@ static Base *object_add_duplicate_internal( DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { BKE_collection_object_add_from(bmain, scene, ob, obn); } else { diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 70a9870e6ae..bc79521ee9b 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -371,7 +371,7 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) ob = base->object; - multires_force_update(ob); + multires_flush_sculpt_updates(ob); /* copy data stored in job descriptor */ bkr.scene = scene; @@ -435,7 +435,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) ob = base->object; - multires_force_update(ob); + multires_flush_sculpt_updates(ob); data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data"); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index d9baec7c3ca..9e9cfe1beed 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -879,7 +879,7 @@ static int bake(Render *re, else { ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage); ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); } } } @@ -976,7 +976,7 @@ static int bake(Render *re, highpoly[i].ob = ob_iter; highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; - highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); + highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false); /* lowpoly to highpoly transformation matrix */ @@ -992,10 +992,10 @@ static int bake(Render *re, if (ob_cage != NULL) { ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); } ob_low_eval->restrictflag |= OB_RESTRICT_RENDER; - ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER); + ob_low_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects(me_low, diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c index fcaefaf220d..a00e5e7b198 100644 --- a/source/blender/editors/object/object_collection.c +++ b/source/blender/editors/object/object_collection.c @@ -186,7 +186,7 @@ void COLLECTION_OT_objects_add_active(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Add Selected To Active Collection"; + ot->name = "Add Selected to Active Collection"; ot->description = "Add the object to an object collection that contains the active object"; ot->idname = "COLLECTION_OT_objects_add_active"; @@ -259,7 +259,7 @@ void COLLECTION_OT_objects_remove_active(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Remove Selected From Active Collection"; + ot->name = "Remove Selected from Active Collection"; ot->description = "Remove the object from an object collection that contains the active object"; ot->idname = "COLLECTION_OT_objects_remove_active"; @@ -302,7 +302,7 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op void COLLECTION_OT_objects_remove_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "Remove From All Unlinked Collections"; + ot->name = "Remove from All Unlinked Collections"; ot->description = "Remove selected objects from all collections not used in a scene"; ot->idname = "COLLECTION_OT_objects_remove_all"; @@ -361,7 +361,7 @@ void COLLECTION_OT_objects_remove(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Remove From Collection"; + ot->name = "Remove from Collection"; ot->description = "Remove selected objects from a collection"; ot->idname = "COLLECTION_OT_objects_remove"; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 74abe104134..70d024c7902 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op) /* Hide selected or unselected objects. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (!(base->flag & BASE_VISIBLE)) { + if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { continue; } @@ -292,7 +292,7 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); if (v3d->flag & V3D_LOCAL_COLLECTIONS) { - if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { + if (lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) { return OPERATOR_CANCELLED; } if (toggle) { @@ -300,11 +300,11 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op) BKE_layer_collection_local_sync(view_layer, v3d); } else { - BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend); + BKE_layer_collection_isolate_local(view_layer, v3d, lc, extend); } } else { - BKE_layer_collection_isolate(scene, view_layer, lc, extend); + BKE_layer_collection_isolate_global(scene, view_layer, lc, extend); } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -910,12 +910,25 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot) /* ********************************************** */ /* Motion Paths */ +static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range) +{ + switch (range) { + case OBJECT_PATH_CALC_RANGE_CURRENT_FRAME: + return ANIMVIZ_CALC_RANGE_CURRENT_FRAME; + case OBJECT_PATH_CALC_RANGE_CHANGED: + return ANIMVIZ_CALC_RANGE_CHANGED; + case OBJECT_PATH_CALC_RANGE_FULL: + return ANIMVIZ_CALC_RANGE_FULL; + } + return ANIMVIZ_CALC_RANGE_FULL; +} + /* For the objects with animation: update paths for those that have got them * This should selectively update paths that exist... * * To be called from various tools that do incremental updates */ -void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only) +void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range) { /* Transform doesn't always have context available to do update. */ if (C == NULL) { @@ -923,11 +936,9 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_ } Main *bmain = CTX_data_main(C); - /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some - * nested pointers, like animation data. */ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ListBase targets = {NULL, NULL}; + ViewLayer *view_layer = CTX_data_view_layer(C); + ListBase targets = {NULL, NULL}; /* loop over objects in scene */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* set flag to force recalc, then grab path(s) from object */ @@ -936,11 +947,27 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_ } CTX_DATA_END; + Depsgraph *depsgraph; + bool free_depsgraph = false; + /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead + * of building all the relations and so on for a temporary one. */ + if (range == OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) { + /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some + * nested pointers, like animation data. */ + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + free_depsgraph = false; + } + else { + depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets); + free_depsgraph = true; + } + /* recalculate paths, then free */ - animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only); + animviz_calc_motionpaths( + depsgraph, bmain, scene, &targets, object_path_convert_range(range), true); BLI_freelistN(&targets); - if (!current_frame_only) { + if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) { /* Tag objects for copy on write - so paths will draw/redraw * For currently frame only we update evaluated object directly. */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { @@ -950,6 +977,11 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_ } CTX_DATA_END; } + + /* Free temporary depsgraph. */ + if (free_depsgraph) { + DEG_graph_free(depsgraph); + } } /* show popup to determine settings */ @@ -995,7 +1027,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene, false); + ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1060,7 +1092,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op)) } /* calculate the paths for objects that have them (and are tagged to get refreshed) */ - ED_objects_recalculate_paths(C, scene, false); + ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL); /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1515,7 +1547,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op) } int collection_index = RNA_property_int_get(op->ptr, prop); - collection = BKE_collection_from_index(CTX_data_scene(C), collection_index); + collection = BKE_collection_from_index(scene, collection_index); if (collection == NULL) { BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 88d01936882..abcb4afa37d 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -677,7 +677,7 @@ static int modifier_apply_obdata( /* Multires: ensure that recent sculpting is applied */ if (md_eval->type == eModifierType_Multires) { - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); } if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { @@ -2022,7 +2022,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) is_bind = (csmd->bind_coords != NULL); MEM_SAFE_FREE(csmd->bind_coords); - MEM_SAFE_FREE(csmd->delta_cache); + MEM_SAFE_FREE(csmd->delta_cache.deltas); if (is_bind) { /* toggle off */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 0d20a07dcee..c030c551374 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1817,6 +1817,10 @@ static void single_object_users( if (v3d) { ID_NEW_REMAP(v3d->camera); } + /* Camera pointers of markers. */ + for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) { + ID_NEW_REMAP(marker->camera); + } /* Making single user may affect other scenes if they share * with current one some collections in their ViewLayer. */ @@ -2046,6 +2050,13 @@ void ED_object_single_users(Main *bmain, single_obdata_users(bmain, scene, NULL, NULL, 0); single_object_action_users(bmain, scene, NULL, NULL, 0); single_mat_users_expand(bmain); + /* Duplicating obdata and other IDs may require another update of the collections and objects + * pointers, especially regarding drivers and custom props, see T66641. + * Note that this whole scene duplication code and 'make single user' functions have te be + * rewritten at some point to make use of proper modern ID management code, + * but that is no small task. + * For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */ + libblock_relink_collection(scene->master_collection); } /* Relink nodetrees' pointers that have been duplicated. */ diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 815cc618d4b..35762c5861e 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -40,12 +40,17 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_mirror.h" +#include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_shrinkwrap.h" #include "BKE_customdata.h" #include "BKE_mesh_remesh_voxel.h" @@ -73,13 +78,24 @@ static bool object_remesh_poll(bContext *C) { Object *ob = CTX_data_active_object(C); + if (ob == NULL) { + return false; + } + if (BKE_object_is_in_editmode(ob)) { - CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run from edit mode."); + CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode."); return false; } if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) { - CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run with dyntopo activated."); + CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated."); + return false; + } + + if (modifiers_usesMultires(ob)) { + CTX_wm_operator_poll_msg_set( + C, "The remesher cannot run with a Multires modifier in the modifier stack."); + return false; } return ED_operator_object_active_editable_mesh(C); @@ -101,29 +117,35 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) ED_sculpt_undo_geometry_begin(ob); } - new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size); + float isovalue = 0.0f; + if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { + isovalue = mesh->remesh_voxel_size * 0.3f; + } + + new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain( + mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue); if (!new_mesh) { return OPERATOR_CANCELLED; } - Mesh *obj_mesh_copy = NULL; - if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) { - obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0); - CustomData_copy( - &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - for (int i = 0; i < mesh->totvert; i++) { - copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co); - } + if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) { + new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh); + BKE_mesh_calc_normals(new_mesh); } - BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); + if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { + BKE_mesh_runtime_clear_geometry(mesh); + BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob); + } if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) { - BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); - BKE_mesh_free(obj_mesh_copy); + BKE_mesh_runtime_clear_geometry(mesh); + BKE_remesh_reproject_paint_mask(new_mesh, mesh); } + BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); + if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) { BKE_mesh_smooth_flag_set(ob->data, true); } @@ -163,14 +185,26 @@ enum { /****************** quadriflow remesh operator *********************/ +#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f + +typedef enum eSymmetryAxes { + SYMMETRY_AXES_X = (1 << 0), + SYMMETRY_AXES_Y = (1 << 1), + SYMMETRY_AXES_Z = (1 << 2), +} eSymmetryAxes; + typedef struct QuadriFlowJob { /* from wmJob */ struct Object *owner; + struct Main *bmain; short *stop, *do_update; float *progress; int target_faces; int seed; + bool use_paint_symmetry; + eSymmetryAxes symmetry_axes; + bool use_preserve_sharp; bool use_preserve_boundary; bool use_mesh_curvature; @@ -181,6 +215,57 @@ typedef struct QuadriFlowJob { int success; } QuadriFlowJob; +static bool mesh_is_manifold_consistent(Mesh *mesh) +{ + /* In this check we count boundary edges as manifold. Additionally, we also + * check that the direction of the faces are consistent and doesn't suddenly + * flip + */ + + bool is_manifold_consistent = true; + const MLoop *mloop = mesh->mloop; + char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check"); + int *edge_vert = (int *)MEM_malloc_arrayN( + mesh->totedge, sizeof(unsigned int), "remesh_consistent_check"); + + for (unsigned int i = 0; i < mesh->totedge; i++) { + edge_vert[i] = -1; + } + + for (unsigned int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) { + const MLoop *loop = &mloop[loop_idx]; + edge_faces[loop->e] += 1; + if (edge_faces[loop->e] > 2) { + is_manifold_consistent = false; + break; + } + + if (edge_vert[loop->e] == -1) { + edge_vert[loop->e] = loop->v; + } + else if (edge_vert[loop->e] == loop->v) { + /* Mesh has flips in the surface so it is non consistent */ + is_manifold_consistent = false; + break; + } + } + + if (is_manifold_consistent) { + /* check for wire edges */ + for (unsigned int i = 0; i < mesh->totedge; i++) { + if (edge_faces[i] == 0) { + is_manifold_consistent = false; + break; + } + } + } + + MEM_freeN(edge_faces); + MEM_freeN(edge_vert); + + return is_manifold_consistent; +} + static void quadriflow_free_job(void *customdata) { QuadriFlowJob *qj = customdata; @@ -221,6 +306,66 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel) *(qj->progress) = progress; } +static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes) +{ + MirrorModifierData mmd = {0}; + mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE; + + Mesh *mesh_bisect, *mesh_bisect_temp; + mesh_bisect = BKE_mesh_copy(bmain, mesh); + + int axis; + float plane_co[3], plane_no[3]; + zero_v3(plane_co); + + for (char i = 0; i < 3; i++) { + eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i); + if (symmetry_axes & symm_it) { + axis = i; + mmd.flag = 0; + mmd.flag &= MOD_MIR_BISECT_AXIS_X << i; + zero_v3(plane_no); + plane_no[axis] = -1.0f; + mesh_bisect_temp = mesh_bisect; + mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no); + if (mesh_bisect_temp != mesh_bisect) { + BKE_id_free(bmain, mesh_bisect_temp); + } + } + } + + BKE_id_free(bmain, mesh); + + return mesh_bisect; +} + +static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes) +{ + MirrorModifierData mmd = {0}; + mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE; + Mesh *mesh_mirror, *mesh_mirror_temp; + + mesh_mirror = mesh; + + int axis; + + for (char i = 0; i < 3; i++) { + eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i); + if (symmetry_axes & symm_it) { + axis = i; + mmd.flag = 0; + mmd.flag &= MOD_MIR_AXIS_X << i; + mesh_mirror_temp = mesh_mirror; + mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis); + if (mesh_mirror_temp != mesh_mirror) { + BKE_id_free(NULL, mesh_mirror_temp); + } + } + } + + return mesh_mirror; +} + static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress) { QuadriFlowJob *qj = customdata; @@ -235,16 +380,33 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update Object *ob = qj->owner; Mesh *mesh = ob->data; Mesh *new_mesh; + Mesh *bisect_mesh; + + /* Check if the mesh is manifold. Quadriflow requires manifold meshes */ + if (!mesh_is_manifold_consistent(mesh)) { + qj->success = -2; + return; + } + + /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without + * freeing the original ID */ + bisect_mesh = BKE_mesh_copy(qj->bmain, mesh); - new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh, + /* Bisect the input mesh using the paint symmetry settings */ + bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes); + + new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh, qj->target_faces, qj->seed, qj->use_preserve_sharp, - qj->use_preserve_boundary, + qj->use_preserve_boundary || + qj->use_paint_symmetry, qj->use_mesh_curvature, quadriflow_update_job, (void *)qj); + BKE_id_free(qj->bmain, bisect_mesh); + if (!new_mesh) { *do_update = true; *stop = 0; @@ -255,28 +417,26 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update return; } + /* Mirror the Quadriflow result to build the final mesh */ + if (new_mesh) { + new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes); + } + if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_begin(ob); } - Mesh *obj_mesh_copy = NULL; if (qj->preserve_paint_mask) { - obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0); - CustomData_copy( - &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert); - for (int i = 0; i < mesh->totvert; i++) { - copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co); - } + BKE_mesh_runtime_clear_geometry(mesh); + BKE_remesh_reproject_paint_mask(new_mesh, mesh); } BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true); - if (qj->preserve_paint_mask) { - BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy); - BKE_mesh_free(obj_mesh_copy); - } - if (qj->smooth_normals) { + if (qj->use_paint_symmetry) { + BKE_mesh_calc_normals(ob->data); + } BKE_mesh_smooth_flag_set(ob->data, true); } @@ -298,17 +458,22 @@ static void quadriflow_end_job(void *customdata) WM_set_locked_interface(G_MAIN->wm.first, false); - if (qj->success > 0) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!"); - } - else { - if (qj->success == 0) { + switch (qj->success) { + case 1: + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!"); + break; + case 0: WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!"); - } - else { + break; + case -1: WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!"); - } + break; + case -2: + WM_report(RPT_WARNING, + "QuadriFlow: The mesh needs to be manifold and have face normals that point in a " + "consistent direction."); + break; } } @@ -317,10 +482,13 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op) QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob"); job->owner = CTX_data_active_object(C); + job->bmain = CTX_data_main(C); job->target_faces = RNA_int_get(op->ptr, "target_faces"); job->seed = RNA_int_get(op->ptr, "seed"); + job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry"); + job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp"); job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary"); @@ -329,6 +497,22 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op) job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask"); job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals"); + /* Update the target face count if symmetry is enabled */ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + if (sd && job->use_paint_symmetry) { + job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL); + for (char i = 0; i < 3; i++) { + eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i); + if (job->symmetry_axes & symm_it) { + job->target_faces = job->target_faces / 2; + } + } + } + else { + job->use_paint_symmetry = false; + job->symmetry_axes = 0; + } + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C), @@ -453,6 +637,12 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, + "use_paint_symmetry", + true, + "Use Paint Symmetry", + "Generates a symmetrycal mesh using the paint symmetry configuration"); + + RNA_def_boolean(ot->srna, "use_preserve_sharp", false, "Preserve Sharp", @@ -485,7 +675,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) RNA_def_enum(ot->srna, "mode", mode_type_items, - 0, + QUADRIFLOW_REMESH_FACES, "Mode", "How to specify the amount of detail for the new mesh"); @@ -511,7 +701,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "target_faces", - 1, + 4000, 1, INT_MAX, "Number of Faces", diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 28242b986f1..40fa11994f4 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -214,7 +214,7 @@ bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action) static int get_base_select_priority(Base *base) { - if (base->flag & BASE_VISIBLE) { + if (base->flag & BASE_VISIBLE_DEPSGRAPH) { if (base->flag & BASE_SELECTABLE) { return 3; } @@ -288,7 +288,7 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_ if (!(base->flag & BASE_SELECTED)) { ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT); - if (base->flag & BASE_VISIBLE) { + if (BASE_VISIBLE(v3d, base)) { ED_object_base_select(base, BA_SELECT); } diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 1cd16b1b0bf..b534e1b9683 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1715,8 +1715,9 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op) static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); if (vc.obact == NULL || !object_is_target_compat(vc.obact)) { /* Falls back to texture space transform. */ diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 2047ecb9e0a..f16a372cb3c 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -93,6 +93,7 @@ bool PE_poll(bContext *C) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -100,7 +101,7 @@ bool PE_poll(bContext *C) return false; } - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); if (edit == NULL) { return false; } @@ -113,6 +114,7 @@ bool PE_poll(bContext *C) bool PE_hair_poll(bContext *C) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -120,7 +122,7 @@ bool PE_hair_poll(bContext *C) return false; } - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); if (edit == NULL || edit->psys == NULL) { return false; } @@ -149,8 +151,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit) } if (edit->points) { - LOOP_POINTS - { + LOOP_POINTS { if (point->keys) { MEM_freeN(point->keys); } @@ -356,9 +357,9 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o return edit; } -PTCacheEdit *PE_get_current(Scene *scene, Object *ob) +PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob) { - return pe_get_current(NULL, scene, ob, 0); + return pe_get_current(depsgraph, scene, ob, 0); } PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob) @@ -380,10 +381,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra) KEY_K; if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) { - LOOP_POINTS - { - LOOP_KEYS - { + LOOP_POINTS { + LOOP_KEYS { if (fabsf(cfra - *key->time) < pset->fade_frames) { key->flag &= ~PEK_HIDE; } @@ -395,10 +394,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra) } } else { - LOOP_POINTS - { - LOOP_KEYS - { + LOOP_POINTS { + LOOP_KEYS { key->flag &= ~PEK_HIDE; } } @@ -466,14 +463,14 @@ static void PE_set_data(bContext *C, PEData *data) data->view_layer = CTX_data_view_layer(C); data->ob = CTX_data_active_object(C); data->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - data->edit = PE_get_current(data->scene, data->ob); + data->edit = PE_get_current(data->depsgraph, data->scene, data->ob); } static void PE_set_view3d_data(bContext *C, PEData *data) { PE_set_data(C, data); - ED_view3d_viewcontext_init(C, &data->vc); + ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph); if (!XRAY_ENABLED(data->vc.v3d)) { if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) { @@ -633,8 +630,7 @@ static bool point_is_selected(PTCacheEditPoint *point) return 0; } - LOOP_SELECTED_KEYS - { + LOOP_SELECTED_KEYS { return 1; } @@ -684,8 +680,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic nearest_point = -1; nearest_key = -1; - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { if (pset->selectmode == SCE_SELECT_END) { if (point->totkey) { /* only do end keys */ @@ -707,8 +702,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic } else { /* do all keys */ - LOOP_VISIBLE_KEYS - { + LOOP_VISIBLE_KEYS { if (flag & PSEL_NEAREST) { if (key_inside_circle(data, dist, KEY_WCO, &dist)) { nearest_point = p; @@ -745,8 +739,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele selected = 0; } - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { if (pset->selectmode == SCE_SELECT_END) { if (point->totkey) { /* only do end keys */ @@ -762,8 +755,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele } else { /* do all keys */ - LOOP_VISIBLE_KEYS - { + LOOP_VISIBLE_KEYS { if (selected == 0 || key->flag & PEK_SELECT) { float mouse_distance; if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) { @@ -823,8 +815,7 @@ static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v, /* do all keys */ PTCacheEditKey *key; int k; - LOOP_VISIBLE_KEYS - { + LOOP_VISIBLE_KEYS { if (selected == 0 || key->flag & PEK_SELECT) { float mouse_distance; if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) { @@ -866,8 +857,7 @@ static void foreach_selected_point(PEData *data, ForPointFunc func) PTCacheEdit *edit = data->edit; POINT_P; - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { func(data, p); } } @@ -878,10 +868,8 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func) POINT_P; KEY_K; - LOOP_VISIBLE_POINTS - { - LOOP_SELECTED_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { func(data, p, k, true); } } @@ -892,8 +880,7 @@ static void foreach_point(PEData *data, ForPointFunc func) PTCacheEdit *edit = data->edit; POINT_P; - LOOP_POINTS - { + LOOP_POINTS { func(data, p); } } @@ -905,11 +892,9 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit) KEY_K; int sel = 0; - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { if (pset->selectmode == SCE_SELECT_POINT) { - LOOP_SELECTED_KEYS - { + LOOP_SELECTED_KEYS { sel++; } } @@ -1117,8 +1102,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) /* we delay settings the PARS_EDIT_RECALC for mirrored particles * to avoid doing mirror twice */ - LOOP_POINTS - { + LOOP_POINTS { if (point->flag & PEP_EDIT_RECALC) { PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL); @@ -1128,8 +1112,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) } } - LOOP_POINTS - { + LOOP_POINTS { if (point->flag & PEP_EDIT_RECALC) { if (edit->mirror_cache[p] != -1) { edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC; @@ -1173,13 +1156,11 @@ static void deflect_emitter_iter(void *__restrict iter_data_v, psys_mat_hair_to_object( object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat); - LOOP_KEYS - { + LOOP_KEYS { mul_m4_v3(hairmat, key->co); } - LOOP_KEYS - { + LOOP_KEYS { if (k == 0) { dist_1st = len_v3v3((key + 1)->co, key->co); dist_1st *= dist * emitterdist; @@ -1215,8 +1196,7 @@ static void deflect_emitter_iter(void *__restrict iter_data_v, invert_m4_m4(hairimat, hairmat); - LOOP_KEYS - { + LOOP_KEYS { mul_m4_v3(hairimat, key->co); } } @@ -1268,8 +1248,7 @@ static void apply_lengths_iter(void *__restrict iter_data_v, } PTCacheEditKey *key; int k; - LOOP_KEYS - { + LOOP_KEYS { if (k) { float dv1[3]; sub_v3_v3v3(dv1, key->co, (key - 1)->co); @@ -1387,8 +1366,7 @@ void recalc_lengths(PTCacheEdit *edit) return; } - LOOP_EDITED_POINTS - { + LOOP_EDITED_POINTS { key = point->keys; for (k = 0; k < point->totkey - 1; k++, key++) { key->length = len_v3v3(key->co, (key + 1)->co); @@ -1461,15 +1439,14 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag) { - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); HairKey *hkey; POINT_P; KEY_K; /* flag all particles to be updated if not using flag */ if (!useflag) { - LOOP_POINTS - { + LOOP_POINTS { point->flag |= PEP_EDIT_RECALC; } } @@ -1477,11 +1454,9 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, /* flush edit key flag to hair key flag to preserve selection * on save */ if (edit->psys) { - LOOP_POINTS - { + LOOP_POINTS { hkey = edit->psys->particles[p].hair; - LOOP_KEYS - { + LOOP_KEYS { hkey->editflag = key->flag; hkey++; } @@ -1491,8 +1466,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ - LOOP_POINTS - { + LOOP_POINTS { point->flag &= ~PEP_EDIT_RECALC; } @@ -1511,15 +1485,13 @@ void update_world_cos(Object *ob, PTCacheEdit *edit) return; } - LOOP_POINTS - { + LOOP_POINTS { if (!(psys->flag & PSYS_GLOBAL_HAIR)) { psys_mat_hair_to_global( ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat); } - LOOP_KEYS - { + LOOP_KEYS { copy_v3_v3(key->world_co, key->co); if (!(psys->flag & PSYS_GLOBAL_HAIR)) { mul_m4_v3(hairmat, key->world_co); @@ -1541,10 +1513,8 @@ static void update_velocities(PTCacheEdit *edit) frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f; - LOOP_EDITED_POINTS - { - LOOP_KEYS - { + LOOP_EDITED_POINTS { + LOOP_KEYS { if (k == 0) { dfra = *(key + 1)->time - *key->time; @@ -1596,7 +1566,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla /* use this to do partial particle updates, not usable when adding or * removing, then a full redo is necessary and calling this may crash */ ParticleEditSettings *pset = PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); POINT_P; if (!edit) { @@ -1605,8 +1575,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla /* flag all particles to be updated if not using flag */ if (!useflag) { - LOOP_POINTS - { + LOOP_POINTS { point->flag |= PEP_EDIT_RECALC; } } @@ -1624,14 +1593,19 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla if (pset->flag & PE_AUTO_VELOCITY) { update_velocities(edit); } - PE_hide_keys_time(scene, edit, CFRA); + + /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet + * and flagging with PEK_HIDE will prevent selection. This might get restored once this is + * supported in drawing (but doesn't make much sense for hair anyways). */ + if (edit->psys->part->type == PART_EMITTER) { + PE_hide_keys_time(scene, edit, CFRA); + } /* regenerate path caches */ psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ - LOOP_POINTS - { + LOOP_POINTS { point->flag &= ~PEP_EDIT_RECALC; } @@ -1686,8 +1660,7 @@ static void select_keys(PEData *data, PTCacheEditPoint *point = edit->points + point_index; KEY_K; - LOOP_KEYS - { + LOOP_KEYS { if (data->select) { key->flag |= PEK_SELECT; } @@ -1780,17 +1753,15 @@ static int pe_select_all_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); POINT_P; KEY_K; int action = RNA_enum_get(op->ptr, "action"); if (action == SEL_TOGGLE) { action = SEL_SELECT; - LOOP_VISIBLE_POINTS - { - LOOP_SELECTED_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { action = SEL_DESELECT; break; } @@ -1802,10 +1773,8 @@ static int pe_select_all_exec(bContext *C, wmOperator *op) } bool changed = false; - LOOP_VISIBLE_POINTS - { - LOOP_VISIBLE_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_VISIBLE_KEYS { changed |= select_action_apply(point, key, action); } } @@ -1841,26 +1810,26 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele PEData data; Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); POINT_P; KEY_K; + PE_set_view3d_data(C, &data); + + PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob); + if (!PE_start_edit(edit)) { return false; } if (!extend && !deselect && !toggle) { - LOOP_VISIBLE_POINTS - { - LOOP_SELECTED_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { key->flag &= ~PEK_SELECT; point->flag |= PEP_EDIT_RECALC; } } } - PE_set_view3d_data(C, &data); data.mval = mval; data.rad = ED_view3d_select_dist_px(); @@ -2048,26 +2017,22 @@ static int select_random_exec(bContext *C, wmOperator *op) PE_set_data(C, &data); data.select_action = SEL_SELECT; - edit = PE_get_current(data.scene, data.ob); + edit = PE_get_current(data.depsgraph, data.scene, data.ob); rng = BLI_rng_new_srandom(seed); switch (type) { case RAN_HAIR: - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT; - LOOP_KEYS - { + LOOP_KEYS { data.is_changed |= select_action_apply(point, key, flag); } } break; case RAN_POINTS: - LOOP_VISIBLE_POINTS - { - LOOP_VISIBLE_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_VISIBLE_KEYS { int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT; data.is_changed |= select_action_apply(point, key, flag); } @@ -2166,10 +2131,8 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit) POINT_P; KEY_K; - LOOP_VISIBLE_POINTS - { - LOOP_SELECTED_KEYS - { + LOOP_VISIBLE_POINTS { + LOOP_SELECTED_KEYS { if ((key->flag & PEK_SELECT) != 0) { key->flag &= ~PEK_SELECT; point->flag |= PEP_EDIT_RECALC; @@ -2182,9 +2145,10 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit) bool PE_deselect_all_visible(bContext *C) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); if (!PE_start_edit(edit)) { return false; } @@ -2193,9 +2157,10 @@ bool PE_deselect_all_visible(bContext *C) bool PE_box_select(bContext *C, const rcti *rect, const int sel_op) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); PEData data; if (!PE_start_edit(edit)) { @@ -2229,9 +2194,10 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op) bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad) { BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); PEData data; if (!PE_start_edit(edit)) { @@ -2260,11 +2226,12 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); ARegion *ar = CTX_wm_region(C); ParticleEditSettings *pset = PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd_eval = edit->psmd_eval; POINT_P; @@ -2287,16 +2254,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const data.is_changed |= PE_deselect_all_visible_ex(edit); } - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { psys_mat_hair_to_global( ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); } if (pset->selectmode == SCE_SELECT_POINT) { - LOOP_KEYS - { + LOOP_VISIBLE_KEYS { copy_v3_v3(co, key->co); mul_m4_v3(mat, co); const bool is_select = key->flag & PEK_SELECT; @@ -2350,30 +2315,26 @@ static int hide_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); POINT_P; KEY_K; if (RNA_boolean_get(op->ptr, "unselected")) { - LOOP_UNSELECTED_POINTS - { + LOOP_UNSELECTED_POINTS { point->flag |= PEP_HIDE; point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS - { + LOOP_KEYS { key->flag &= ~PEK_SELECT; } } } else { - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { point->flag |= PEP_HIDE; point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS - { + LOOP_KEYS { key->flag &= ~PEK_SELECT; } } @@ -2410,19 +2371,17 @@ static int reveal_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); const bool select = RNA_boolean_get(op->ptr, "select"); POINT_P; KEY_K; - LOOP_POINTS - { + LOOP_POINTS { if (point->flag & PEP_HIDE) { point->flag &= ~PEP_HIDE; point->flag |= PEP_EDIT_RECALC; - LOOP_KEYS - { + LOOP_KEYS { SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT); } } @@ -2460,8 +2419,7 @@ static void select_less_keys(PEData *data, int point_index) PTCacheEditPoint *point = edit->points + point_index; KEY_K; - LOOP_SELECTED_KEYS - { + LOOP_SELECTED_KEYS { if (k == 0) { if (((key + 1)->flag & PEK_SELECT) == 0) { key->flag |= PEK_TAG; @@ -2479,8 +2437,7 @@ static void select_less_keys(PEData *data, int point_index) } } - LOOP_KEYS - { + LOOP_KEYS { if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) { key->flag &= ~(PEK_TAG | PEK_SELECT); point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ @@ -2525,8 +2482,7 @@ static void select_more_keys(PEData *data, int point_index) PTCacheEditPoint *point = edit->points + point_index; KEY_K; - LOOP_KEYS - { + LOOP_KEYS { if (key->flag & PEK_SELECT) { continue; } @@ -2548,8 +2504,7 @@ static void select_more_keys(PEData *data, int point_index) } } - LOOP_KEYS - { + LOOP_KEYS { if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) { key->flag &= ~PEK_TAG; key->flag |= PEK_SELECT; @@ -2694,7 +2649,8 @@ void PARTICLE_OT_rekey(wmOperatorType *ot) static void rekey_particle_to_time( const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time) { - PTCacheEdit *edit = PE_get_current(scene, ob); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys; ParticleSimulationData sim = {0}; ParticleData *pa; @@ -2709,7 +2665,7 @@ static void rekey_particle_to_time( psys = edit->psys; - sim.depsgraph = CTX_data_depsgraph_pointer(C); + sim.depsgraph = depsgraph; sim.scene = scene; sim.ob = ob; sim.psys = psys; @@ -2758,14 +2714,12 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) /* mirror tags */ psmd_eval = edit->psmd_eval; - LOOP_TAGGED_POINTS - { + LOOP_TAGGED_POINTS { PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL); } } - LOOP_TAGGED_POINTS - { + LOOP_TAGGED_POINTS { new_totpart--; removed++; } @@ -2850,21 +2804,17 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated( depsgraph, ob, &psmd->modifier); - LOOP_POINTS - { - LOOP_TAGGED_KEYS - { + LOOP_POINTS { + LOOP_TAGGED_KEYS { PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL); break; } } } - LOOP_POINTS - { + LOOP_POINTS { new_totkey = point->totkey; - LOOP_TAGGED_KEYS - { + LOOP_TAGGED_KEYS { new_totkey--; } /* we can't have elements with less than two keys*/ @@ -2874,13 +2824,11 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem } remove_tagged_particles(ob, psys, pe_x_mirror(ob)); - LOOP_POINTS - { + LOOP_POINTS { pa = psys->particles + p; new_totkey = pa->totkey; - LOOP_TAGGED_KEYS - { + LOOP_TAGGED_KEYS { new_totkey--; } @@ -2889,8 +2837,7 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys"); hkey = pa->hair; - LOOP_KEYS - { + LOOP_KEYS { while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) { key++; hkey++; @@ -3062,9 +3009,10 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot) static int remove_doubles_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd_eval; KDTree_3d *tree; @@ -3087,8 +3035,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) tree = BLI_kdtree_3d_new(psys->totpart); /* insert particles into kd tree */ - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { psys_mat_hair_to_object( ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); copy_v3_v3(co, point->keys->co); @@ -3099,8 +3046,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) BLI_kdtree_3d_balance(tree); /* tag particles to be removed */ - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { psys_mat_hair_to_object( ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); copy_v3_v3(co, point->keys->co); @@ -3130,7 +3076,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved); + BKE_reportf(op->reports, RPT_INFO, "Removed %d double particle(s)", totremoved); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob); @@ -3166,10 +3112,11 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot) static int weight_set_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ParticleEditSettings *pset = PE_settings(scene); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys = edit->psys; POINT_P; KEY_K; @@ -3181,12 +3128,10 @@ static int weight_set_exec(bContext *C, wmOperator *op) weight = brush->strength; edit = psys->edit; - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { ParticleData *pa = psys->particles + p; - LOOP_SELECTED_KEYS - { + LOOP_SELECTED_KEYS { hkey = pa->hair + k; hkey->weight = interpf(weight, hkey->weight, factor); } @@ -3315,6 +3260,7 @@ static int delete_exec(bContext *C, wmOperator *op) } DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY); + BKE_particle_batch_cache_dirty_tag(data.edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob); return OPERATOR_FINISHED; @@ -3346,11 +3292,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot) /*************************** mirror operator **************************/ -static void PE_mirror_x(Scene *scene, Object *ob, int tagged) +static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged) { Mesh *me = (Mesh *)(ob->data); ParticleSystemModifierData *psmd_eval; - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys = edit->psys; ParticleData *pa, *newpa, *new_pars; PTCacheEditPoint *newpoint, *new_points; @@ -3386,8 +3332,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) totpart = psys->totpart; newtotpart = psys->totpart; - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { pa = psys->particles + p; if (!tagged) { @@ -3503,8 +3448,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) } } - LOOP_POINTS - { + LOOP_POINTS { point->flag &= ~PEP_TAG; } @@ -3513,14 +3457,18 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) static int mirror_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); - PE_mirror_x(scene, ob, 0); + PE_mirror_x(depsgraph, scene, ob, 0); update_world_cos(ob, edit); + psys_free_path_cache(NULL, edit); + WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob); + BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); return OPERATOR_FINISHED; @@ -3681,8 +3629,7 @@ static void brush_length(PEData *data, int point_index, float UNUSED(mouse_dista KEY_K; float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f}; - LOOP_KEYS - { + LOOP_KEYS { if (k == 0) { copy_v3_v3(pvec, key->co); } @@ -3731,8 +3678,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) unit_m4(imat); } - LOOP_KEYS - { + LOOP_KEYS { float kco[3]; if (k == 0) { @@ -4504,10 +4450,11 @@ typedef struct BrushEdit { static int brush_edit_init(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ARegion *ar = CTX_wm_region(C); BrushEdit *bedit; float min[3], max[3]; @@ -4518,7 +4465,7 @@ static int brush_edit_init(bContext *C, wmOperator *op) /* set the 'distance factor' for grabbing (used in comb etc) */ INIT_MINMAX(min, max); - PE_minmax(scene, view_layer, min, max); + PE_minmax(depsgraph, scene, view_layer, min, max); mid_v3_v3v3(min, min, max); bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit"); @@ -4744,7 +4691,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) { if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) { - PE_mirror_x(scene, ob, 1); + PE_mirror_x(depsgraph, scene, ob, 1); } update_world_cos(ob, edit); @@ -4993,10 +4940,11 @@ static void shape_cut(PEData *data, int pa_index) static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(scene); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); Object *shapeob = pset->shape_object; int selected = count_selected_keys(scene, edit); int lock_root = pset->flag & PE_LOCK_FIRST; @@ -5074,10 +5022,11 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot) /************************ utilities ******************************/ -int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) +int PE_minmax( + Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) { Object *ob = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys; ParticleSystemModifierData *psmd_eval = NULL; POINT_P; @@ -5096,15 +5045,13 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) unit_m4(mat); } - LOOP_VISIBLE_POINTS - { + LOOP_VISIBLE_POINTS { if (psys) { psys_mat_hair_to_global( ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat); } - LOOP_SELECTED_KEYS - { + LOOP_SELECTED_KEYS { copy_v3_v3(co, key->co); mul_m4_v3(mat, co); DO_MINMAX(co, min, max); @@ -5181,15 +5128,13 @@ void PE_create_particle_edit( BLI_listbase_clear(&edit->pathcachebufs); pa = psys->particles; - LOOP_POINTS - { + LOOP_POINTS { point->totkey = pa->totkey; point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys"); point->flag |= PEP_EDIT_RECALC; hkey = pa->hair; - LOOP_KEYS - { + LOOP_KEYS { key->co = hkey->co; key->time = &hkey->time; key->flag = hkey->editflag; @@ -5217,8 +5162,7 @@ void PE_create_particle_edit( } for (pm = cache->mem_cache.first; pm; pm = pm->next) { - LOOP_POINTS - { + LOOP_POINTS { if (BKE_ptcache_mem_pointers_seek(p, pm) == 0) { continue; } @@ -5421,8 +5365,7 @@ static float calculate_point_length(PTCacheEditPoint *point) { float length = 0.0f; KEY_K; - LOOP_KEYS - { + LOOP_KEYS { if (k > 0) { length += len_v3v3((key - 1)->co, key->co); } @@ -5435,8 +5378,7 @@ static float calculate_average_length(PTCacheEdit *edit) int num_selected = 0; float total_length = 0; POINT_P; - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { total_length += calculate_point_length(point); num_selected++; } @@ -5450,8 +5392,7 @@ static void scale_point_factor(PTCacheEditPoint *point, float factor) { float orig_prev_co[3], prev_co[3]; KEY_K; - LOOP_KEYS - { + LOOP_KEYS { if (k == 0) { copy_v3_v3(orig_prev_co, key->co); copy_v3_v3(prev_co, key->co); @@ -5484,8 +5425,7 @@ static void scale_point_to_length(PTCacheEditPoint *point, float length) static void scale_points_to_length(PTCacheEdit *edit, float length) { POINT_P; - LOOP_SELECTED_POINTS - { + LOOP_SELECTED_POINTS { scale_point_to_length(point, length); } recalc_lengths(edit); @@ -5497,7 +5437,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); float average_length = calculate_average_length(edit); if (average_length == 0.0f) { diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index 40d90676487..aee79523c87 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -109,8 +109,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) POINT_P; KEY_K; - LOOP_POINTS - { + LOOP_POINTS { if (psys && psys->particles[p].hair) { MEM_freeN(psys->particles[p].hair); } @@ -133,8 +132,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) edit->points = MEM_dupallocN(undo->points); edit->totpoint = undo->totpoint; - LOOP_POINTS - { + LOOP_POINTS { point->keys = MEM_dupallocN(point->keys); } @@ -143,13 +141,11 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) psys->totpart = undo->totpoint; - LOOP_POINTS - { + LOOP_POINTS { pa = psys->particles + p; hkey = pa->hair = MEM_dupallocN(pa->hair); - LOOP_KEYS - { + LOOP_KEYS { key->co = hkey->co; key->time = &hkey->time; hkey++; @@ -174,10 +170,8 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit) } BKE_ptcache_mem_pointers_init(pm); - LOOP_POINTS - { - LOOP_KEYS - { + LOOP_POINTS { + LOOP_KEYS { if ((int)key->ftime == (int)pm->frame) { key->co = pm->cur[BPHYS_DATA_LOCATION]; key->vel = pm->cur[BPHYS_DATA_VELOCITY]; @@ -228,10 +222,11 @@ typedef struct ParticleUndoStep { static bool particle_undosys_poll(struct bContext *C) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); return (edit != NULL); } @@ -240,11 +235,12 @@ static bool particle_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); ParticleUndoStep *us = (ParticleUndoStep *)us_p; ViewLayer *view_layer = CTX_data_view_layer(C); us->scene_ref.ptr = CTX_data_scene(C); us->object_ref.ptr = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr); + PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr); undoptcache_from_editcache(&us->data, edit); return true; } @@ -255,6 +251,7 @@ static void particle_undosys_step_decode(struct bContext *C, int UNUSED(dir), bool UNUSED(is_final)) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); BLI_assert(particle_undosys_poll(C)); @@ -262,7 +259,7 @@ static void particle_undosys_step_decode(struct bContext *C, ParticleUndoStep *us = (ParticleUndoStep *)us_p; Scene *scene = us->scene_ref.ptr; Object *ob = us->object_ref.ptr; - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); if (edit) { undoptcache_to_editcache(&us->data, edit); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 5a2009845f8..cfb3a400f47 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1017,13 +1017,11 @@ static void copy_particle_edit(Depsgraph *depsgraph, edit->points = MEM_dupallocN(edit_from->points); pa = psys->particles; - LOOP_POINTS - { + LOOP_POINTS { HairKey *hkey = pa->hair; point->keys = MEM_dupallocN(point->keys); - LOOP_KEYS - { + LOOP_KEYS { key->co = hkey->co; key->time = &hkey->time; key->flag = hkey->editflag; diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 4b1d51ee6c2..303a0714388 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -115,13 +115,7 @@ bool ED_rigidbody_constraint_add( void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob) { - RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene); - - BKE_rigidbody_remove_constraint(scene, ob); - if (rbw) { - BKE_collection_object_remove(bmain, rbw->constraints, ob, false); - DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE); - } + BKE_rigidbody_remove_constraint(bmain, scene, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index bc8a1799fa0..43ca421b9d0 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -105,7 +105,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob) { - BKE_rigidbody_remove_object(bmain, scene, ob); + BKE_rigidbody_remove_object(bmain, scene, ob, false); DEG_relations_tag_update(bmain); DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 053ca3d8f9f..7106af25a82 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -859,7 +859,7 @@ static void screen_render_cancel(bContext *C, wmOperator *op) static void clean_viewport_memory_base(Base *base) { - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return; } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 3e001ef25b5..6dc3a1ec1ac 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -115,7 +115,7 @@ ImBuf *get_brush_icon(Brush *brush) // first use the path directly to try and load the file BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath)); - BLI_path_abs(path, BKE_main_blendfile_path_from_global()); + BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id)); /* use default colorspaces for brushes */ brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); @@ -474,7 +474,7 @@ static Scene *preview_prepare_scene( } } else if (base->object->type == OB_LAMP) { - base->flag |= BASE_VISIBLE; + base->flag |= BASE_VISIBLE_DEPSGRAPH; } } } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 9f13431f25a..7970d491877 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -103,15 +103,17 @@ static Object **object_array_for_shading(bContext *C, uint *r_objects_len) ScrArea *sa = CTX_wm_area(C); SpaceProperties *sbuts = NULL; View3D *v3d = NULL; - if (sa->spacetype == SPACE_PROPERTIES) { - sbuts = sa->spacedata.first; - } - else if (sa->spacetype == SPACE_VIEW3D) { - v3d = sa->spacedata.first; + if (sa != NULL) { + if (sa->spacetype == SPACE_PROPERTIES) { + sbuts = sa->spacedata.first; + } + else if (sa->spacetype == SPACE_VIEW3D) { + v3d = sa->spacedata.first; + } } Object **objects; - if (sbuts && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) { + if (sbuts != NULL && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) { objects = MEM_mallocN(sizeof(*objects), __func__); objects[0] = (Object *)sbuts->pinid; *r_objects_len = 1; diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index 3154d5d0985..a54701f8725 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -36,6 +36,8 @@ #include "BKE_screen.h" #include "BKE_report.h" +#include "BLT_translation.h" + #include "WM_api.h" #include "WM_types.h" @@ -137,11 +139,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) SpaceImage *sima; bool area_was_image = false; - if (scene->r.displaymode == R_OUTPUT_NONE) { + if (U.render_display_type == USER_RENDER_DISPLAY_NONE) { return NULL; } - if (scene->r.displaymode == R_OUTPUT_WINDOW) { + if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) { int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100; int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100; @@ -154,14 +156,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } /* changes context! */ - if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) { + if (WM_window_open_temp( + C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE, false) == NULL) { BKE_report(reports, RPT_ERROR, "Failed to open window!"); return NULL; } sa = CTX_wm_area(C); } - else if (scene->r.displaymode == R_OUTPUT_SCREEN) { + else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) { sa = CTX_wm_area(C); /* if the active screen is already in fullscreen mode, skip this and diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index 84d6610242a..7705278443f 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -29,21 +29,16 @@ #include "BKE_global.h" #include "BKE_layer.h" #include "BKE_library.h" -#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "BLT_translation.h" -#include "DNA_object_types.h" -#include "DNA_workspace_types.h" - #include "ED_object.h" #include "ED_render.h" #include "ED_scene.h" diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index cb87b076d79..9957fe0515c 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -30,6 +30,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_rand.h" #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" @@ -60,7 +61,6 @@ #include "BLF_api.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_metadata.h" @@ -543,20 +543,20 @@ void ED_region_do_draw(bContext *C, ARegion *ar) region_draw_azones(sa, ar); /* for debugging unneeded area redraws and partial redraw */ -#if 0 - GPU_blend(true); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4f(drand48(), drand48(), drand48(), 0.1f); - immRectf(pos, - ar->drawrct.xmin - ar->winrct.xmin, - ar->drawrct.ymin - ar->winrct.ymin, - ar->drawrct.xmax - ar->winrct.xmin, - ar->drawrct.ymax - ar->winrct.ymin); - immUnbindProgram(); - GPU_blend(false); -#endif + if (G.debug_value == 888) { + GPU_blend(true); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f); + immRectf(pos, + ar->drawrct.xmin - ar->winrct.xmin, + ar->drawrct.ymin - ar->winrct.ymin, + ar->drawrct.xmax - ar->winrct.xmin, + ar->drawrct.ymax - ar->winrct.ymin); + immUnbindProgram(); + GPU_blend(false); + } memset(&ar->drawrct, 0, sizeof(ar->drawrct)); @@ -1827,7 +1827,7 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar) if (WM_cursor_set_from_tool(win, sa, ar)) { return; } - WM_cursor_set(win, CURSOR_STD); + WM_cursor_set(win, WM_CURSOR_DEFAULT); } } @@ -2869,7 +2869,7 @@ void ED_region_info_draw(ARegion *ar, float fill_color[4], const bool full_redraw) { - ED_region_info_draw_multiline(ar, (const char * [2]){text, NULL}, fill_color, full_redraw); + ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw); } #define MAX_METADATA_STR 1024 diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c index 420d70e63fb..46559efc614 100644 --- a/source/blender/editors/screen/area_query.c +++ b/source/blender/editors/screen/area_query.c @@ -28,8 +28,6 @@ #include "RNA_types.h" -#include "WM_api.h" - #include "ED_screen.h" #include "UI_interface.h" diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c index 1a99210b73d..61fb9d5a3a8 100644 --- a/source/blender/editors/screen/area_utils.c +++ b/source/blender/editors/screen/area_utils.c @@ -28,7 +28,6 @@ #include "RNA_access.h" #include "RNA_types.h" -#include "WM_api.h" #include "WM_message.h" #include "ED_screen.h" diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index d8926bfc460..dc435efd86b 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -24,8 +24,6 @@ #include <stdio.h> #include <string.h> -#include "MEM_guardedalloc.h" - #include "DNA_userdef_types.h" #include "DNA_vec_types.h" diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 6f8b25f782b..f7742c5e50a 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -29,36 +29,28 @@ #include "DNA_object_types.h" #include "DNA_armature_types.h" -#include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_sequence_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" -#include "DNA_workspace_types.h" #include "BLI_utildefines.h" -#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_object.h" #include "BKE_action.h" #include "BKE_armature.h" -#include "BKE_paint.h" #include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_sequencer.h" -#include "BKE_workspace.h" - -#include "DEG_depsgraph.h" #include "RNA_access.h" #include "ED_armature.h" #include "ED_gpencil.h" #include "ED_anim_api.h" -#include "ED_uvedit.h" #include "WM_api.h" #include "UI_interface.h" diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index db744df02e7..a6b8bba73e3 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -21,7 +21,7 @@ #include "ED_screen.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_matrix.h" @@ -32,9 +32,7 @@ #include "BLI_rect.h" #include "WM_api.h" -#include "WM_types.h" -#include "UI_interface.h" #include "UI_resources.h" #include "screen_intern.h" diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index b37aa47aba6..bbdddfadc30 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -41,20 +41,18 @@ #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" -#include "BKE_node.h" #include "BKE_screen.h" #include "BKE_scene.h" +#include "BKE_sound.h" #include "BKE_workspace.h" #include "WM_api.h" #include "WM_types.h" -#include "ED_object.h" #include "ED_screen.h" #include "ED_screen_types.h" #include "ED_clip.h" #include "ED_node.h" -#include "ED_render.h" #include "UI_interface.h" @@ -518,6 +516,17 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree } } +/** + * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated + * slightly differently, see #ui_region_temp_remove(). + */ +void ED_region_remove(bContext *C, ScrArea *sa, ARegion *ar) +{ + ED_region_exit(C, ar); + BKE_area_region_free(sa->type, ar); + BLI_freelinkN(&sa->regionbase, ar); +} + /* *********** exit calls are for closing running stuff ******** */ void ED_region_exit(bContext *C, ARegion *ar) @@ -583,6 +592,11 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) if (screen->animtimer) { WM_event_remove_timer(wm, window, screen->animtimer); + + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Scene *scene = WM_window_get_active_scene(prevwin); + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); + BKE_sound_stop_scene(scene_eval); } screen->animtimer = NULL; screen->scrubbing = false; @@ -630,14 +644,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2]) if (sa) { if (az->type == AZONE_AREA) { - WM_cursor_set(win, CURSOR_EDIT); + WM_cursor_set(win, WM_CURSOR_EDIT); } else if (az->type == AZONE_REGION) { if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) { - WM_cursor_set(win, CURSOR_X_MOVE); + WM_cursor_set(win, WM_CURSOR_X_MOVE); } else { - WM_cursor_set(win, CURSOR_Y_MOVE); + WM_cursor_set(win, WM_CURSOR_Y_MOVE); } } } @@ -646,14 +660,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2]) if (actedge) { if (screen_geom_edge_is_horizontal(actedge)) { - WM_cursor_set(win, CURSOR_Y_MOVE); + WM_cursor_set(win, WM_CURSOR_Y_MOVE); } else { - WM_cursor_set(win, CURSOR_X_MOVE); + WM_cursor_set(win, WM_CURSOR_X_MOVE); } } else { - WM_cursor_set(win, CURSOR_STD); + WM_cursor_set(win, WM_CURSOR_DEFAULT); } } } @@ -1346,6 +1360,54 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s return sc->areabase.first; } +/** + * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined + * by \a display_type. + * + * \param title: Title to set for the window, if a window is spawned. + * \param x, y: Position of the window, if a window is spawned. + * \param sizex, sizey: Dimensions of the window, if a window is spawned. + */ +ScrArea *ED_screen_temp_space_open(bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + eSpace_Type space_type, + int display_type, + bool dialog) +{ + ScrArea *sa = NULL; + + switch (display_type) { + case USER_TEMP_SPACE_DISPLAY_WINDOW: + if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) { + sa = CTX_wm_area(C); + } + break; + case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: { + ScrArea *ctx_sa = CTX_wm_area(C); + + if (ctx_sa->full) { + sa = ctx_sa; + ED_area_newspace(C, ctx_sa, space_type, true); + /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ + sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); + } + else if (ctx_sa->spacetype == space_type) { + sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED); + } + else { + sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type); + } + break; + } + } + + return sa; +} + /* update frame rate info for viewport drawing */ void ED_refresh_viewport_fps(bContext *C) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f29535a7f0b..cc1f53eabde 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -38,7 +38,6 @@ #include "DNA_lattice_types.h" #include "DNA_object_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" @@ -48,7 +47,6 @@ #include "DNA_userdef_types.h" #include "BKE_context.h" -#include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_global.h" @@ -1043,28 +1041,28 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) { /* Same area, so possible split. */ WM_cursor_set( - win, (ELEM(sad->gesture_dir, 'n', 's')) ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR); + win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); is_gesture = (delta_max > split_threshold); } else { /* Different area, so possible join. */ if (sad->gesture_dir == 'n') { - WM_cursor_set(win, BC_N_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_N_ARROW); } else if (sad->gesture_dir == 's') { - WM_cursor_set(win, BC_S_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_S_ARROW); } else if (sad->gesture_dir == 'e') { - WM_cursor_set(win, BC_E_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_E_ARROW); } else { - WM_cursor_set(win, BC_W_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_W_ARROW); } is_gesture = (delta_max > join_threshold); } } else { - WM_cursor_set(CTX_wm_window(C), BC_CROSSCURSOR); + WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS); is_gesture = false; } } @@ -1229,7 +1227,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event) } /* add modal handler */ - WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_SWAP_AREA); WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -2121,7 +2119,7 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op) { wmWindow *win = CTX_wm_window(C); int dir = RNA_enum_get(op->ptr, "direction"); - WM_cursor_set(win, (dir == 'n' || dir == 's') ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR); + WM_cursor_set(win, (dir == 'n' || dir == 's') ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); } /* UI callback, adds new handler */ @@ -3420,19 +3418,19 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (dir == 1) { - WM_cursor_set(win, BC_N_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_N_ARROW); } else if (dir == 3) { - WM_cursor_set(win, BC_S_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_S_ARROW); } else if (dir == 2) { - WM_cursor_set(win, BC_E_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_E_ARROW); } else if (dir == 0) { - WM_cursor_set(win, BC_W_ARROWCURSOR); + WM_cursor_set(win, WM_CURSOR_W_ARROW); } else { - WM_cursor_set(win, BC_STOPCURSOR); + WM_cursor_set(win, WM_CURSOR_STOP); } break; @@ -3848,10 +3846,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op) for (ar = sa->regionbase.first; ar; ar = arn) { arn = ar->next; if (ar->alignment == RGN_ALIGN_QSPLIT) { - ED_region_exit(C, ar); - BKE_area_region_free(sa->type, ar); - BLI_remlink(&sa->regionbase, ar); - MEM_freeN(ar); + ED_region_remove(C, sa, ar); } } ED_area_tag_redraw(sa); @@ -3951,7 +3946,7 @@ static int region_toggle_exec(bContext *C, wmOperator *op) region = CTX_wm_region(C); } - if (region) { + if (region && (region->alignment != RGN_ALIGN_NONE)) { ED_region_toggle_hidden(C, region); } ED_region_tag_redraw(region); @@ -4833,7 +4828,14 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even int sizey = 520 * UI_DPI_FAC; /* changes context! */ - if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Preferences"), + event->x, + event->y, + sizex, + sizey, + SPACE_USERPREF, + false) != NULL) { /* The header only contains the editor switcher and looks empty. * So hiding in the temp window makes sense. */ ScrArea *area = CTX_wm_area(C); @@ -4882,7 +4884,16 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent but = UI_context_active_but_prop_get(C, &ptr, &prop, &index); /* changes context! */ - if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Drivers Editor"), + event->x, + event->y, + sizex, + sizey, + SPACE_GRAPH, + false) != NULL) { + ED_drivers_editor_init(C, CTX_wm_area(C)); + /* activate driver F-Curve for the property under the cursor */ if (but) { FCurve *fcu; @@ -4938,7 +4949,14 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even int shift_y = 480; /* changes context! */ - if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) { + if (WM_window_open_temp(C, + IFACE_("Blender Info Log"), + event->x, + event->y + shift_y, + sizex, + sizey, + SPACE_INFO, + false) != NULL) { return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index 26849edeb44..661c17f55d2 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -52,27 +52,43 @@ #include "RNA_access.h" /* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + +static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl) +{ + if (sl->spacetype == SPACE_NODE) { + const SpaceNode *snode = (const SpaceNode *)sl; + return snode->tree_idname; + } + return CTX_data_mode_string(C); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Menu Type * \{ */ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len) { SpaceLink *sl = CTX_wm_space_data(C); - const char *context = CTX_data_mode_string(C); if (sl == NULL) { *r_len = 0; return NULL; } + const char *context_mode = CTX_data_mode_string(C); + const char *context = screen_menu_context_string(C, sl); uint array_len = 3; bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__); um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context); um_array[1] = (sl->spacetype != SPACE_TOPBAR) ? - BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) : + BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) : NULL; um_array[2] = (sl->spacetype == SPACE_VIEW3D) ? - BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context) : + BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) : NULL; *r_len = array_len; @@ -82,7 +98,7 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len) bUserMenu *ED_screen_user_menu_ensure(bContext *C) { SpaceLink *sl = CTX_wm_space_data(C); - const char *context = CTX_data_mode_string(C); + const char *context = screen_menu_context_string(C, sl); return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context); } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 61b737589c8..bbb959c27ff 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -29,18 +29,13 @@ #include "BKE_appdir.h" #include "BKE_blendfile.h" #include "BKE_context.h" -#include "BKE_idcode.h" -#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" -#include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_workspace.h" #include "BLO_readfile.h" -#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -49,13 +44,9 @@ #include "ED_object.h" #include "ED_screen.h" -#include "MEM_guardedalloc.h" - #include "RNA_access.h" #include "RNA_define.h" -#include "DEG_depsgraph.h" - #include "UI_interface.h" #include "UI_resources.h" @@ -63,7 +54,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "WM_toolsystem.h" #include "screen_intern.h" diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 752a5c36010..a5cc262ddcd 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../../render/extern/include ../../windowmanager ../../../../intern/atomic + ../../../../intern/clog ../../../../intern/glew-mx ../../../../intern/guardedalloc ) @@ -47,7 +48,6 @@ set(SRC paint_image.c paint_image_2d.c paint_image_proj.c - paint_image_undo.c paint_mask.c paint_ops.c paint_stroke.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 5c83bdf0012..c59ab6279cd 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -91,6 +91,7 @@ typedef struct CursorSnapshot { GLuint overlay_texture; int size; int zoom; + int curve_preset; } CursorSnapshot; static TexSnapshot primary_snap = {0}; @@ -409,7 +410,7 @@ static void load_tex_cursor_task_cb(void *__restrict userdata, if (len <= 1.0f) { float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */ - buffer[index] = 255 - (GLubyte)(255 * avg); + buffer[index] = (GLubyte)(255 * avg); } else { buffer[index] = 0; @@ -426,7 +427,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) int size; const bool refresh = !cursor_snap.overlay_texture || - (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom; + (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom || + cursor_snap.curve_preset != br->curve_preset; init = (cursor_snap.overlay_texture != 0); @@ -506,6 +508,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + cursor_snap.curve_preset = br->curve_preset; BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE); return 1; @@ -1093,17 +1096,15 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush) return true; } -static void cursor_draw_point_screen_space(const uint gpuattr, - const ARegion *ar, - const float true_location[3], - const float obmat[4][4]) +static void cursor_draw_point_screen_space( + const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size) { float translation_vertex_cursor[3], location[3]; copy_v3_v3(location, true_location); mul_m4_v3(obmat, location); ED_view3d_project(ar, location, translation_vertex_cursor); imm_draw_circle_fill_3d( - gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], 3, 10); + gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10); } static void cursor_draw_tiling_preview(const uint gpuattr, @@ -1145,7 +1146,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr, for (dim = 0; dim < 3; dim++) { location[dim] = cur[dim] * step[dim] + orgLoc[dim]; } - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); } } } @@ -1166,7 +1167,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, /* Axis Symmetry */ flip_v3_v3(location, true_location, (char)i); - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); /* Tiling */ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius); @@ -1181,7 +1182,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, mul_m4_v3(symm_rot_mat, location); cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius); - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); } } } @@ -1191,7 +1192,13 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss) { immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f); - GPU_depth_test(true); + + /* Cursor normally draws on top, but for this part we need depth tests. */ + const bool depth_test = GPU_depth_test_enabled(); + if (!depth_test) { + GPU_depth_test(true); + } + GPU_line_width(1.0f); if (ss->preview_vert_index_count > 0) { immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count); @@ -1200,10 +1207,24 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession } immEnd(); } + + /* Restore depth test value. */ + if (!depth_test) { + GPU_depth_test(false); + } +} + +static bool paint_use_2d_cursor(ePaintMode mode) +{ + if (mode >= PAINT_MODE_TEXTURE_3D) { + return true; + } + return false; } static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -1211,6 +1232,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) Brush *brush = BKE_paint_brush(paint); ePaintMode mode = BKE_paintmode_get_active_from_context(C); + /* 2d or 3d painting? */ + const bool use_2d_cursor = paint_use_2d_cursor(mode); + /* check that brush drawing is enabled */ if (ommit_cursor_drawing(paint, mode, brush)) { return; @@ -1219,7 +1243,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* can't use stroke vc here because this will be called during * mouse over too, not just during a stroke */ ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) { return; @@ -1237,7 +1261,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* set various defaults */ const float *outline_col = brush->add_col; - const float outline_alpha = 0.5f; + const float outline_alpha = 0.7f; float translation[2] = {x, y}; float final_radius = (BKE_brush_size_get(scene, brush) * zoomx); @@ -1251,33 +1275,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* draw overlay */ bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode); - /* TODO: as sculpt and other paint modes are unified, this - * special mode of drawing will go away */ - if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) { - float location[3]; - int pixel_radius; - - /* test if brush is over the mesh */ - bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups); - - if (BKE_brush_use_locked_size(scene, brush)) { - BKE_brush_size_set(scene, brush, pixel_radius); - } - - /* check if brush is subtracting, use different color then */ - /* TODO: no way currently to know state of pen flip or - * invert key modifier without starting a stroke */ - if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) && - BKE_brush_sculpt_has_secondary_color(brush)) { - outline_col = brush->sub_col; - } - - /* only do if brush is over the mesh */ - if (hit) { - paint_cursor_on_hit(ups, brush, &vc, location); - } - } - if (ups->draw_anchored) { final_radius = ups->anchored_size; copy_v2_fl2(translation, @@ -1290,148 +1287,239 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) GPU_blend(true); /* TODO: also set blend mode? */ GPU_line_smooth(true); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + if (use_2d_cursor) { + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - /* set brush color */ - immUniformColor3fvAlpha(outline_col, outline_alpha); + immUniformColor3fvAlpha(outline_col, outline_alpha); - /* draw brush outline */ - if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) { - /* inner at full alpha */ - imm_draw_circle_wire_2d( - pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40); - /* outer at half alpha */ - immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f); + /* draw brush outline */ + if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) { + imm_draw_circle_wire_2d( + pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40); + /* outer at half alpha */ + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f); + } + + GPU_line_width(1.0f); + imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40); } + else { /* 3d painting */ + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + /* TODO: as sculpt and other paint modes are unified, this + * special mode of drawing will go away */ + Object *obact = vc.obact; + SculptSession *ss = obact ? obact->sculpt : NULL; + if ((mode == PAINT_MODE_SCULPT) && ss) { + float location[3]; + int pixel_radius; + + /* test if brush is over the mesh */ + bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups); + + if (BKE_brush_use_locked_size(scene, brush)) { + BKE_brush_size_set(scene, brush, pixel_radius); + } - /* Only sculpt mode cursor for now */ + /* check if brush is subtracting, use different color then */ + /* TODO: no way currently to know state of pen flip or + * invert key modifier without starting a stroke */ + if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) && + BKE_brush_sculpt_has_secondary_color(brush)) { + outline_col = brush->sub_col; + } - /* Disable for PBVH_GRIDS */ - SculptSession *ss = vc.obact->sculpt; - bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS; + /* only do if brush is over the mesh */ + if (hit) { + paint_cursor_on_hit(ups, brush, &vc, location); + } + } - if ((mode == PAINT_MODE_SCULPT) && ss && !is_multires && - !(brush->falloff_shape & BRUSH_AIRBRUSH)) { - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - wmWindow *win = CTX_wm_window(C); + immUniformColor3fvAlpha(outline_col, outline_alpha); - /* Update WM mouse cursor, disable when the 3D brush cursor is enabled */ - if (sd->paint.brush->overlay_flags & BRUSH_OVERLAY_CURSOR) { - WM_cursor_set(win, CURSOR_STD); + if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) { + imm_draw_circle_wire_3d( + pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40); + /* outer at half alpha */ + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f); } - else { - WM_cursor_set(win, CURSOR_EDIT); + + /* Only sculpt mode cursor for now */ + /* Disable for PBVH_GRIDS */ + bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS; + + SculptCursorGeometryInfo gi; + float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin}; + int prev_active_vertex_index = -1; + bool is_cursor_over_mesh = false; + + /* Update the active vertex */ + if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) { + prev_active_vertex_index = ss->active_vertex_index; + is_cursor_over_mesh = sculpt_cursor_geometry_info_update( + C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)); } + /* Use special paint crosshair cursor in all paint modes*/ + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, WM_CURSOR_PAINT); - if (!ups->stroke_active) { - SculptCursorGeometryInfo gi; - float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin}; - if (sculpt_cursor_geometry_info_update(C, &gi, mouse, true) && !alpha_overlay_active) { + if ((mode == PAINT_MODE_SCULPT) && ss && + (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) { + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - float rds; - if (!BKE_brush_use_locked_size(scene, brush)) { - rds = paint_calc_object_space_radius(&vc, gi.location, BKE_brush_size_get(scene, brush)); - } - else { - rds = BKE_brush_unprojected_radius_get(scene, brush); - } + if (!ups->stroke_active) { + bool update_previews = false; + if (is_cursor_over_mesh && !alpha_overlay_active) { - wmViewport(&ar->winrct); + if (prev_active_vertex_index != ss->active_vertex_index) { + update_previews = true; + } - /* Draw 3D active vertex preview with symmetry*/ - if (len_v3v3(gi.active_vertex_co, gi.location) < rds) { - cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds); - } + float rds; + if (!BKE_brush_use_locked_size(scene, brush)) { + rds = paint_calc_object_space_radius( + &vc, gi.location, BKE_brush_size_get(scene, brush)); + } + else { + rds = BKE_brush_unprojected_radius_get(scene, brush); + } - /* Draw 3D brush cursor */ - GPU_matrix_push_projection(); - ED_view3d_draw_setup_view(CTX_wm_window(C), - CTX_data_depsgraph_pointer(C), - CTX_data_scene(C), - ar, - CTX_wm_view3d(C), - NULL, - NULL, - NULL); - - float cursor_trans[4][4], cursor_rot[4][4]; - float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float quat[4]; - - copy_m4_m4(cursor_trans, vc.obact->obmat); - translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]); - rotation_between_vecs_to_quat(quat, z_axis, gi.normal); - quat_to_mat4(cursor_rot, quat); - - GPU_matrix_push(); - GPU_matrix_mul(cursor_trans); - GPU_matrix_mul(cursor_rot); - imm_draw_circle_wire_3d(pos, 0, 0, rds, 40); - GPU_matrix_pop(); - - /* Update and draw dynamic mesh preview lines */ - GPU_matrix_push(); - GPU_matrix_mul(vc.obact->obmat); - if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { - sculpt_geometry_preview_lines_update(C, ss, rds); - sculpt_geometry_preview_lines_draw(pos, ss); + wmViewport(&ar->winrct); + + /* Draw 3D active vertex preview with symmetry*/ + if (len_v3v3(gi.active_vertex_co, gi.location) < rds) { + cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds); + } + + /* Draw pose brush origin */ + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); + if (update_previews) { + BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false); + sculpt_pose_calc_pose_data( + sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL); + } + cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5); + } + + /* Draw 3D brush cursor */ + GPU_matrix_push_projection(); + ED_view3d_draw_setup_view(CTX_wm_window(C), + CTX_data_depsgraph_pointer(C), + CTX_data_scene(C), + ar, + CTX_wm_view3d(C), + NULL, + NULL, + NULL); + + float cursor_trans[4][4], cursor_rot[4][4]; + float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float quat[4]; + + copy_m4_m4(cursor_trans, vc.obact->obmat); + translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]); + rotation_between_vecs_to_quat(quat, z_axis, gi.normal); + quat_to_mat4(cursor_rot, quat); + + GPU_matrix_push(); + GPU_matrix_mul(cursor_trans); + GPU_matrix_mul(cursor_rot); + immUniformColor3fvAlpha(outline_col, outline_alpha); + GPU_line_width(2.0f); + imm_draw_circle_wire_3d(pos, 0, 0, rds, 80); + GPU_line_width(1.0f); + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f); + imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80); + GPU_matrix_pop(); + + /* Update and draw dynamic mesh preview lines */ + GPU_matrix_push(); + GPU_matrix_mul(vc.obact->obmat); + if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) && + !is_multires) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) { + sculpt_geometry_preview_lines_update(C, ss, rds); + sculpt_geometry_preview_lines_draw(pos, ss); + } + } + + /* Draw pose brush line preview */ + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); + GPU_line_width(2.0f); + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, ss->pose_origin); + immVertex3fv(pos, gi.location); + immEnd(); } - } - GPU_matrix_pop(); - GPU_matrix_pop_projection(); + GPU_matrix_pop(); - wmWindowViewport(win); + GPU_matrix_pop_projection(); + + wmWindowViewport(win); + } + else { + /* Draw default cursor when the mouse is not over the mesh or there are no supported + * overlays active */ + GPU_line_width(1.0f); + /* Reduce alpha to increase the contrast when the cursor is over the mesh */ + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8); + imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80); + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f); + imm_draw_circle_wire_3d(pos, + translation[0], + translation[1], + final_radius * clamp_f(brush->alpha, 0.0f, 1.0f), + 80); + } } else { - /* Draw default cursor when the mouse is not over the mesh or there are no supported - * overlays active */ - GPU_line_width(1.0f); - imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40); - } - } - else { - if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) { - /* Draw cursor location preview when the stroke is active using the data from StrokeCache - */ - float cursor_location[3]; - wmViewport(&ar->winrct); - copy_v3_v3(cursor_location, ss->cache->true_location); - if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) { - add_v3_v3(cursor_location, ss->cache->grab_delta); - } - cursor_draw_point_with_symmetry(pos, ar, cursor_location, sd, vc.obact, ss->cache->radius); - - /* Draw cached dynamic mesh preview lines */ - if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) { - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { - GPU_matrix_push_projection(); - ED_view3d_draw_setup_view(CTX_wm_window(C), - CTX_data_depsgraph_pointer(C), - CTX_data_scene(C), - ar, - CTX_wm_view3d(C), - NULL, - NULL, - NULL); - GPU_matrix_push(); - GPU_matrix_mul(vc.obact->obmat); - sculpt_geometry_preview_lines_draw(pos, ss); - GPU_matrix_pop(); - GPU_matrix_pop_projection(); + if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) { + /* Draw cursor location preview when the stroke is active using the data from StrokeCache + */ + float cursor_location[3]; + wmViewport(&ar->winrct); + copy_v3_v3(cursor_location, ss->cache->true_location); + if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) { + add_v3_v3(cursor_location, ss->cache->grab_delta); + } + cursor_draw_point_with_symmetry( + pos, ar, cursor_location, sd, vc.obact, ss->cache->radius); + + /* Draw cached dynamic mesh preview lines */ + if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) && + !is_multires) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) { + GPU_matrix_push_projection(); + ED_view3d_draw_setup_view(CTX_wm_window(C), + CTX_data_depsgraph_pointer(C), + CTX_data_scene(C), + ar, + CTX_wm_view3d(C), + NULL, + NULL, + NULL); + GPU_matrix_push(); + GPU_matrix_mul(vc.obact->obmat); + sculpt_geometry_preview_lines_draw(pos, ss); + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + } } - } - wmWindowViewport(win); + wmWindowViewport(win); + } } } - } - else { - /* Draw default cursor in unsupported modes */ - GPU_line_width(1.0f); - imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40); + else { + /* Draw default cursor in unsupported modes */ + GPU_line_width(1.0f); + imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40); + } } immUnbindProgram(); diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index d9fd194e96f..62c31c91f8d 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -35,8 +35,6 @@ #include "BKE_main.h" #include "BKE_paint.h" -#include "DEG_depsgraph.h" - #include "ED_view3d.h" #include "ED_paint.h" diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c index bd62a59e73f..c14ccd27804 100644 --- a/source/blender/editors/sculpt_paint/paint_curve_undo.c +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -35,7 +35,6 @@ #include "ED_undo.h" #include "WM_api.h" -#include "WM_types.h" #include "paint_intern.h" diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 5852012891d..026dc39c668 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -37,7 +37,6 @@ #include "BKE_ccg.h" #include "BKE_context.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_subsurf.h" @@ -135,7 +134,6 @@ static void partialvis_update_grids(Depsgraph *depsgraph, float planes[4][4]) { CCGElem **grids; - CCGKey key; BLI_bitmap **grid_hidden; int *grid_indices, totgrid, i; bool any_changed = false, any_visible = false; @@ -143,7 +141,7 @@ static void partialvis_update_grids(Depsgraph *depsgraph, /* get PBVH data */ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids); grid_hidden = BKE_pbvh_grid_hidden(pbvh); - BKE_pbvh_get_grid_key(pbvh, &key); + CCGKey key = *BKE_pbvh_get_grid_key(pbvh); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); @@ -299,15 +297,17 @@ static void rect_from_props(rcti *rect, PointerRNA *ptr) rect->ymax = RNA_int_get(ptr, "ymax"); } -static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect) +static void clip_planes_from_rect(bContext *C, + Depsgraph *depsgraph, + float clip_planes[4][4], + const rcti *rect) { ViewContext vc; BoundBox bb; view3d_operator_needs_opengl(C); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect); - negate_m4(clip_planes); } /* If mode is inside, get all PBVH nodes that lie at least partially @@ -322,17 +322,18 @@ static void get_pbvh_nodes( /* select search callback */ switch (mode) { case PARTIALVIS_INSIDE: - cb = BKE_pbvh_node_planes_contain_AABB; + cb = BKE_pbvh_node_frustum_contain_AABB; break; case PARTIALVIS_OUTSIDE: - cb = BKE_pbvh_node_planes_exclude_AABB; + cb = BKE_pbvh_node_frustum_exclude_AABB; break; case PARTIALVIS_ALL: case PARTIALVIS_MASKED: break; } - BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode); + PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 4}; + BKE_pbvh_search_gather(pbvh, cb, &frustum, nodes, totnode); } static int hide_show_exec(bContext *C, wmOperator *op) @@ -355,7 +356,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) area = RNA_enum_get(op->ptr, "area"); rect_from_props(&rect, op->ptr); - clip_planes_from_rect(C, clip_planes, &rect); + clip_planes_from_rect(C, depsgraph, clip_planes, &rect); pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); BLI_assert(ob->sculpt->pbvh == pbvh); @@ -363,6 +364,8 @@ static int hide_show_exec(bContext *C, wmOperator *op) get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); pbvh_type = BKE_pbvh_type(pbvh); + negate_m4(clip_planes); + /* start undo */ switch (action) { case PARTIALVIS_HIDE: diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index f3a6cfa0d5c..b4388f6c324 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -113,10 +113,10 @@ void imapaint_region_tiles( IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h); - *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS); - *th = ((y + h - 1) >> IMAPAINT_TILE_BITS); - *tx = (x >> IMAPAINT_TILE_BITS); - *ty = (y >> IMAPAINT_TILE_BITS); + *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS); + *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS); + *tx = (x >> ED_IMAGE_UNDO_TILE_BITS); + *ty = (y >> ED_IMAGE_UNDO_TILE_BITS); } void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old) @@ -147,11 +147,12 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh); - ListBase *undo_tiles = ED_image_undo_get_tiles(); + ListBase *undo_tiles = ED_image_paint_tile_list_get(); for (ty = tiley; ty <= tileh; ty++) { for (tx = tilex; tx <= tilew; tx++) { - image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); + ED_image_paint_tile_push( + undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old); } } @@ -467,12 +468,13 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2]) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ Brush *brush = BKE_paint_brush(&settings->imapaint.paint); int mode = RNA_enum_get(op->ptr, "mode"); - ED_view3d_viewcontext_init(C, &pop->vc); + ED_view3d_viewcontext_init(C, &pop->vc, depsgraph); copy_v2_v2(pop->prevmouse, mouse); copy_v2_v2(pop->startmouse, mouse); @@ -538,7 +540,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po RNA_float_get_array(itemptr, "mouse", mouse); pressure = RNA_float_get(itemptr, "pressure"); eraser = RNA_boolean_get(itemptr, "pen_flip"); - size = max_ff(1.0f, RNA_float_get(itemptr, "size")); + size = RNA_float_get(itemptr, "size"); /* stroking with fill tool only acts on stroke end */ if (brush->imagepaint_tool == PAINT_TOOL_FILL) { @@ -699,7 +701,7 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) event->type); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { - paint_stroke_data_free(op); + paint_stroke_free(C, op); return OPERATOR_FINISHED; } /* add modal handler */ @@ -1022,7 +1024,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event !RNA_boolean_get(op->ptr, "merged"); paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false); - WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 8f1156295a3..9c95a3cee4d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -374,25 +374,65 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, /* create a mask with the falloff strength */ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, - float radius) + float radius, + const float pos[2]) { Brush *brush = painter->brush; - int xoff = -radius; - int yoff = -radius; + int offset = (int)floorf(diameter / 2.0f); unsigned short *mask, *m; - int x, y; mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); m = mask; - for (y = 0; y < diameter; y++) { - for (x = 0; x < diameter; x++, m++) { - float xy[2] = {x + xoff, y + yoff}; - float len = len_v2(xy); + int aa_samples = 1.0f / (radius * 0.20f); + aa_samples = clamp_i(aa_samples, 3, 16); - *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius)); + /* Temporal until we have the brush properties */ + const float hardness = 1.0f; + const float rotation = 0.0f; + + float aa_offset = 1.0f / (2.0f * (float)aa_samples); + float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = pos[0] - floorf(pos[0]) + offset + aa_offset; + bpos[1] = pos[1] - floorf(pos[1]) + offset + aa_offset; + + const float co = cosf(DEG2RADF(rotation)); + const float si = sinf(DEG2RADF(rotation)); + + float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float total_samples = 0; + for (int i = 0; i < aa_samples; i++) { + for (int j = 0; j < aa_samples; j++) { + float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; + float xy_rot[2]; + sub_v2_v2(pixel_xy, bpos); + + xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; + xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; + + float len = len_v2(xy_rot); + float p = len / radius; + if (hardness < 1.0f) { + p = (p - hardness) / (1 - hardness); + p = 1.0f - p; + CLAMP(p, 0, 1); + } + else { + p = 1.0; + } + float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; + float curve = BKE_brush_curve_strength_clamped(brush, len, radius); + total_samples += curve * hardness_factor; + } + } + *m = (unsigned short)(total_samples * norm_factor); } } @@ -721,7 +761,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; - const int diameter = 2 * size; + /* Adding 4 pixels of padding for brush antialiasing */ + const int diameter = MAX2(1, size * 2) + 4; bool do_random = false; bool do_partial_update = false; @@ -802,15 +843,13 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } /* curve mask can only change if the size changes */ - if (diameter != cache->lastdiameter) { - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - cache->curve_mask = NULL; - } - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size); + if (cache->curve_mask) { + MEM_freeN(cache->curve_mask); + cache->curve_mask = NULL; } + cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* detect if we need to recreate image brush buffer */ if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) || do_random || update_color) { @@ -1197,23 +1236,24 @@ static void paint_2d_do_making_brush(ImagePaintState *s, int tileh) { ImBuf tmpbuf; - IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0); - ListBase *undo_tiles = ED_image_undo_get_tiles(); + ListBase *undo_tiles = ED_image_paint_tile_list_get(); for (int ty = tiley; ty <= tileh; ty++) { for (int tx = tilex; tx <= tilew; tx++) { /* retrieve original pixels + mask from undo buffer */ unsigned short *mask; - int origx = region->destx - tx * IMAPAINT_TILE_SIZE; - int origy = region->desty - ty * IMAPAINT_TILE_SIZE; + int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE; + int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE; if (s->canvas->rect_float) { - tmpbuf.rect_float = image_undo_find_tile( + tmpbuf.rect_float = ED_image_paint_tile_find( undo_tiles, s->image, s->canvas, tx, ty, &mask, false); } else { - tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false); + tmpbuf.rect = ED_image_paint_tile_find( + undo_tiles, s->image, s->canvas, tx, ty, &mask, false); } IMB_rectblend(s->canvas, @@ -1454,8 +1494,6 @@ static void paint_2d_canvas_free(ImagePaintState *s) paint_delete_blur_kernel(s->blurkernel); MEM_freeN(s->blurkernel); } - - image_undo_remove_masks(); } void paint_2d_stroke(void *ps, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 04a54ad5137..4c7e5e18257 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -77,15 +77,11 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "UI_interface.h" - #include "ED_object.h" -#include "ED_mesh.h" #include "ED_node.h" #include "ED_paint.h" #include "ED_screen.h" @@ -93,6 +89,7 @@ #include "ED_view3d.h" #include "GPU_extensions.h" +#include "GPU_init_exit.h" #include "WM_api.h" #include "WM_types.h" @@ -105,7 +102,6 @@ #include "IMB_colormanagement.h" -#include "bmesh.h" //#include "bmesh_tools.h" #include "paint_intern.h" @@ -1812,31 +1808,31 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) } if (generate_tile) { - ListBase *undo_tiles = ED_image_undo_get_tiles(); + ListBase *undo_tiles = ED_image_paint_tile_list_get(); volatile void *undorect; if (tinf->masked) { - undorect = image_undo_push_tile(undo_tiles, - pjIma->ima, - pjIma->ibuf, - tinf->tmpibuf, - tx, - ty, - &pjIma->maskRect[tile_index], - &pjIma->valid[tile_index], - true, - false); + undorect = ED_image_paint_tile_push(undo_tiles, + pjIma->ima, + pjIma->ibuf, + tinf->tmpibuf, + tx, + ty, + &pjIma->maskRect[tile_index], + &pjIma->valid[tile_index], + true, + false); } else { - undorect = image_undo_push_tile(undo_tiles, - pjIma->ima, - pjIma->ibuf, - tinf->tmpibuf, - tx, - ty, - NULL, - &pjIma->valid[tile_index], - true, - false); + undorect = ED_image_paint_tile_push(undo_tiles, + pjIma->ima, + pjIma->ibuf, + tinf->tmpibuf, + tx, + ty, + NULL, + &pjIma->valid[tile_index], + true, + false); } BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf); @@ -1885,14 +1881,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps, /* calculate the undo tile offset of the pixel, used to store the original * pixel color and accumulated mask if any */ - x_tile = x_px >> IMAPAINT_TILE_BITS; - y_tile = y_px >> IMAPAINT_TILE_BITS; + x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS; + y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS; - x_round = x_tile * IMAPAINT_TILE_SIZE; - y_round = y_tile * IMAPAINT_TILE_SIZE; + x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE; + y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE; // memset(projPixel, 0, size); - tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE; + tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE; tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile); /* other thread may be initializing the tile so wait here */ @@ -1900,8 +1896,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps, /* pass */ } - BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y))); - BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE)); + BLI_assert(tile_index < + (ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x) * ED_IMAGE_UNDO_TILE_NUMBER(ibuf->y))); + BLI_assert(tile_offset < (ED_IMAGE_UNDO_TILE_SIZE * ED_IMAGE_UNDO_TILE_SIZE)); projPixel->valid = projima->valid[tile_index]; @@ -2979,7 +2976,7 @@ static void project_paint_face_init(const ProjPaintState *ps, TileInfo tinf = { ps->tile_lock, ps->do_masking, - IMAPAINT_TILE_NUMBER(ibuf->x), + ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x), tmpibuf, ps->projImages + image_index, }; @@ -3931,7 +3928,7 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th BLI_spin_init(ps->tile_lock); } - image_undo_init_locks(); + ED_image_paint_tile_lock_init(); } for (a = 0; a < ps->thread_tot; a++) { @@ -4249,8 +4246,8 @@ static void project_paint_build_proj_ima(ProjPaintState *ps, projIma->ima = node->link; projIma->touch = 0; projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); - size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * - IMAPAINT_TILE_NUMBER(projIma->ibuf->y); + size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) * + ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y); projIma->partRedrawRect = BLI_memarena_alloc( arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); partial_redraw_array_init(projIma->partRedrawRect); @@ -4540,8 +4537,6 @@ static void project_paint_end(ProjPaintState *ps) { int a; - image_undo_remove_masks(); - /* dereference used image buffers */ if (ps->is_shared_user == false) { ProjPaintImage *projIma; @@ -4583,7 +4578,7 @@ static void project_paint_end(ProjPaintState *ps) MEM_freeN((void *)ps->tile_lock); } - image_undo_end_locks(); + ED_image_paint_tile_lock_end(); #ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->seam_bleed_px > 0.0f) { @@ -6143,6 +6138,9 @@ static bool texture_paint_image_from_view_poll(bContext *C) CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from"); return false; } + if (!GPU_is_initialized()) { + return false; + } return true; } diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c deleted file mode 100644 index 93dcd3ad0f6..00000000000 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup edsculpt - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" -#include "BLI_threads.h" - -#include "DNA_image_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_object_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_workspace_types.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "BKE_context.h" -#include "BKE_image.h" -#include "BKE_paint.h" -#include "BKE_undo_system.h" - -#include "DEG_depsgraph.h" - -#include "ED_paint.h" -#include "ED_undo.h" -#include "ED_util.h" -#include "ED_object.h" - -#include "GPU_draw.h" - -#include "WM_api.h" - -#include "paint_intern.h" - -/* -------------------------------------------------------------------- */ -/** \name Undo Conversion - * \{ */ - -typedef struct UndoImageTile { - struct UndoImageTile *next, *prev; - - char ibufname[IMB_FILENAME_SIZE]; - - union { - float *fp; - unsigned int *uint; - void *pt; - } rect; - - unsigned short *mask; - - int x, y; - - /* TODO(campbell): avoid storing the ID per tile, - * adds unnecessary overhead restoring undo steps when most tiles share the same image. */ - UndoRefID_Image image_ref; - - short source; - bool use_float; - char gen_type; - bool valid; - - size_t undo_size; -} UndoImageTile; - -/* this is a static resource for non-globality, - * Maybe it should be exposed as part of the - * paint operation, but for now just give a public interface */ -static SpinLock undolock; - -void image_undo_init_locks(void) -{ - BLI_spin_init(&undolock); -} - -void image_undo_end_locks(void) -{ - BLI_spin_end(&undolock); -} - -/* UNDO */ -typedef enum { - COPY = 0, - RESTORE = 1, - RESTORE_COPY = 2, -} CopyMode; - -static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) -{ - if (mode == COPY) { - /* copy or swap contents of tile->rect and region in ibuf->rect */ - IMB_rectcpy(tmpibuf, - ibuf, - 0, - 0, - tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, - IMAPAINT_TILE_SIZE, - IMAPAINT_TILE_SIZE); - - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - else { - if (mode == RESTORE_COPY) { - IMB_rectcpy(tmpibuf, - ibuf, - 0, - 0, - tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, - IMAPAINT_TILE_SIZE, - IMAPAINT_TILE_SIZE); - } - /* swap to the tmpbuf for easy copying */ - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - - IMB_rectcpy(ibuf, - tmpibuf, - tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, - 0, - 0, - IMAPAINT_TILE_SIZE, - IMAPAINT_TILE_SIZE); - - if (mode == RESTORE) { - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); - } - else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - } - } -} - -void *image_undo_find_tile(ListBase *undo_tiles, - Image *ima, - ImBuf *ibuf, - int x_tile, - int y_tile, - unsigned short **mask, - bool validate) -{ - UndoImageTile *tile; - const bool use_float = (ibuf->rect_float != NULL); - - for (tile = undo_tiles->first; tile; tile = tile->next) { - if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && - ima->source == tile->source) { - if (tile->use_float == use_float) { - if (STREQ(tile->ibufname, ibuf->name)) { - if (mask) { - /* allocate mask if requested */ - if (!tile->mask) { - tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * - IMAPAINT_TILE_SIZE, - "UndoImageTile.mask"); - } - - *mask = tile->mask; - } - if (validate) { - tile->valid = true; - } - return tile->rect.pt; - } - } - } - } - - return NULL; -} - -void *image_undo_push_tile(ListBase *undo_tiles, - Image *ima, - ImBuf *ibuf, - ImBuf **tmpibuf, - int x_tile, - int y_tile, - unsigned short **mask, - bool **valid, - bool proj, - bool find_prev) -{ - UndoImageTile *tile; - int allocsize; - const bool use_float = (ibuf->rect_float != NULL); - void *data; - - /* check if tile is already pushed */ - - /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ - if (find_prev) { - data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true); - if (data) { - return data; - } - } - - if (*tmpibuf == NULL) { - *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - } - - tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); - tile->x = x_tile; - tile->y = y_tile; - - /* add mask explicitly here */ - if (mask) { - *mask = tile->mask = MEM_callocN( - sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask"); - } - allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); - tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); - - BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname)); - - tile->gen_type = ima->gen_type; - tile->source = ima->source; - tile->use_float = use_float; - tile->valid = true; - tile->image_ref.ptr = ima; - - if (valid) { - *valid = &tile->valid; - } - undo_copy_tile(tile, *tmpibuf, ibuf, COPY); - - if (proj) { - BLI_spin_lock(&undolock); - } - BLI_addtail(undo_tiles, tile); - - if (proj) { - BLI_spin_unlock(&undolock); - } - return tile->rect.pt; -} - -void image_undo_remove_masks(void) -{ - ListBase *undo_tiles = ED_image_undo_get_tiles(); - UndoImageTile *tile; - - for (tile = undo_tiles->first; tile; tile = tile->next) { - if (tile->mask) { - MEM_freeN(tile->mask); - tile->mask = NULL; - } - } -} - -static void image_undo_restore_runtime(ListBase *lb) -{ - ImBuf *ibuf, *tmpibuf; - UndoImageTile *tile; - - tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - - for (tile = lb->first; tile; tile = tile->next) { - Image *ima = tile->image_ref.ptr; - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); - - GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ - if (ibuf->rect_float) { - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - } - if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - } - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -static void image_undo_restore_list(ListBase *lb) -{ - ImBuf *tmpibuf = IMB_allocImBuf( - IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - - for (UndoImageTile *tile = lb->first; tile; tile = tile->next) { - - Image *ima = tile->image_ref.ptr; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { - /* current ImBuf filename was changed, probably current frame - * was changed when painting on image sequence, rather than storing - * full image user (which isn't so obvious, btw) try to find ImBuf with - * matched file name in list of already loaded images */ - - BKE_image_release_ibuf(ima, ibuf, NULL); - - ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname); - } - - if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - if (ima->gen_type != tile->gen_type || ima->source != tile->source) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - const bool use_float = (ibuf->rect_float != NULL); - - if (use_float != tile->use_float) { - BKE_image_release_ibuf(ima, ibuf, NULL); - continue; - } - - undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); - - BKE_image_mark_dirty(ima, ibuf); - GPU_free_image(ima); /* force OpenGL reload */ - - if (ibuf->rect_float) { - ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ - } - if (ibuf->mipmap[0]) { - ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ - } - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - DEG_id_tag_update(&ima->id, 0); - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - IMB_freeImBuf(tmpibuf); -} - -static void image_undo_free_list(ListBase *lb) -{ - for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) { - tile_next = tile->next; - MEM_freeN(tile->rect.pt); - MEM_freeN(tile); - } -} - -static void image_undo_invalidate(void) -{ - UndoImageTile *tile; - ListBase *lb = ED_image_undo_get_tiles(); - - for (tile = lb->first; tile; tile = tile->next) { - tile->valid = false; - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Implements ED Undo System - * \{ */ - -typedef struct ImageUndoStep { - UndoStep step; - ListBase tiles; - bool is_encode_init; - ePaintMode paint_mode; -} ImageUndoStep; - -static bool image_undosys_poll(bContext *C) -{ - Object *obact = CTX_data_active_object(C); - - ScrArea *sa = CTX_wm_area(C); - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - return true; - } - } - else { - if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) { - return true; - } - } - return false; -} - -static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) -{ - ImageUndoStep *us = (ImageUndoStep *)us_p; - /* dummy, memory is cleared anyway. */ - us->is_encode_init = true; - BLI_listbase_clear(&us->tiles); -} - -static bool image_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) -{ - /* dummy, encoding is done along the way by adding tiles - * to the current 'ImageUndoStep' added by encode_init. */ - ImageUndoStep *us = (ImageUndoStep *)us_p; - - BLI_assert(us->step.data_size == 0); - - int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - - if (us->is_encode_init) { - /* first dispose of invalid tiles (may happen due to drag dot for instance) */ - for (UndoImageTile *tile = us->tiles.first; tile;) { - if (!tile->valid) { - UndoImageTile *tmp_tile = tile->next; - MEM_freeN(tile->rect.pt); - BLI_freelinkN(&us->tiles, tile); - tile = tmp_tile; - } - else { - us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char)); - tile = tile->next; - } - } - } - else { - /* Happens when switching modes. */ - ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); - BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); - us->paint_mode = paint_mode; - } - - us_p->is_applied = true; - - return true; -} - -static void image_undosys_step_decode_undo_impl(ImageUndoStep *us) -{ - BLI_assert(us->step.is_applied == true); - image_undo_restore_list(&us->tiles); - us->step.is_applied = false; -} - -static void image_undosys_step_decode_redo_impl(ImageUndoStep *us) -{ - BLI_assert(us->step.is_applied == false); - image_undo_restore_list(&us->tiles); - us->step.is_applied = true; -} - -static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final) -{ - ImageUndoStep *us_iter = us; - while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { - if (us_iter->step.next->is_applied == false) { - break; - } - us_iter = (ImageUndoStep *)us_iter->step.next; - } - while (us_iter != us || (!is_final && us_iter == us)) { - image_undosys_step_decode_undo_impl(us_iter); - if (us_iter == us) { - break; - } - us_iter = (ImageUndoStep *)us_iter->step.prev; - } -} - -static void image_undosys_step_decode_redo(ImageUndoStep *us) -{ - ImageUndoStep *us_iter = us; - while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { - if (us_iter->step.prev->is_applied == true) { - break; - } - us_iter = (ImageUndoStep *)us_iter->step.prev; - } - while (us_iter && (us_iter->step.is_applied == false)) { - image_undosys_step_decode_redo_impl(us_iter); - if (us_iter == us) { - break; - } - us_iter = (ImageUndoStep *)us_iter->step.next; - } -} - -static void image_undosys_step_decode( - struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final) -{ - ImageUndoStep *us = (ImageUndoStep *)us_p; - if (dir < 0) { - image_undosys_step_decode_undo(us, is_final); - } - else { - image_undosys_step_decode_redo(us); - } - - if (us->paint_mode == PAINT_MODE_TEXTURE_3D) { - ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT); - } - - /* Refresh texture slots. */ - ED_editors_init_for_undo(bmain); -} - -static void image_undosys_step_free(UndoStep *us_p) -{ - ImageUndoStep *us = (ImageUndoStep *)us_p; - image_undo_free_list(&us->tiles); -} - -static void image_undosys_foreach_ID_ref(UndoStep *us_p, - UndoTypeForEachIDRefFn foreach_ID_ref_fn, - void *user_data) -{ - ImageUndoStep *us = (ImageUndoStep *)us_p; - for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) { - foreach_ID_ref_fn(user_data, ((UndoRefID *)&tile->image_ref)); - } -} - -/* Export for ED_undo_sys. */ -void ED_image_undosys_type(UndoType *ut) -{ - ut->name = "Image"; - ut->poll = image_undosys_poll; - ut->step_encode_init = image_undosys_step_encode_init; - ut->step_encode = image_undosys_step_encode; - ut->step_decode = image_undosys_step_decode; - ut->step_free = image_undosys_step_free; - - ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; - - ut->use_context = true; - - ut->step_size = sizeof(ImageUndoStep); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Utilities - * \{ */ - -ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p) -{ - ImageUndoStep *us = (ImageUndoStep *)us_p; - return &us->tiles; -} - -ListBase *ED_image_undo_get_tiles(void) -{ - UndoStack *ustack = ED_undo_stack_get(); - UndoStep *us_prev = ustack->step_init; - UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); - ImageUndoStep *us = (ImageUndoStep *)us_p; - /* We should always have an undo push started when accessing tiles, - * not doing this means we won't have paint_mode correctly set. */ - BLI_assert(us_p == us_prev); - if (us_p != us_prev) { - /* Fallback value until we can be sure this never happens. */ - us->paint_mode = PAINT_MODE_TEXTURE_2D; - } - return ED_image_undosys_step_get_tiles(us_p); -} - -/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ -void ED_image_undo_restore(UndoStep *us) -{ - ListBase *lb = ED_image_undosys_step_get_tiles(us); - image_undo_restore_runtime(lb); - image_undo_invalidate(); -} - -void ED_image_undo_push_begin(const char *name, int paint_mode) -{ - UndoStack *ustack = ED_undo_stack_get(); - bContext *C = NULL; /* special case, we never read from this. */ - UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); - ImageUndoStep *us = (ImageUndoStep *)us_p; - BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); - us->paint_mode = paint_mode; -} - -void ED_image_undo_push_end(void) -{ - UndoStack *ustack = ED_undo_stack_get(); - BKE_undosys_step_push(ustack, NULL, NULL); - WM_file_tag_modified(); -} - -/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 5efedf69fe4..19380fb9022 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -29,7 +29,6 @@ struct Brush; struct ColorManagedDisplay; struct ColorSpace; struct ImagePool; -struct ListBase; struct MTex; struct Object; struct Paint; @@ -37,7 +36,6 @@ struct PaintStroke; struct PointerRNA; struct RegionView3D; struct Scene; -struct UndoStep; struct VPaint; struct ViewContext; struct bContext; @@ -70,7 +68,7 @@ struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeRedraw redraw, StrokeDone done, int event_type); -void paint_stroke_data_free(struct wmOperator *op); +void paint_stroke_free(struct bContext *C, struct wmOperator *op); bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode); bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode); @@ -184,10 +182,6 @@ typedef struct ImagePaintPartialRedraw { int enabled; } ImagePaintPartialRedraw; -#define IMAPAINT_TILE_BITS 6 -#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) -#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) - bool image_texture_paint_poll(struct bContext *C); void imapaint_image_update(struct SpaceImage *sima, struct Image *image, @@ -252,31 +246,6 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); -/* paint_image_undo.c */ -void *image_undo_find_tile(ListBase *undo_tiles, - struct Image *ima, - struct ImBuf *ibuf, - int x_tile, - int y_tile, - unsigned short **mask, - bool validate); -void *image_undo_push_tile(ListBase *undo_tiles, - struct Image *ima, - struct ImBuf *ibuf, - struct ImBuf **tmpibuf, - int x_tile, - int y_tile, - unsigned short **, - bool **valid, - bool proj, - bool find_prev); -void image_undo_remove_masks(void); -void image_undo_init_locks(void); -void image_undo_end_locks(void); - -struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p); -struct ListBase *ED_image_undo_get_tiles(void); - /* sculpt_uv.c */ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0e8d4d75360..d160fba4013 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -109,6 +109,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata, const PaintMaskFloodMode mode = data->mode; const float value = data->value; + bool redraw = false; PBVHVertexIter vi; @@ -116,13 +117,19 @@ static void mask_flood_fill_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { + float prevmask = *vi.mask; mask_flood_fill_set_elem(vi.mask, mode, value); + if (prevmask != *vi.mask) { + redraw = true; + } } BKE_pbvh_vertex_iter_end; - BKE_pbvh_node_mark_redraw(node); - if (data->multires) { - BKE_pbvh_node_mark_normals_update(node); + if (redraw) { + BKE_pbvh_node_mark_update_mask(node); + if (data->multires) { + BKE_pbvh_node_mark_normals_update(node); + } } } @@ -159,17 +166,16 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .value = value, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range( - - 0, totnode, &data, mask_flood_fill_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } + BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask); + sculpt_undo_push_end(); if (nodes) { @@ -255,24 +261,32 @@ static void mask_box_select_task_cb(void *__restrict userdata, PBVHVertexIter vi; bool any_masked = false; + bool redraw = false; BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { if (is_effected(clip_planes_final, vi.co)) { + float prevmask = *vi.mask; if (!any_masked) { any_masked = true; sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_node_mark_redraw(node); if (data->multires) { BKE_pbvh_node_mark_normals_update(node); } } mask_flood_fill_set_elem(vi.mask, mode, value); + if (prevmask != *vi.mask) { + redraw = true; + } } } BKE_pbvh_vertex_iter_end; + + if (redraw) { + BKE_pbvh_node_mark_update_mask(node); + } } bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select) @@ -297,7 +311,6 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * /* transform the clip planes in object space */ ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect); - negate_m4(clip_planes); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); pbvh = ob->sculpt->pbvh; @@ -315,8 +328,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * flip_plane(clip_planes_final[j], clip_planes[j], symmpass); } - BKE_pbvh_search_gather( - pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); + PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4}; + BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode); + + negate_m4(clip_planes_final); MaskTaskData data = { .ob = ob, @@ -328,11 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .clip_planes_final = clip_planes_final, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -344,6 +357,8 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } + BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask); + sculpt_undo_push_end(); ED_region_tag_redraw(ar); @@ -462,7 +477,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) /* Calculations of individual vertices are done in 2D screen space to diminish the amount of * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle * of lasso */ - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); /* lasso data calculations */ data.vc = &vc; @@ -483,7 +498,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) &data); ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect); - negate_m4(clip_planes); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); pbvh = ob->sculpt->pbvh; @@ -505,8 +519,11 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) /* gather nodes inside lasso's enclosing rectangle * (should greatly help with bigger meshes) */ + PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4}; BKE_pbvh_search_gather( - pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); + pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode); + + negate_m4(clip_planes_final); data.task_data.ob = ob; data.task_data.pbvh = pbvh; @@ -515,11 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - (totnode > SCULPT_THREADED_LIMIT)); - BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -531,6 +546,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } + BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask); + sculpt_undo_push_end(); ED_region_tag_redraw(vc.ar); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index f58afcdadc1..97455d479dc 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -29,32 +29,22 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" #include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_paint.h" -#include "BKE_report.h" - -#include "DEG_depsgraph.h" #include "ED_paint.h" #include "ED_screen.h" -#include "ED_select_utils.h" #include "ED_image.h" -#include "ED_gpencil.h" -#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" -#include "WM_toolsystem.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "paint_intern.h" #include "sculpt_intern.h" diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index c764933fcf0..36418045551 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -43,7 +43,6 @@ #include "BKE_curve.h" #include "BKE_colortools.h" #include "BKE_image.h" -#include "BKE_mesh.h" #include "WM_api.h" #include "WM_types.h" @@ -257,6 +256,7 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM, SCULPT_TOOL_POSE)) { return false; @@ -669,7 +669,7 @@ static float paint_space_stroke_spacing(bContext *C, return max_ff(0.001f, size_clamp * spacing / 50.f); } else { - return max_ff(1.0, size_clamp * spacing / 50.0f); + return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f); } } @@ -808,7 +808,7 @@ static int paint_space_stroke(bContext *C, while (length > 0.0f) { float spacing = paint_space_stroke_spacing_variable( C, scene, stroke, pressure, dpressure, length); - float mouse[2]; + float mouse[3]; if (length >= spacing) { if (use_scene_spacing) { @@ -857,14 +857,16 @@ PaintStroke *paint_stroke_new(bContext *C, StrokeDone done, int event_type) { + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); ToolSettings *toolsettings = CTX_data_tool_settings(C); UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; Paint *p = BKE_paint_get_active_from_context(C); Brush *br = stroke->brush = BKE_paint_brush(p); + RegionView3D *rv3d = CTX_wm_region_view3d(C); float zoomx, zoomy; - ED_view3d_viewcontext_init(C, &stroke->vc); + ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph); stroke->get_location = get_location; stroke->test_start = test_start; @@ -887,6 +889,10 @@ PaintStroke *paint_stroke_new(bContext *C, ups->overlap_factor = 1.0; ups->stroke_active = true; + if (rv3d) { + rv3d->rflag |= RV3D_PAINTING; + } + zero_v3(ups->average_stroke_accum); ups->average_stroke_counter = 0; @@ -901,20 +907,46 @@ PaintStroke *paint_stroke_new(bContext *C, return stroke; } -void paint_stroke_data_free(struct wmOperator *op) +void paint_stroke_free(bContext *C, wmOperator *op) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d) { + rv3d->rflag &= ~RV3D_PAINTING; + } + BKE_paint_set_overlay_override(0); + + PaintStroke *stroke = op->customdata; + if (stroke == NULL) { + return; + } + + UnifiedPaintSettings *ups = stroke->ups; + ups->draw_anchored = false; + ups->stroke_active = false; + + if (stroke->timer) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); + } + + if (stroke->rng) { + BLI_rng_free(stroke->rng); + } + + if (stroke->stroke_cursor) { + WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor); + } + + BLI_freelistN(&stroke->line); + MEM_SAFE_FREE(op->customdata); } -static void stroke_done(struct bContext *C, struct wmOperator *op) +static void stroke_done(bContext *C, wmOperator *op) { - struct PaintStroke *stroke = op->customdata; + PaintStroke *stroke = op->customdata; UnifiedPaintSettings *ups = stroke->ups; - ups->draw_anchored = false; - ups->stroke_active = false; - /* reset rotation here to avoid doing so in cursor display */ if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { ups->brush_rotation = 0.0f; @@ -934,21 +966,7 @@ static void stroke_done(struct bContext *C, struct wmOperator *op) } } - if (stroke->timer) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); - } - - if (stroke->rng) { - BLI_rng_free(stroke->rng); - } - - if (stroke->stroke_cursor) { - WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor); - } - - BLI_freelistN(&stroke->line); - - paint_stroke_data_free(op); + paint_stroke_free(C, op); } /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ @@ -962,6 +980,7 @@ static bool sculpt_is_grab_tool(Brush *br) return ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ELASTIC_DEFORM, + SCULPT_TOOL_POSE, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 6459325e6ee..a014fe7fdff 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -46,7 +46,6 @@ #include "BKE_image.h" #include "BKE_material.h" #include "BKE_mesh_runtime.h" -#include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" @@ -145,7 +144,6 @@ void paint_calc_redraw_planes(float planes[4][4], rect.ymax += 2; ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect); - negate_m4(planes); } float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius) @@ -506,7 +504,7 @@ void paint_sample_color( unsigned int totpoly = me->totpoly; if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) { - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 12da8790b91..77c95c6acb3 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -34,7 +34,6 @@ #include "BLI_array_utils.h" #include "BLI_task.h" -#include "DNA_armature_types.h" #include "DNA_mesh_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" @@ -42,7 +41,6 @@ #include "DNA_object_types.h" #include "RNA_access.h" -#include "RNA_define.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -195,17 +193,12 @@ static bool vertex_paint_use_fast_update_check(Object *ob) return false; } -static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2]) +static void paint_last_stroke_update(Scene *scene, const float location[3]) { - const int mval_i[2] = {mval[0], mval[1]}; - float world[3]; - - if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) { - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - ups->average_stroke_counter++; - add_v3_v3(ups->average_stroke_accum, world); - ups->last_stroke_valid = true; - } + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + ups->average_stroke_counter++; + add_v3_v3(ups->average_stroke_accum, location); + ups->last_stroke_valid = true; } /* polling - retrieve whether cursor should be set or operator should be done */ @@ -260,7 +253,7 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool) (BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) && (sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) { ARegion *ar = CTX_wm_region(C); - if (ar->regiontype == RGN_TYPE_WINDOW) { + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) { if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) { return 1; } @@ -1610,7 +1603,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo /* make mode data storage */ wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData"); paint_stroke_set_mode_data(stroke, wpd); - ED_view3d_viewcontext_init(C, &wpd->vc); + ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph); view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle, (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); @@ -2079,11 +2072,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data, struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && - totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -2128,24 +2119,23 @@ static void wpaint_paint_leaves(bContext *C, /* Use this so average can modify its weight without touching the brush. */ data.strength = BKE_brush_weight_get(scene, brush); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); /* NOTE: current mirroring code cannot be run in parallel */ - settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode); switch ((eBrushWeightPaintTool)brush->weightpaint_tool) { case WPAINT_TOOL_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; case WPAINT_TOOL_SMEAR: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); break; case WPAINT_TOOL_BLUR: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); break; case WPAINT_TOOL_DRAW: - BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; } } @@ -2351,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); + paint_last_stroke_update(scene, ss->cache->location); BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); @@ -2446,7 +2436,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) event->type); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { - paint_stroke_data_free(op); + paint_stroke_free(C, op); return OPERATOR_FINISHED; } /* add modal handler */ @@ -2597,11 +2587,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) * - revise whether op->customdata should be added in object, in set_vpaint */ -typedef struct PolyFaceMap { - struct PolyFaceMap *next, *prev; - int facenr; -} PolyFaceMap; - struct VPaintData { ViewContext vc; struct NormalAnglePrecalc normal_angle_precalc; @@ -2655,7 +2640,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f /* make mode data storage */ vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); - ED_view3d_viewcontext_init(C, &vpd->vc); + ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph); view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle, (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); @@ -3141,9 +3126,9 @@ static void calculate_average_color(SculptThreadedTaskData *data, struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -3187,21 +3172,21 @@ static void vpaint_paint_leaves(bContext *C, .lcol = (uint *)me->mloopcol, .me = me, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { case VPAINT_TOOL_AVERAGE: calculate_average_color(&data, nodes, totnode); - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; case VPAINT_TOOL_BLUR: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); break; case VPAINT_TOOL_SMEAR: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); break; case VPAINT_TOOL_DRAW: - BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; } } @@ -3331,7 +3316,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); + paint_last_stroke_update(scene, ss->cache->location); ED_region_tag_redraw(vc->ar); @@ -3388,7 +3373,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) event->type); if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { - paint_stroke_data_free(op); + paint_stroke_free(C, op); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c index 068c36abdaa..71865d0de73 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c @@ -20,13 +20,9 @@ * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`. */ -#include "MEM_guardedalloc.h" - -#include "DNA_brush_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" #include "BLI_math_base.h" #include "BLI_math_color.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index 4aa9dc8a295..f0fe2d4ebdc 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -24,13 +24,8 @@ #include "BLI_math.h" #include "BLI_bitmap.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" -#include "IMB_colormanagement.h" - #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_particle_types.h" #include "DNA_brush_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -44,7 +39,6 @@ #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_iterators.h" -#include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object_deform.h" @@ -178,11 +172,12 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot) /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Mesh *me; bool changed = false; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); me = BKE_mesh_from_object(vc.obact); if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) { @@ -308,10 +303,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, if (C) { wmWindow *win = CTX_wm_window(C); if (win && win->eventstate) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); ViewContext vc; Mesh *me; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); me = BKE_mesh_from_object(vc.obact); if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) { @@ -379,8 +375,9 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, static int weight_sample_group_exec(bContext *C, wmOperator *op) { int type = RNA_enum_get(op->ptr, "group"); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); BLI_assert(type + 1 >= 0); vc.obact->actdef = type + 1; @@ -885,7 +882,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot) prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); + WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT); } /** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c index c71315872f6..28699b45add 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -20,16 +20,12 @@ * Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`. */ -#include "MEM_guardedalloc.h" - #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string_utils.h" #include "DNA_armature_types.h" #include "DNA_mesh_types.h" -#include "DNA_scene_types.h" -#include "DNA_brush_types.h" #include "DNA_object_types.h" #include "BKE_action.h" diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 351e4c0482b..06fa03ccbc6 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -27,13 +27,11 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_dial_2d.h" -#include "BLI_hash.h" #include "BLI_gsqueue.h" -#include "BLI_stack.h" +#include "BLI_ghash.h" +#include "BLI_hash.h" #include "BLI_task.h" -#include "BLI_stack.h" #include "BLI_utildefines.h" -#include "BLI_ghash.h" #include "BLT_translation.h" @@ -66,10 +64,10 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "WM_api.h" #include "WM_types.h" @@ -96,21 +94,13 @@ #include <stdlib.h> #include <string.h> -/* Sculpt PBVH abstraction API */ - -/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */ - -float *sculpt_vertex_co_get(SculptSession *ss, int index) -{ - switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - return ss->mvert[index].co; - case PBVH_BMESH: - return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co; - default: - return NULL; - } -} +/* Sculpt PBVH abstraction API + * + * This is read-only, for writing use PBVH vertex iterators. There vd.index matches + * the indices used here. + * + * For multires, the same vertex in multiple grids is counted multiple times, with + * different index for each grid. */ static void sculpt_vertex_random_access_init(SculptSession *ss) { @@ -119,28 +109,36 @@ static void sculpt_vertex_random_access_init(SculptSession *ss) } } -static int sculpt_active_vertex_get(SculptSession *ss) +static int sculpt_vertex_count_get(SculptSession *ss) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->active_vertex_index; + return ss->totvert; case PBVH_BMESH: - return ss->active_vertex_index; - default: - return 0; + return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT); + case PBVH_GRIDS: + return BKE_pbvh_get_grid_num_vertices(ss->pbvh); } + + return 0; } -static int sculpt_vertex_count_get(SculptSession *ss) +const float *sculpt_vertex_co_get(SculptSession *ss, int index) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->totvert; + return ss->mvert[index].co; case PBVH_BMESH: - return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT); - default: - return 0; + return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; + return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index)); + } } + return NULL; } static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3]) @@ -152,27 +150,14 @@ static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3]) case PBVH_BMESH: copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no); break; - default: - zero_v3(no); - return; - } -} - -static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask) -{ - BMVert *v; - float *mask_p; - switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - ss->vmask[index] = mask; - return; - case PBVH_BMESH: - v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); - mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); - *(mask_p) = mask; - return; - default: - return; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; + copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index))); + break; + } } } @@ -187,49 +172,58 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index) v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index); mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); return *mask; - default: - return 0; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index]; + return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index)); + } } + + return 0.0f; } -static void UNUSED_FUNCTION(sculpt_vertex_co_set)(SculptSession *ss, int index, float co[3]) +static int sculpt_active_vertex_get(SculptSession *ss) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - copy_v3_v3(ss->mvert[index].co, co); - return; + return ss->active_vertex_index; case PBVH_BMESH: - copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co); - return; - default: - return; + return ss->active_vertex_index; + case PBVH_GRIDS: + return ss->active_vertex_index; } + + return 0; } -static void UNUSED_FUNCTION(sculpt_vertex_tag_update)(SculptSession *ss, int index) +static const float *sculpt_active_vertex_co_get(SculptSession *ss) { - switch (BKE_pbvh_type(ss->pbvh)) { - case PBVH_FACES: - ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE; - return; - case PBVH_BMESH: - return; - default: - return; - } + return sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)); +} + +static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3]) +{ + sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), normal); } #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { + /* Storage */ int *neighbors; int size; int capacity; - int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY]; - int index; + /* Internal iterator. */ + int num_duplicates; int i; + + /* Public */ + int index; + bool is_duplicate; } SculptVertexNeighborIter; static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index) @@ -265,6 +259,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss, BMIter liter; BMLoop *l; iter->size = 0; + iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; @@ -287,6 +282,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, int i; MeshElemMap *vert_map = &ss->pmap[(int)index]; iter->size = 0; + iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; @@ -296,18 +292,52 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) { int j; for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) { - if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) { - if (f_adj_v[j] != (int)index) { - sculpt_vertex_neighbor_add(iter, f_adj_v[j]); - } + if (f_adj_v[j] != (int)index) { + sculpt_vertex_neighbor_add(iter, f_adj_v[j]); } } } } } +static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, + const int index, + const bool include_duplicates, + SculptVertexNeighborIter *iter) +{ + /* TODO: optimize this. We could fill SculptVertexNeighborIter directly, + * maybe provide coordinate and mask pointers directly rather than converting + * back and forth between CCGElem and global index. */ + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + + SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + + SubdivCCGNeighbors neighbors; + BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors); + + iter->size = 0; + iter->num_duplicates = neighbors.num_duplicates; + iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; + iter->neighbors = iter->neighbors_fixed; + + for (int i = 0; i < neighbors.size; i++) { + sculpt_vertex_neighbor_add(iter, + neighbors.coords[i].grid_index * key->grid_area + + neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x); + } + + if (neighbors.coords != neighbors.coords_fixed) { + MEM_freeN(neighbors.coords); + } +} + static void sculpt_vertex_neighbors_get(SculptSession *ss, - int index, + const int index, + const bool include_duplicates, SculptVertexNeighborIter *iter) { switch (BKE_pbvh_type(ss->pbvh)) { @@ -317,17 +347,29 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss, case PBVH_BMESH: sculpt_vertex_neighbors_get_bmesh(ss, index, iter); return; - default: - break; + case PBVH_GRIDS: + sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter); + return; } } +/* Iterator over neighboring vertices. */ #define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ - sculpt_vertex_neighbors_get(ss, v_index, &neighbor_iterator); \ + sculpt_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ neighbor_iterator.i++) { \ neighbor_iterator.index = ni.neighbors[ni.i]; +/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come + * first since they are nearest for floodfill. */ +#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \ + sculpt_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ + for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ + neighbor_iterator.i--) { \ + neighbor_iterator.index = ni.neighbors[ni.i]; \ + neighbor_iterator.is_duplicate = (ni.i >= \ + neighbor_iterator.size - neighbor_iterator.num_duplicates); + #define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \ } \ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ @@ -336,17 +378,6 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss, ((void)0) /* Utils */ -static void sculpt_vertex_mask_clamp(SculptSession *ss, int index, float min, float max) -{ - float mask = sculpt_vertex_mask_get(ss, index); - if (mask > max) { - sculpt_vertex_mask_set(ss, index, max); - } - else if (mask < min) { - sculpt_vertex_mask_set(ss, index, min); - } -} - static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm) { bool is_in_symmetry_area = true; @@ -366,37 +397,46 @@ static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], return is_in_symmetry_area; } +typedef struct NearestVertexTLSData { + int nearest_vertex_index; + float nearest_vertex_distance_squared; +} NearestVertexTLSData; + static void do_nearest_vertex_get_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; + NearestVertexTLSData *nvtd = tls->userdata_chunk; PBVHVertexIter vd; - int node_nearest_vertex_index = -1; - float node_nearest_vertex_distance_squared = FLT_MAX; BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co); - if (distance_squared < node_nearest_vertex_distance_squared && + if (distance_squared < nvtd->nearest_vertex_distance_squared && distance_squared < data->max_distance_squared) { - node_nearest_vertex_index = vd.index; - node_nearest_vertex_distance_squared = distance_squared; + nvtd->nearest_vertex_index = vd.index; + nvtd->nearest_vertex_distance_squared = distance_squared; } } BKE_pbvh_vertex_iter_end; +} - BLI_mutex_lock(&data->mutex); - if (data->nearest_vertex_index == -1) { - data->nearest_vertex_index = node_nearest_vertex_index; +static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + NearestVertexTLSData *join = chunk_join; + NearestVertexTLSData *nvtd = chunk; + if (join->nearest_vertex_index == -1) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } - else if (node_nearest_vertex_distance_squared < - len_squared_v3v3(data->nearest_vertex_search_co, - sculpt_vertex_co_get(ss, data->nearest_vertex_index))) { - data->nearest_vertex_index = node_nearest_vertex_index; + else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } - BLI_mutex_unlock(&data->mutex); } static int sculpt_nearest_vertex_get( @@ -422,19 +462,23 @@ static int sculpt_nearest_vertex_get( .ob = ob, .nodes = nodes, .max_distance_squared = max_distance * max_distance, - .nearest_vertex_index = -1, }; copy_v3_v3(task_data.nearest_vertex_search_co, co); + NearestVertexTLSData nvtd; + nvtd.nearest_vertex_index = -1; + nvtd.nearest_vertex_distance_squared = FLT_MAX; - BLI_mutex_init(&task_data.mutex); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); - BLI_mutex_end(&task_data.mutex); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + settings.func_reduce = nearest_vertex_get_reduce; + settings.userdata_chunk = &nvtd; + settings.userdata_chunk_size = sizeof(NearestVertexTLSData); + BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); - return task_data.nearest_vertex_index; + MEM_SAFE_FREE(nodes); + + return nvtd.nearest_vertex_index; } static bool is_symmetry_iteration_valid(char i, char symm) @@ -443,7 +487,7 @@ static bool is_symmetry_iteration_valid(char i, char symm) } /* Checks if a vertex is inside the brush radius from any of its mirrored axis */ -static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3], +static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3], const float br_co[3], float radius, char symm) @@ -460,6 +504,85 @@ static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3], return false; } +/* Sculpt Flood Fill API + * + * Iterate over connected vertices, starting from one or more initial vertices. */ + +typedef struct SculptFloodFill { + GSQueue *queue; + char *visited_vertices; +} SculptFloodFill; + +static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood) +{ + int vertex_count = sculpt_vertex_count_get(ss); + sculpt_vertex_random_access_init(ss); + + flood->queue = BLI_gsqueue_new(sizeof(int)); + flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); +} + +static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index) +{ + BLI_gsqueue_push(flood->queue, &index); +} + +static void sculpt_floodfill_add_active( + Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius) +{ + /* Add active vertex and symmetric vertices to the queue. */ + const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + for (char i = 0; i <= symm; ++i) { + if (is_symmetry_iteration_valid(i, symm)) { + int v = -1; + if (i == 0) { + v = sculpt_active_vertex_get(ss); + } + else if (radius > 0.0f) { + float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius; + float location[3]; + flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i); + v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false); + } + if (v != -1) { + sculpt_floodfill_add_initial(flood, v); + } + } + } +} + +static void sculpt_floodfill_execute( + SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), + void *userdata) +{ + while (!BLI_gsqueue_is_empty(flood->queue)) { + int from_v; + BLI_gsqueue_pop(flood->queue, &from_v); + SculptVertexNeighborIter ni; + sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni) + { + const int to_v = ni.index; + if (flood->visited_vertices[to_v] == 0) { + flood->visited_vertices[to_v] = 1; + + if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { + BLI_gsqueue_push(flood->queue, &to_v); + } + } + } + sculpt_vertex_neighbors_iter_end(ni); + } +} + +static void sculpt_floodfill_free(SculptFloodFill *flood) +{ + MEM_SAFE_FREE(flood->visited_vertices); + BLI_gsqueue_free(flood->queue); + flood->queue = NULL; +} + /** \name Tool Capabilities * * Avoid duplicate checks, internal logic only, @@ -814,15 +937,11 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && - totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); + BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); - if (nodes) { - MEM_freeN(nodes); - } + MEM_SAFE_FREE(nodes); } /*** BVH Tree ***/ @@ -1003,9 +1122,8 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca local_co[1] = fabsf(local_co[1]); local_co[2] = fabsf(local_co[2]); + const float p = 8.0f; if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) { - float p = 4.0f; - test->dist = ((powf(local_co[0], p) + powf(local_co[1], p) + powf(local_co[2], p)) / powf(side, p)); @@ -1100,11 +1218,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br) { - // REMOVE WITH PBVH_GRIDS - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return false; - } - if (sculpt_stroke_is_dynamic_topology(ss, br)) { return false; } @@ -1134,21 +1247,38 @@ static void sculpt_automasking_end(Object *ob) static bool sculpt_automasking_is_constrained_by_radius(Brush *br) { + /* 2D falloff is not constrained by radius */ + if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + return false; + } + if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) { return true; } return false; } -typedef struct VertexTopologyIterator { - int v; - int it; - float edge_factor; -} VertexTopologyIterator; +typedef struct AutomaskFloodFillData { + float *automask_factor; + float radius; + bool use_radius; + float location[3]; + char symm; +} AutomaskFloodFillData; -static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +static bool automask_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata) { + AutomaskFloodFillData *data = userdata; + data->automask_factor[to_v] = 1.0f; + return (!data->use_radius || + sculpt_is_vertex_inside_brush_radius_symm( + sculpt_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); +} + +static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +{ SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); @@ -1161,63 +1291,21 @@ static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *au return NULL; } - bool *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(bool), - "visited vertices"); - - BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator), - "not vertices stack"); - - VertexTopologyIterator mevit; - - /* Add active vertex and symmetric vertices to the stack. */ - float location[3]; - const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - for (char i = 0; i <= symm; ++i) { - if (is_symmetry_iteration_valid(i, symm)) { - flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i); - if (i == 0) { - mevit.v = sculpt_active_vertex_get(ss); - } - else { - mevit.v = sculpt_nearest_vertex_get( - sd, ob, location, ss->cache->radius * ss->cache->radius, false); - } - if (mevit.v != -1) { - mevit.it = 1; - BLI_stack_push(not_visited_vertices, &mevit); - } - } - } + /* Flood fill automask to connected vertices. Limited to vertices inside + * the brush radius if the tool requires it */ + SculptFloodFill flood; + sculpt_floodfill_init(ss, &flood); + sculpt_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius); - copy_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); - bool use_radius = sculpt_automasking_is_constrained_by_radius(brush); - - /* Flood fill automask to connected vertices. Limited to vertices inside the brush radius if the - * tool requires it */ - while (!BLI_stack_is_empty(not_visited_vertices)) { - VertexTopologyIterator c_mevit; - BLI_stack_pop(not_visited_vertices, &c_mevit); - SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni) - { - if (!visited_vertices[(int)ni.index]) { - VertexTopologyIterator new_entry; - new_entry.v = ni.index; - automask_factor[new_entry.v] = 1.0f; - visited_vertices[(int)ni.index] = true; - if (!use_radius || - sculpt_is_vertex_inside_brush_radius_symm( - sculpt_vertex_co_get(ss, new_entry.v), location, ss->cache->radius, symm)) { - BLI_stack_push(not_visited_vertices, &new_entry); - } - } - } - sculpt_vertex_neighbors_iter_end(ni); - } - - BLI_stack_free(not_visited_vertices); - - MEM_freeN(visited_vertices); + AutomaskFloodFillData fdata = { + .automask_factor = automask_factor, + .radius = ss->cache->radius, + .use_radius = sculpt_automasking_is_constrained_by_radius(brush), + .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL, + }; + copy_v3_v3(fdata.location, sculpt_active_vertex_co_get(ss)); + sculpt_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata); + sculpt_floodfill_free(&flood); return automask_factor; } @@ -1324,21 +1412,26 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \note These are all _very_ similar, when changing one, check others. * \{ */ +typedef struct AreaNormalCenterTLSData { + /* 0=towards view, 1=flipped */ + float area_cos[2][3]; + float area_nos[2][3]; + int area_count[2]; +} AreaNormalCenterTLSData; + static void calc_area_normal_and_center_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; - float(*area_nos)[3] = data->area_nos; - float(*area_cos)[3] = data->area_cos; + AreaNormalCenterTLSData *anctd = tls->userdata_chunk; + const bool use_area_nos = data->use_area_nos; + const bool use_area_cos = data->use_area_cos; PBVHVertexIter vd; SculptUndoNode *unode = NULL; - float private_co[2][3] = {{0.0f}}; - float private_no[2][3] = {{0.0f}}; - int private_count[2] = {0}; bool use_original = false; if (ss->cache && ss->cache->original) { @@ -1353,7 +1446,10 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, /* Update the test radius to sample the normal using the normal radius of the brush */ if (data->brush->ob_mode == OB_MODE_SCULPT) { float test_radius = sqrtf(test.radius_squared); - test_radius *= data->brush->normal_radius_factor; + /* Layer brush produces artifacts with normal radius */ + if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) { + test_radius *= data->brush->normal_radius_factor; + } test.radius_squared = test_radius * test_radius; } @@ -1384,13 +1480,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, normal_tri_v3(no, UNPACK3(co_tri)); flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f); - if (area_cos) { - add_v3_v3(private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } } @@ -1436,37 +1532,37 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <= 0.0f); - if (area_cos) { - add_v3_v3(private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } BKE_pbvh_vertex_iter_end; } +} - BLI_mutex_lock(&data->mutex); +static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + AreaNormalCenterTLSData *join = chunk_join; + AreaNormalCenterTLSData *anctd = chunk; /* for flatten center */ - if (area_cos) { - add_v3_v3(area_cos[0], private_co[0]); - add_v3_v3(area_cos[1], private_co[1]); - } + add_v3_v3(join->area_cos[0], anctd->area_cos[0]); + add_v3_v3(join->area_cos[1], anctd->area_cos[1]); /* for area normal */ - if (area_nos) { - add_v3_v3(area_nos[0], private_no[0]); - add_v3_v3(area_nos[1], private_no[1]); - } + add_v3_v3(join->area_nos[0], anctd->area_nos[0]); + add_v3_v3(join->area_nos[1], anctd->area_nos[1]); /* weights */ - data->count[0] += private_count[0]; - data->count[1] += private_count[1]; - - BLI_mutex_unlock(&data->mutex); + join->area_count[0] += anctd->area_count[0]; + join->area_count[1] += anctd->area_count[1]; } static void calc_area_center( @@ -1477,11 +1573,6 @@ static void calc_area_center( const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); int n; - /* 0=towards view, 1=flipped */ - float area_cos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1490,23 +1581,22 @@ static void calc_area_center( .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = area_cos, - .area_nos = NULL, - .count = count, + .use_area_cos = true, }; - BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + AreaNormalCenterTLSData anctd = {{{0}}}; - BLI_mutex_end(&data.mutex); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + settings.func_reduce = calc_area_normal_and_center_reduce; + settings.userdata_chunk = &anctd; + settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for flatten center */ - for (n = 0; n < ARRAY_SIZE(area_cos); n++) { - if (count[n] != 0) { - mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]); + for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { + if (anctd.area_count[n] != 0) { + mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]); break; } } @@ -1519,7 +1609,7 @@ static void calc_area_normal( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); - bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT; + bool use_threading = (sd->flags & SCULPT_USE_OPENMP); sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no); } @@ -1534,11 +1624,6 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush, SculptSession *ss = ob->sculpt; const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); - /* 0=towards view, 1=flipped */ - float area_nos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1547,23 +1632,22 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = NULL, - .area_nos = area_nos, - .count = count, + .use_area_nos = true, .any_vertex_sampled = false, }; - BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = use_threading; - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + AreaNormalCenterTLSData anctd = {{{0}}}; - BLI_mutex_end(&data.mutex); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode); + settings.func_reduce = calc_area_normal_and_center_reduce; + settings.userdata_chunk = &anctd; + settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for area normal */ - for (int i = 0; i < ARRAY_SIZE(area_nos); i++) { - if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) { + for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) { + if (normalize_v3_v3(r_area_no, anctd.area_nos[i]) != 0.0f) { break; } } @@ -1581,12 +1665,6 @@ static void calc_area_normal_and_center( const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush); int n; - /* 0=towards view, 1=flipped */ - float area_cos[2][3] = {{0.0f}}; - float area_nos[2][3] = {{0.0f}}; - - int count[2] = {0}; - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { .sd = NULL, @@ -1595,23 +1673,23 @@ static void calc_area_normal_and_center( .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, - .area_cos = area_cos, - .area_nos = area_nos, - .count = count, + .use_area_cos = true, + .use_area_nos = true, }; - BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + AreaNormalCenterTLSData anctd = {{{0}}}; - BLI_mutex_end(&data.mutex); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + settings.func_reduce = calc_area_normal_and_center_reduce; + settings.userdata_chunk = &anctd; + settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); + BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* for flatten center */ - for (n = 0; n < ARRAY_SIZE(area_cos); n++) { - if (count[n] != 0) { - mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]); + for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { + if (anctd.area_count[n] != 0) { + mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]); break; } } @@ -1620,8 +1698,8 @@ static void calc_area_normal_and_center( } /* for area normal */ - for (n = 0; n < ARRAY_SIZE(area_nos); n++) { - if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) { + for (n = 0; n < ARRAY_SIZE(anctd.area_nos); n++) { + if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) { break; } } @@ -1655,11 +1733,13 @@ static float brush_strength(const Sculpt *sd, switch (brush->sculpt_tool) { case SCULPT_TOOL_CLAY: - case SCULPT_TOOL_CLAY_STRIPS: case SCULPT_TOOL_DRAW: case SCULPT_TOOL_DRAW_SHARP: case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; + case SCULPT_TOOL_CLAY_STRIPS: + /* Clay Strips needs extra strength to compensate for its default normal radius */ + return alpha * flip * pressure * overlap * feather * 1.3f; case SCULPT_TOOL_MASK: overlap = (1 + overlap) / 2; @@ -1831,6 +1911,12 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v) float t[3], bb_min[3], bb_max[3]; int i; + if (data->ignore_fully_masked) { + if (BKE_pbvh_node_fully_masked_get(node)) { + return false; + } + } + if (data->original) { BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); } @@ -1861,6 +1947,12 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v) SculptSearchCircleData *data = data_v; float bb_min[3], bb_max[3]; + if (data->ignore_fully_masked) { + if (BKE_pbvh_node_fully_masked_get(node)) { + return false; + } + } + if (data->original) { BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); } @@ -1894,6 +1986,25 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float } } +static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob, + Sculpt *sd, + bool use_original, + int *r_totnode) +{ + SculptSession *ss = ob->sculpt; + PBVHNode **nodes = NULL; + SculptSearchSphereData data = { + .ss = ss, + .sd = sd, + .radius_squared = ss->cursor_radius, + .original = use_original, + .ignore_fully_masked = false, + .center = NULL, + }; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode); + return nodes; +} + static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, Sculpt *sd, const Brush *brush, @@ -1910,8 +2021,9 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, SculptSearchSphereData data = { .ss = ss, .sd = sd, - .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius, + .radius_squared = SQUARE(ss->cache->radius * radius_scale), .original = use_original, + .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK, .center = NULL, }; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode); @@ -1926,6 +2038,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius, .original = use_original, .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc, + .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK, }; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode); } @@ -1969,9 +2082,15 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, PBVHNode **nodes, int t { const Brush *brush = BKE_paint_brush(&sd->paint); StrokeCache *cache = ob->sculpt->cache; + /* Grab brush does not update the sculpt normal during a stroke */ + const bool update_normal = !(brush->flag & BRUSH_ORIGINAL_NORMAL) && + !(brush->sculpt_tool == SCULPT_TOOL_GRAB) && + !(brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) && + !(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + cache->normal_weight > 0.0f); if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 && - (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { + (cache->first_time || update_normal)) { calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal); if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal); @@ -2160,92 +2279,51 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v) copy_v3_v3(avg, v->co); } -/* For bmesh: average only the four most aligned (parallel and perpendicular) edges - * relative to a direction. Naturally converges to a quad-like tessellation. */ +/* For bmesh: Average surrounding verts based on an orthogonality measure. + * Naturally converges to a quad-like structure. */ static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v) { - /* Logic for 3 or more is identical. */ - const int vfcount = BM_vert_face_count_at_most(v, 3); - - /* Don't modify corner vertices. */ - if (vfcount < 2) { - copy_v3_v3(avg, v->co); - return; - } - - /* Project the direction to the vertex normal and create an additional - * parallel vector. */ - float dir_a[3], dir_b[3]; - cross_v3_v3v3(dir_a, direction, v->no); - cross_v3_v3v3(dir_b, dir_a, v->no); - - /* The four vectors which will be used for smoothing. - * Occasionally less than 4 verts match the requirements in that case - * use 'v' as fallback. */ - BMVert *pos_a = v; - BMVert *neg_a = v; - BMVert *pos_b = v; - BMVert *neg_b = v; - - float pos_score_a = 0.0f; - float neg_score_a = 0.0f; - float pos_score_b = 0.0f; - float neg_score_b = 0.0f; - - BMIter liter; - BMLoop *l; - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - BMVert *adj_v[2] = {l->prev->v, l->next->v}; - - for (int i = 0; i < ARRAY_SIZE(adj_v); i++) { - BMVert *v_other = adj_v[i]; - - if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) { - float vec[3]; - sub_v3_v3v3(vec, v_other->co, v->co); - normalize_v3(vec); + float avg_co[3] = {0, 0, 0}; + float tot_co = 0; - /* The score is a measure of how orthogonal the edge is. */ - float score = dot_v3v3(vec, dir_a); + BMIter eiter; + BMEdge *e; - if (score >= pos_score_a) { - pos_a = v_other; - pos_score_a = score; - } - else if (score < neg_score_a) { - neg_a = v_other; - neg_score_a = score; - } - /* The same scoring but for the perpendicular direction. */ - score = dot_v3v3(vec, dir_b); - - if (score >= pos_score_b) { - pos_b = v_other; - pos_score_b = score; - } - else if (score < neg_score_b) { - neg_b = v_other; - neg_score_b = score; - } - } + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(e)) { + copy_v3_v3(avg, v->co); + return; } + BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1; + float vec[3]; + sub_v3_v3v3(vec, v_other->co, v->co); + madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no)); + normalize_v3(vec); + + /* fac is a measure of how orthogonal or parallel the edge is + * relative to the direction */ + float fac = dot_v3v3(vec, direction); + fac = fac * fac - 0.5f; + fac *= fac; + madd_v3_v3fl(avg_co, v_other->co, fac); + tot_co += fac; } - /* Average everything together. */ - zero_v3(avg); - add_v3_v3(avg, pos_a->co); - add_v3_v3(avg, neg_a->co); - add_v3_v3(avg, pos_b->co); - add_v3_v3(avg, neg_b->co); - mul_v3_fl(avg, 0.25f); + /* In case vert has no Edge s */ + if (tot_co > 0) { + mul_v3_v3fl(avg, avg_co, 1.0f / tot_co); - /* Preserve volume. */ - float vec[3]; - sub_v3_v3(avg, v->co); - mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no)); - sub_v3_v3(avg, vec); - add_v3_v3(avg, v->co); + /* Preserve volume. */ + float vec[3]; + sub_v3_v3(avg, v->co); + mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no)); + sub_v3_v3(avg, vec); + add_v3_v3(avg, v->co); + } + else { + zero_v3(avg); + } } /* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */ @@ -2277,6 +2355,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse } } +static void grids_neighbor_average(SculptSession *ss, float result[3], int index) +{ + float avg[3] = {0.0f, 0.0f, 0.0f}; + int total = 0; + + SculptVertexNeighborIter ni; + sculpt_vertex_neighbors_iter_begin(ss, index, ni) + { + add_v3_v3(avg, sculpt_vertex_co_get(ss, ni.index)); + total++; + } + sculpt_vertex_neighbors_iter_end(ni); + + if (total > 0) { + mul_v3_v3fl(result, avg, 1.0f / (float)total); + } + else { + copy_v3_v3(result, sculpt_vertex_co_get(ss, index)); + } +} + +static float grids_neighbor_average_mask(SculptSession *ss, int index) +{ + float avg = 0.0f; + int total = 0; + + SculptVertexNeighborIter ni; + sculpt_vertex_neighbors_iter_begin(ss, index, ni) + { + avg += sculpt_vertex_mask_get(ss, ni.index); + total++; + } + sculpt_vertex_neighbors_iter_end(ni); + + if (total > 0) { + return avg / (float)total; + } + else { + return sculpt_vertex_mask_get(ss, index); + } +} + /* Note: uses after-struct allocated mem to store actual cache... */ typedef struct SculptDoBrushSmoothGridDataChunk { size_t tmpgrid_size; @@ -2442,6 +2562,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, mul_v3_v3fl( tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction)); sub_v3_v3(direction, tmp); + normalize_v3(direction); /* Cancel if there's no grab data. */ if (is_zero_v3(direction)) { @@ -2502,7 +2623,6 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, float bstrength = data->strength; CCGElem **griddata, *gddata; - CCGKey key; float(*tmpgrid_co)[3] = NULL; float tmprow_co[2][3]; @@ -2521,7 +2641,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, BKE_pbvh_node_get_grids( ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata); - BKE_pbvh_get_grid_key(ss->pbvh, &key); + CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh); grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh); @@ -2681,9 +2801,8 @@ static void smooth(Sculpt *sd, .strength = strength, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); switch (type) { case PBVH_GRIDS: { @@ -2700,16 +2819,16 @@ static void smooth(Sculpt *sd, settings.userdata_chunk = data_chunk; settings.userdata_chunk_size = size; - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); MEM_freeN(data_chunk); break; } case PBVH_FACES: - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); break; case PBVH_BMESH: - BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); break; } @@ -2741,11 +2860,10 @@ static void bmesh_topology_rake( .nodes = nodes, .strength = factor, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); } } @@ -2799,10 +2917,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2887,10 +3004,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); } static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, @@ -2964,10 +3080,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .offset = offset, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } /** @@ -3081,10 +3196,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .flippedbstrength = flippedbstrength, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); } static void do_pinch_brush_task_cb_ex(void *__restrict userdata, @@ -3144,10 +3258,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); } static void do_grab_brush_task_cb_ex(void *__restrict userdata, @@ -3217,10 +3330,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } /* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity @@ -3459,6 +3571,10 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + SculptThreadedTaskData data = { .sd = sd, .ob = ob, @@ -3467,10 +3583,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .grab_delta = grab_delta, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); } static void do_pose_brush_task_cb_ex(void *__restrict userdata, @@ -3522,10 +3637,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) float pose_initial_co[3]; float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4]; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return; - } - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); copy_v3_v3(pose_origin, ss->cache->pose_origin); @@ -3561,39 +3672,115 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .transform_trans_inv = transform_trans_inv, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } -static void pose_brush_init_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) +typedef struct PoseGrowFactorTLSData { + float pos_avg[3]; + int pos_count; +} PoseGrowFactorTLSData; + +static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; + PoseGrowFactorTLSData *gftd = tls->userdata_chunk; SculptSession *ss = data->ob->sculpt; + const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const float *active_co = sculpt_active_vertex_co_get(ss); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SculptVertexNeighborIter ni; - float avg = 0; - int total = 0; + float max = 0.0f; sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni) { - avg += ss->cache->pose_factor[ni.index]; - total++; + float vmask_f = data->prev_mask[ni.index]; + if (vmask_f > max) { + max = vmask_f; + } } sculpt_vertex_neighbors_iter_end(ni); - - if (total > 0) { - ss->cache->pose_factor[vd.index] = avg / (float)total; + if (max != data->prev_mask[vd.index]) { + data->pose_factor[vd.index] = max; + if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) { + add_v3_v3(gftd->pos_avg, vd.co); + gftd->pos_count++; + } } } + BKE_pbvh_vertex_iter_end; } -static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3], +static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + PoseGrowFactorTLSData *join = chunk_join; + PoseGrowFactorTLSData *gftd = chunk; + add_v3_v3(join->pos_avg, gftd->pos_avg); + join->pos_count += gftd->pos_count; +} + +/* Grow the factor until its boundary is near to the offset pose origin */ +static void sculpt_pose_grow_pose_factor( + Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor) +{ + PBVHNode **nodes; + PBVH *pbvh = ob->sculpt->pbvh; + int totnode; + + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = nodes, + .totnode = totnode, + .pose_factor = pose_factor, + }; + PBVHParallelSettings settings; + PoseGrowFactorTLSData gftd; + gftd.pos_count = 0; + zero_v3(gftd.pos_avg); + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + settings.func_reduce = pose_brush_grow_factor_reduce; + settings.userdata_chunk = &gftd; + settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData); + + bool grow_next_iteration = true; + float prev_len = FLT_MAX; + data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask"); + while (grow_next_iteration) { + zero_v3(gftd.pos_avg); + gftd.pos_count = 0; + memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float)); + BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); + if (gftd.pos_count != 0) { + mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count); + float len = len_v3v3(gftd.pos_avg, pose_origin); + if (len < prev_len) { + prev_len = len; + grow_next_iteration = true; + } + else { + grow_next_iteration = false; + memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float)); + } + } + else { + grow_next_iteration = false; + } + } + MEM_freeN(data.prev_mask); + + MEM_SAFE_FREE(nodes); +} + +static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3], const float br_co[3], float radius, char symm) @@ -3610,85 +3797,123 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3], return false; } -static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br) +/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush + * + * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't + * be calculated. */ +typedef struct PoseFloodFillData { + float pose_initial_co[3]; + float radius; + int symm; + + float *pose_factor; + float pose_origin[3]; + int tot_co; +} PoseFloodFillData; + +static bool pose_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { - sculpt_vertex_random_access_init(ss); + PoseFloodFillData *data = userdata; - ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor"); + if (data->pose_factor) { + data->pose_factor[to_v] = 1.0f; + } - copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location); + const float *co = sculpt_vertex_co_get(ss, to_v); + if (sculpt_pose_brush_is_vertex_inside_brush_radius( + co, data->pose_initial_co, data->radius, data->symm)) { + return true; + } + else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) { + if (!is_duplicate) { + add_v3_v3(data->pose_origin, co); + data->tot_co++; + } + } - char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char), - "Visited vertices"); - BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator), - "not visited vertices stack"); + return false; +} - float tot_co = 0; - zero_v3(ss->cache->pose_origin); +void sculpt_pose_calc_pose_data(Sculpt *sd, + Object *ob, + SculptSession *ss, + float initial_location[3], + float radius, + float pose_offset, + float *r_pose_origin, + float *r_pose_factor) +{ + sculpt_vertex_random_access_init(ss); - VertexTopologyIterator mevit; + /* Calculate the pose rotation point based on the boundaries of the brush factor. */ + SculptFloodFill flood; + sculpt_floodfill_init(ss, &flood); + sculpt_floodfill_add_active(sd, ob, ss, &flood, (r_pose_factor) ? radius : 0.0f); - /* Add active vertex and symmetric vertices to the stack. */ - const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - for (char i = 0; i <= symm; ++i) { - if (is_symmetry_iteration_valid(i, symm)) { - float location[3]; - flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i); - if (i == 0) { - mevit.v = sculpt_active_vertex_get(ss); - } - else { - mevit.v = sculpt_nearest_vertex_get( - sd, ob, location, ss->cache->radius * ss->cache->radius, false); - } - if (mevit.v != -1) { - mevit.it = 1; - BLI_stack_push(not_visited_vertices, &mevit); - } - } + PoseFloodFillData fdata = { + .radius = radius, + .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL, + .pose_factor = r_pose_factor, + .tot_co = 0, + }; + zero_v3(fdata.pose_origin); + copy_v3_v3(fdata.pose_initial_co, initial_location); + sculpt_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata); + sculpt_floodfill_free(&flood); + + if (fdata.tot_co > 0) { + mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co); } - /* Flood fill the internal pose brush factor. Calculate the pose rotation point based on the - * boundaries of the brush factor*/ - while (!BLI_stack_is_empty(not_visited_vertices)) { - VertexTopologyIterator c_mevit; - BLI_stack_pop(not_visited_vertices, &c_mevit); + /* Offset the pose origin */ + float pose_d[3]; + sub_v3_v3v3(pose_d, fdata.pose_origin, fdata.pose_initial_co); + normalize_v3(pose_d); + madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset); + copy_v3_v3(r_pose_origin, fdata.pose_origin); + + if (pose_offset != 0.0f && r_pose_factor) { + sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor); + } +} + +static void pose_brush_init_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni) + float avg = 0; + int total = 0; + sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni) { - if (visited_vertices[(int)ni.index] == 0) { - VertexTopologyIterator new_entry; - new_entry.v = ni.index; - new_entry.it = c_mevit.it + 1; - ss->cache->pose_factor[new_entry.v] = 1.0f; - visited_vertices[(int)ni.index] = 1; - if (sculpt_pose_brush_is_vertex_inside_brush_radius(sculpt_vertex_co_get(ss, new_entry.v), - ss->cache->pose_initial_co, - ss->cache->radius, - symm)) { - BLI_stack_push(not_visited_vertices, &new_entry); - } - else { - if (check_vertex_pivot_symmetry( - sculpt_vertex_co_get(ss, new_entry.v), ss->cache->pose_initial_co, symm)) { - tot_co++; - add_v3_v3(ss->cache->pose_origin, sculpt_vertex_co_get(ss, new_entry.v)); - } - } - } + avg += ss->cache->pose_factor[ni.index]; + total++; } sculpt_vertex_neighbors_iter_end(ni); - } - BLI_stack_free(not_visited_vertices); + if (total > 0) { + ss->cache->pose_factor[vd.index] = avg / (float)total; + } + } + BKE_pbvh_vertex_iter_end; +} - MEM_freeN(visited_vertices); +static void sculpt_pose_brush_init( + Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius) +{ + float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor"); - if (tot_co > 0) { - mul_v3_fl(ss->cache->pose_origin, 1.0f / (float)tot_co); - } + sculpt_pose_calc_pose_data( + sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor); - /* Smooth the pose brush factor for cleaner deformation */ + copy_v3_v3(ss->cache->pose_initial_co, initial_location); + ss->cache->pose_factor = pose_factor; PBVHNode **nodes; PBVH *pbvh = ob->sculpt->pbvh; @@ -3703,12 +3928,14 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br .nodes = nodes, }; + /* Smooth the pose brush factor for cleaner deformation */ for (int i = 0; i < 4; i++) { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } + + MEM_SAFE_FREE(nodes); } static void do_nudge_brush_task_cb_ex(void *__restrict userdata, @@ -3773,10 +4000,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); } static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, @@ -3895,10 +4121,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .grab_delta = grab_delta, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); } static void do_thumb_brush_task_cb_ex(void *__restrict userdata, @@ -3968,10 +4193,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); } static void do_rotate_brush_task_cb_ex(void *__restrict userdata, @@ -4042,10 +4266,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); } static void do_layer_brush_task_cb_ex(void *__restrict userdata, @@ -4140,10 +4363,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); BLI_mutex_end(&data.mutex); } @@ -4209,10 +4431,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } static void calc_sculpt_plane( @@ -4223,7 +4444,8 @@ static void calc_sculpt_plane( if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 && ss->cache->tile_pass == 0 && - (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { + (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) || + !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { switch (brush->sculpt_plane) { case SCULPT_DISP_DIR_VIEW: copy_v3_v3(r_area_no, ss->cache->true_view_normal); @@ -4260,10 +4482,20 @@ static void calc_sculpt_plane( } /* for area normal */ - copy_v3_v3(ss->cache->sculpt_normal, r_area_no); + if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + copy_v3_v3(r_area_no, ss->cache->sculpt_normal); + } + else { + copy_v3_v3(ss->cache->sculpt_normal, r_area_no); + } /* for flatten center */ - copy_v3_v3(ss->cache->last_center, r_area_co); + if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_PLANE)) { + copy_v3_v3(r_area_co, ss->cache->last_center); + } + else { + copy_v3_v3(ss->cache->last_center, r_area_co); + } } else { /* for area normal */ @@ -4408,10 +4640,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_co = area_co, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); } static void do_clay_brush_task_cb_ex(void *__restrict userdata, @@ -4507,10 +4738,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, @@ -4638,10 +4868,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .mat = mat, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); } static void do_fill_brush_task_cb_ex(void *__restrict userdata, @@ -4732,10 +4961,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); } static void do_scrape_brush_task_cb_ex(void *__restrict userdata, @@ -4825,10 +5053,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_co = area_co, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } static void do_gravity_task_cb_ex(void *__restrict userdata, @@ -4895,10 +5122,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); } void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) @@ -4999,7 +5225,7 @@ static void sculpt_topology_update(Sculpt *sd, (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE)); } - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); /* update average stroke position */ copy_v3_v3(location, ss->cache->true_location); @@ -5017,7 +5243,12 @@ static void do_brush_action_task_cb(void *__restrict userdata, data->nodes[n], data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); - BKE_pbvh_node_mark_update(data->nodes[n]); + if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) { + BKE_pbvh_node_mark_update_mask(data->nodes[n]); + } + else { + BKE_pbvh_node_mark_update(data->nodes[n]); + } } static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups) @@ -5030,18 +5261,27 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* These brushes need to update all nodes as they are not constrained by the brush radius */ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + } + else if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + float final_radius = ss->cache->radius * (1 + brush->pose_offset); SculptSearchSphereData data = { .ss = ss, .sd = sd, - .radius_squared = FLT_MAX, + .radius_squared = final_radius * final_radius, .original = true, }; - BKE_pbvh_search_gather(ss->pbvh, NULL, &data, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); } else { const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; - const float radius_scale = 1.0f; + float radius_scale = 1.0f; + /* With these options enabled not all required nodes are inside the original brush radius, so + * the brush can produce artifacts in some situations */ + if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) { + radius_scale = 2.0f; + } nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode); } @@ -5056,10 +5296,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); if (sculpt_brush_needs_normal(ss, brush)) { update_sculpt_normal(sd, ob, nodes, totnode); @@ -5077,9 +5316,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) { - if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) { - sculpt_pose_brush_init(sd, ob, ss, brush); - } + sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); } /* Apply one type of brush action */ @@ -5168,7 +5405,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe do_gravity(sd, ob, nodes, totnode, sd->gravity_factor); } - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); /* update average stroke position */ copy_v3_v3(location, ss->cache->true_location); @@ -5196,7 +5433,7 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) copy_v3_v3(ss->deform_cos[index], vd->co); copy_v3_v3(ss->orig_cos[index], newco); - if (!ss->kb) { + if (!ss->shapekey_active) { copy_v3_v3(me->mvert[index].co, newco); } } @@ -5252,7 +5489,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata, sculpt_clip(sd, ss, vd.co, val); - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { sculpt_flush_pbvhvert_deform(ob, &vd); } } @@ -5279,15 +5516,12 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } - if (nodes) { - MEM_freeN(nodes); - } + MEM_SAFE_FREE(nodes); } /* copy the modified vertices from bvh to the active key */ @@ -5306,7 +5540,7 @@ static void sculpt_update_keyblock(Object *ob) } if (vertCos) { - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); if (vertCos != ss->orig_cos) { MEM_freeN(vertCos); @@ -5352,7 +5586,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use PBVHNode **nodes; float(*vertCos)[3] = NULL; - if (ss->kb) { + if (ss->shapekey_active) { vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"); /* mesh could have isolated verts which wouldn't be in BVH, @@ -5372,24 +5606,23 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use .vertCos = vertCos, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings); if (vertCos) { - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); MEM_freeN(vertCos); } - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); /* Modifiers could depend on mesh normals, so we should update them/ * Note, then if sculpting happens on locked key, normals should be re-calculated * after applying coords from keyblock on base mesh */ BKE_mesh_calc_normals(me); } - else if (ss->kb) { + else if (ss->shapekey_active) { sculpt_update_keyblock(ob); } } @@ -5676,6 +5909,9 @@ void sculpt_cache_free(StrokeCache *cache) if (cache->dial) { MEM_freeN(cache->dial); } + if (cache->pose_factor) { + MEM_freeN(cache->pose_factor); + } MEM_freeN(cache); } @@ -5869,12 +6105,21 @@ static void sculpt_update_cache_invariants( /* Make copies of the mesh vertex locations and normals for some tools */ if (brush->flag & BRUSH_ANCHORED) { - cache->original = 1; + cache->original = true; + } + + /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it + * should work the opposite way. */ + if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { + cache->original = true; } if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) { if (!(brush->flag & BRUSH_ACCUMULATE)) { - cache->original = 1; + cache->original = true; + if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { + cache->original = false; + } } } @@ -5911,8 +6156,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru if (cache->first_time) { if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) { - copy_v3_v3(cache->orig_grab_location, - sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); + copy_v3_v3(cache->orig_grab_location, sculpt_active_vertex_co_get(ss)); } else { copy_v3_v3(cache->orig_grab_location, cache->true_location); @@ -6125,9 +6369,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po /* Returns true if any of the smoothing modes are active (currently * one of smooth brush, autosmooth, mask smooth, or shift-key * smooth) */ -static bool sculpt_needs_conectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode) +static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode) { - if (ss && sculpt_automasking_enabled(ss, brush)) { + if (ss && ss->pbvh && sculpt_automasking_enabled(ss, brush)) { return true; } return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) || @@ -6141,8 +6385,9 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B SculptSession *ss = ob->sculpt; View3D *v3d = CTX_wm_view3d(C); - bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0); - if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { + bool need_pmap = sculpt_needs_connectivity_info(brush, ss, 0); + if (ss->shapekey_active || ss->deform_modifiers_active || + (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false); } @@ -6272,6 +6517,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, const float mouse[2], bool use_sampled_normal) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); Sculpt *sd = scene->toolsettings->sculpt; Object *ob; @@ -6284,15 +6530,15 @@ bool sculpt_cursor_geometry_info_update(bContext *C, int totnode; bool original = false, hit = false; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ob = vc.obact; ss = ob->sculpt; if (!ss->pbvh) { - copy_v3_fl(out->location, 0.0f); - copy_v3_fl(out->normal, 0.0f); - copy_v3_fl(out->active_vertex_co, 0.0f); + zero_v3(out->location); + zero_v3(out->normal); + zero_v3(out->active_vertex_co); return false; } @@ -6314,16 +6560,16 @@ bool sculpt_cursor_geometry_info_update(bContext *C, /* Cursor is not over the mesh, return default values */ if (!srd.hit) { - copy_v3_fl(out->location, 0.0f); - copy_v3_fl(out->normal, 0.0f); - copy_v3_fl(out->active_vertex_co, 0.0f); + zero_v3(out->location); + zero_v3(out->normal); + zero_v3(out->active_vertex_co); return false; } /* Update the active vertex of the SculptSession */ ss->active_vertex_index = srd.active_vertex_index; + copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss)); - copy_v3_v3(out->active_vertex_co, sculpt_vertex_co_get(ss, srd.active_vertex_index)); copy_v3_v3(out->location, ray_normal); mul_v3_fl(out->location, srd.depth); add_v3_v3(out->location, ray_start); @@ -6335,7 +6581,6 @@ bool sculpt_cursor_geometry_info_update(bContext *C, } /* Sampled normal calculation */ - const float radius_scale = 1.0f; float radius; /* Update cursor data in SculptSession */ @@ -6357,11 +6602,11 @@ bool sculpt_cursor_geometry_info_update(bContext *C, } ss->cursor_radius = radius; - PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, original, radius_scale, &totnode); + PBVHNode **nodes = sculpt_pbvh_gather_cursor_update(ob, sd, original, &totnode); /* In case there are no nodes under the cursor, return the face normal */ if (!totnode) { - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); copy_v3_v3(out->normal, srd.face_normal); return true; } @@ -6374,7 +6619,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, /* Use face normal when there are no vertices to sample inside the cursor radius */ copy_v3_v3(out->normal, srd.face_normal); } - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); return true; } @@ -6384,6 +6629,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, */ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob; SculptSession *ss; StrokeCache *cache; @@ -6391,13 +6637,13 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) bool original; ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ob = vc.obact; ss = ob->sculpt; cache = ss->cache; - original = (cache) ? cache->original : 0; + original = (cache) ? cache->original : false; const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); @@ -6453,10 +6699,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) } } - if (cache && hit) { - copy_v3_v3(cache->true_location, out); - } - return hit; } @@ -6496,7 +6738,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op) view3d_operator_needs_opengl(C); sculpt_brush_init_tex(scene, sd, ss); - is_smooth = sculpt_needs_conectivity_info(brush, ss, mode); + is_smooth = sculpt_needs_connectivity_info(brush, ss, mode); BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask); } @@ -6526,7 +6768,7 @@ void sculpt_update_object_bounding_box(Object *ob) } } -static void sculpt_flush_update_step(bContext *C) +static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Object *ob = CTX_data_active_object(C); @@ -6534,6 +6776,12 @@ static void sculpt_flush_update_step(bContext *C) ARegion *ar = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires; View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + if (rv3d) { + /* Mark for faster 3D viewport redraws. */ + rv3d->rflag |= RV3D_PAINTING; + } if (mmd != NULL) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); @@ -6554,11 +6802,13 @@ static void sculpt_flush_update_step(bContext *C) * only the part of the 3D viewport where changes happened. */ rcti r; - BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB); - /* Update the object's bounding box too so that the object - * doesn't get incorrectly clipped during drawing in - * draw_mesh_object(). [#33790] */ - sculpt_update_object_bounding_box(ob); + if (update_flags & SCULPT_UPDATE_COORDS) { + BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB); + /* Update the object's bounding box too so that the object + * doesn't get incorrectly clipped during drawing in + * draw_mesh_object(). [#33790] */ + sculpt_update_object_bounding_box(ob); + } if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) { if (ss->cache) { @@ -6578,16 +6828,21 @@ static void sculpt_flush_update_step(bContext *C) } } -static void sculpt_flush_update_done(const bContext *C, Object *ob) +static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags) { /* After we are done drawing the stroke, check if we need to do a more * expensive depsgraph tag to update geometry. */ wmWindowManager *wm = CTX_wm_manager(C); View3D *current_v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); SculptSession *ss = ob->sculpt; Mesh *mesh = ob->data; bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */ + if (rv3d) { + rv3d->rflag &= ~RV3D_PAINTING; + } + for (wmWindow *win = wm->windows.first; win; win = win->next) { bScreen *screen = WM_window_get_active_screen(win); for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { @@ -6597,11 +6852,26 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob) if (v3d != current_v3d) { need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d); } + + /* Tag all 3D viewports for redraw now that we are done. Others + * viewports did not get a full redraw, and anti-aliasing for the + * current viewport was deactivated. */ + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + ED_region_tag_redraw(ar); + } + } } } } - BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB); + if (update_flags & SCULPT_UPDATE_COORDS) { + BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB); + } + + if (update_flags & SCULPT_UPDATE_MASK) { + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + } if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { BKE_pbvh_bmesh_after_stroke(ss->pbvh); @@ -6610,7 +6880,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob) /* optimization: if there is locked key and active modifiers present in */ /* the stack, keyblock is updating at each step. otherwise we could update */ /* keyblock only when stroke is finished */ - if (ss->kb && !ss->modifiers_active) { + if (ss->shapekey_active && !ss->deform_modifiers_active) { sculpt_update_keyblock(ob); } @@ -6703,17 +6973,22 @@ static void sculpt_stroke_update_step(bContext *C, * Same applies to the DEG_id_tag_update() invoked from * sculpt_flush_update_step(). */ - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool)); } - else if (ss->kb) { + else if (ss->shapekey_active) { sculpt_update_keyblock(ob); } ss->cache->first_time = false; /* Cleanup */ - sculpt_flush_update_step(C); + if (brush->sculpt_tool == SCULPT_TOOL_MASK) { + sculpt_flush_update_step(C, SCULPT_UPDATE_MASK); + } + else { + sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS); + } } static void sculpt_brush_exit_tex(Sculpt *sd) @@ -6766,7 +7041,12 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_undo_push_end(); - sculpt_flush_update_done(C, ob); + if (brush->sculpt_tool == SCULPT_TOOL_MASK) { + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + } + else { + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); + } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } @@ -6797,12 +7077,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) { - paint_stroke_data_free(op); + paint_stroke_free(C, op); return OPERATOR_PASS_THROUGH; } if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { - paint_stroke_data_free(op); + paint_stroke_free(C, op); return OPERATOR_FINISHED; } /* add modal handler */ @@ -6931,8 +7211,19 @@ void sculpt_pbvh_clear(Object *ob) /* Clear out any existing DM and PBVH */ if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); + ss->pbvh = NULL; + } + + if (ss->pmap) { + MEM_freeN(ss->pmap); + ss->pmap = NULL; } - ss->pbvh = NULL; + + if (ss->pmap_mem) { + MEM_freeN(ss->pmap_mem); + ss->pmap_mem = NULL; + } + BKE_object_free_derived_caches(ob); /* Tag to rebuild PBVH in depsgraph. */ @@ -7502,13 +7793,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen const int mode_flag = OB_MODE_SCULPT; Mesh *me = BKE_mesh_from_object(ob); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - if (mmd) { - multires_force_update(ob); - } + multires_flush_sculpt_updates(ob); /* Not needed for now. */ #if 0 + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); #endif @@ -7653,7 +7942,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) } } - MEM_freeN(nodes); + MEM_SAFE_FREE(nodes); sculpt_undo_push_end(); /* force rebuild of pbvh for better BB placement */ @@ -7694,8 +7983,9 @@ static void sample_detail(bContext *C, int mx, int my) CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); /* Pick sample detail. */ Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -7738,7 +8028,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op) static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e)) { ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail")); - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -7859,43 +8149,36 @@ static void filter_cache_init_task_cb(void *__restrict userdata, const TaskParallelTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; PBVHNode *node = data->nodes[i]; - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) - { - if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) { - data->node_mask[i] = 1; - } - } - BKE_pbvh_vertex_iter_end; - - if (data->node_mask[i] == 1) { - sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); - } + sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS); } static void sculpt_filter_cache_init(Object *ob, Sculpt *sd) { SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - int totnode; ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache"); ss->filter_cache->random_seed = rand(); + float center[3] = {0.0f}; SculptSearchSphereData search_data = { .original = true, - }; - BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode); + .center = center, + .radius_squared = FLT_MAX, + .ignore_fully_masked = true, - int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask"); + }; + BKE_pbvh_search_gather(pbvh, + sculpt_search_sphere_cb, + &search_data, + &ss->filter_cache->nodes, + &ss->filter_cache->totnode); - for (int i = 0; i < totnode; i++) { - BKE_pbvh_node_mark_normals_update(nodes[i]); + for (int i = 0; i < ss->filter_cache->totnode; i++) { + BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]); } /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing. @@ -7907,45 +8190,14 @@ static void sculpt_filter_cache_init(Object *ob, Sculpt *sd) SculptThreadedTaskData data = { .sd = sd, .ob = ob, - .nodes = nodes, - .node_mask = node_mask, + .nodes = ss->filter_cache->nodes, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings); - - int tot_active_nodes = 0; - int active_node_index = 0; - PBVHNode **active_nodes; - - /* Count number of PBVH nodes that are not fully masked */ - for (int i = 0; i < totnode; i++) { - if (node_mask[i] == 1) { - tot_active_nodes++; - } - } - - /* Create the final list of nodes that is going to be processed in the filter */ - active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes"); - - for (int i = 0; i < totnode; i++) { - if (node_mask[i] == 1) { - active_nodes[active_node_index] = nodes[i]; - active_node_index++; - } - } - - ss->filter_cache->nodes = active_nodes; - ss->filter_cache->totnode = tot_active_nodes; - - if (nodes) { - MEM_freeN(nodes); - } - if (node_mask) { - MEM_freeN(node_mask); - } + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range( + 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); } static void sculpt_filter_cache_free(SculptSession *ss) @@ -8017,15 +8269,25 @@ static void mesh_filter_task_cb(void *__restrict userdata, float fade = vd.mask ? *vd.mask : 0.0f; fade = 1 - fade; fade *= data->filter_strength; + + if (fade == 0.0f) { + continue; + } + copy_v3_v3(orig_co, orig_data.co); switch (filter_type) { case MESH_FILTER_SMOOTH: CLAMP(fade, -1.0f, 1.0f); - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - neighbor_average(ss, avg, vd.index); - } - else if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { - bmesh_neighbor_average(avg, vd.bm_vert); + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + neighbor_average(ss, avg, vd.index); + break; + case PBVH_BMESH: + bmesh_neighbor_average(avg, vd.bm_vert); + break; + case PBVH_GRIDS: + grids_neighbor_average(ss, avg, vd.index); + break; } sub_v3_v3v3(val, avg, orig_co); madd_v3_v3v3fl(val, orig_co, val, fade); @@ -8064,11 +8326,16 @@ static void mesh_filter_task_cb(void *__restrict userdata, mid_v3_v3v3(disp, disp, disp2); break; - case MESH_FILTER_RANDOM: + case MESH_FILTER_RANDOM: { normal_short_to_float_v3(normal, orig_data.no); - mul_v3_fl(normal, BLI_hash_int_01(vd.index ^ ss->filter_cache->random_seed) - 0.5f); + /* Index is not unique for multires, so hash by vertex coordinates. */ + const uint *hash_co = (const uint *)orig_co; + const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^ + BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed); + mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f); mul_v3_v3fl(disp, normal, fade); break; + } } for (int it = 0; it < 3; it++) { @@ -8079,8 +8346,9 @@ static void mesh_filter_task_cb(void *__restrict userdata, add_v3_v3v3(final_pos, orig_co, disp); copy_v3_v3(vd.co, final_pos); - if (vd.mvert) + if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } BKE_pbvh_vertex_iter_end; @@ -8100,7 +8368,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { sculpt_filter_cache_free(ss); sculpt_undo_push_end(); - sculpt_flush_update_done(C, ob); + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); return OPERATOR_FINISHED; } @@ -8124,17 +8392,16 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * .filter_strength = filter_strength, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - ss->filter_cache->totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); - if (ss->modifiers_active || ss->kb) { + if (ss->deform_modifiers_active || ss->shapekey_active) { sculpt_flush_stroke_deform(sd, ob, true); } - sculpt_flush_update_step(C); + sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS); return OPERATOR_RUNNING_MODAL; } @@ -8148,10 +8415,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - int deform_axis = RNA_enum_get(op->ptr, "deform_axis"); if (deform_axis == 0) { return OPERATOR_CANCELLED; @@ -8260,35 +8523,42 @@ static void mask_filter_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - float val; float delta, gain, offset, max, min; float prev_val = *vd.mask; SculptVertexNeighborIter ni; switch (mode) { case MASK_FILTER_SMOOTH: - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - val = neighbor_average_mask(ss, vd.index) - *vd.mask; + case MASK_FILTER_SHARPEN: { + float val = 0.0f; + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + val = neighbor_average_mask(ss, vd.index); + break; + case PBVH_BMESH: + val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset); + break; + case PBVH_GRIDS: + val = grids_neighbor_average_mask(ss, vd.index); + break; } - else { - val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask; - } - *vd.mask += val; - break; - case MASK_FILTER_SHARPEN: - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - val = neighbor_average_mask(ss, vd.index) - *vd.mask; - } - else { - val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask; - } - if (*vd.mask > 0.5f) { - *vd.mask += 0.05f; + + val -= *vd.mask; + + if (mode == MASK_FILTER_SMOOTH) { + *vd.mask += val; } - else { - *vd.mask -= 0.05f; + else if (mode == MASK_FILTER_SHARPEN) { + if (*vd.mask > 0.5f) { + *vd.mask += 0.05f; + } + else { + *vd.mask -= 0.05f; + } + *vd.mask += val / 2; } - *vd.mask += val / 2; break; + } case MASK_FILTER_GROW: max = 0.0f; sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni) @@ -8339,7 +8609,7 @@ static void mask_filter_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; if (update) { - BKE_pbvh_node_mark_redraw(node); + BKE_pbvh_node_mark_update_mask(node); } } @@ -8355,10 +8625,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int totnode; int filter_type = RNA_enum_get(op->ptr, "filter_type"); - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); sculpt_vertex_random_access_init(ss); @@ -8380,16 +8646,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) int iterations = RNA_int_get(op->ptr, "iterations"); /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to - * avoid adding an unnecesary ammount of undo steps when using the operator from a shortcut. One - * iteration per 50000 vertices in the mesh should be fine in most cases. Maybe we want this to - * be configurable */ + * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut. + * One iteration per 50000 vertices in the mesh should be fine in most cases. + * Maybe we want this to be configurable. */ if (RNA_boolean_get(op->ptr, "auto_iteration_count")) { iterations = (int)(num_verts / 50000.0f) + 1; } for (int i = 0; i < iterations; i++) { if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { - prev_mask = MEM_mallocN((unsigned long)num_verts * sizeof(float), "prevmask"); + prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask"); for (int j = 0; j < num_verts; j++) { prev_mask[j] = sculpt_vertex_mask_get(ss, j); } @@ -8403,19 +8669,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) .prev_mask = prev_mask, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { MEM_freeN(prev_mask); } } - if (nodes) { - MEM_freeN(nodes); - } + MEM_SAFE_FREE(nodes); sculpt_undo_push_end(); @@ -8461,17 +8724,17 @@ static void SCULPT_OT_mask_filter(struct wmOperatorType *ot) "Use a automatic number of iterations based on the number of vertices of the sculpt"); } -static float neighbor_dirty_mask(SculptSession *ss, const int vert) +static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd) { int total = 0; float avg[3]; zero_v3(avg); SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, vert, ni) + sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni) { float normalized[3]; - sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), sculpt_vertex_co_get(ss, vert)); + sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), vd->co); normalize_v3(normalized); add_v3_v3(avg, normalized); total++; @@ -8481,7 +8744,12 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert) if (total > 0) { mul_v3_fl(avg, 1.0f / total); float normal[3]; - sculpt_vertex_normal_get(ss, vert, normal); + if (vd->no) { + normal_short_to_float_v3(normal, vd->no); + } + else { + copy_v3_v3(normal, vd->fno); + } float dot = dot_v3v3(avg, normal); float angle = max_ff(saacosf(dot), 0.0f); return angle; @@ -8489,25 +8757,75 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert) return 0; } -static void dirty_mask_task_cb(void *__restrict userdata, - const int i, - const TaskParallelTLS *__restrict UNUSED(tls)) +typedef struct DirtyMaskRangeData { + float min, max; +} DirtyMaskRangeData; + +static void dirty_mask_compute_range_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + DirtyMaskRangeData *range = tls->userdata_chunk; + PBVHVertexIter vd; + + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + float dirty_mask = neighbor_dirty_mask(ss, &vd); + range->min = min_ff(dirty_mask, range->min); + range->max = max_ff(dirty_mask, range->max); + } + BKE_pbvh_vertex_iter_end; +} + +static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + DirtyMaskRangeData *join = chunk_join; + DirtyMaskRangeData *range = chunk; + join->min = min_ff(range->min, join->min); + join->max = max_ff(range->max, join->max); +} + +static void dirty_mask_apply_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; PBVHNode *node = data->nodes[i]; PBVHVertexIter vd; + + const bool dirty_only = data->dirty_mask_dirty_only; + const float min = data->dirty_mask_min; + const float max = data->dirty_mask_max; + + float range = max - min; + if (range < 0.0001f) { + range = 0; + } + else { + range = 1.0f / range; + } + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - float val; - val = neighbor_dirty_mask(ss, vd.index); - data->prev_mask[vd.index] = val; + float dirty_mask = neighbor_dirty_mask(ss, &vd); + float mask = *vd.mask + (1 - ((dirty_mask - min) * range)); + if (dirty_only) { + mask = fminf(mask, 0.5f) * 2.0f; + } + *vd.mask = CLAMPIS(mask, 0.0f, 1.0f); + if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } BKE_pbvh_vertex_iter_end; - BKE_pbvh_node_mark_redraw(node); + BKE_pbvh_node_mark_update_mask(node); } static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) @@ -8521,10 +8839,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; int totnode; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); sculpt_vertex_random_access_init(ss); @@ -8533,8 +8847,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - int num_verts = sculpt_vertex_count_get(ss); - BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); sculpt_undo_push_begin("Dirty Mask"); @@ -8542,59 +8854,32 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); } - float *prev_mask = NULL; - - prev_mask = MEM_mallocN((unsigned long)num_verts * sizeof(float), "prevmask"); - for (int j = 0; j < num_verts; j++) { - prev_mask[j] = sculpt_vertex_mask_get(ss, j); - } - SculptThreadedTaskData data = { .sd = sd, .ob = ob, .nodes = nodes, - .prev_mask = prev_mask, + .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"), + }; + DirtyMaskRangeData range = { + .min = FLT_MAX, + .max = -FLT_MAX, }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, totnode, &data, dirty_mask_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - float min = FLT_MAX; - float max = FLT_MIN; - for (int i = 0; i < num_verts; i++) { - float val = prev_mask[i]; - if (val < min) { - min = val; - } - if (val > max) { - max = val; - } - } + settings.func_reduce = dirty_mask_compute_range_reduce; + settings.userdata_chunk = ⦥ + settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - float range = max - min; - if (range < 0.0001f) { - range = 0; - } - else { - range = 1.0f / range; - } + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); + data.dirty_mask_min = range.min; + data.dirty_mask_max = range.max; + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); - bool dirty_only = RNA_boolean_get(op->ptr, "dirty_only"); - for (int i = 0; i < num_verts; i++) { - sculpt_vertex_mask_set( - ss, i, sculpt_vertex_mask_get(ss, i) + (1 - ((prev_mask[i] - min) * range))); - if (dirty_only) { - sculpt_vertex_mask_set(ss, i, fminf(sculpt_vertex_mask_get(ss, i), 0.5f) * 2.0f); - } - sculpt_vertex_mask_clamp(ss, i, 0.0f, 1.0f); - } - MEM_freeN(prev_mask); + MEM_SAFE_FREE(nodes); - if (nodes) { - MEM_freeN(nodes); - } + BKE_pbvh_update_vertex_data(pbvh, SCULPT_UPDATE_MASK); sculpt_undo_push_end(); @@ -8630,19 +8915,22 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op) MEM_freeN(op->customdata); - int vert_count = sculpt_vertex_count_get(ss); - for (int i = 0; i < vert_count; i++) { - sculpt_vertex_mask_set(ss, i, ss->filter_cache->prev_mask[i]); - } + for (int n = 0; n < ss->filter_cache->totnode; n++) { + PBVHNode *node = ss->filter_cache->nodes[n]; + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + *vd.mask = ss->filter_cache->prev_mask[vd.index]; + } + BKE_pbvh_vertex_iter_end; - for (int i = 0; i < ss->filter_cache->totnode; i++) { - BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]); + BKE_pbvh_node_mark_redraw(node); } - sculpt_flush_update_step(C); + sculpt_flush_update_step(C, SCULPT_UPDATE_MASK); sculpt_filter_cache_free(ss); sculpt_undo_push_end(); - sculpt_flush_update_done(C, ob); + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK); ED_workspace_status_text(C, NULL); } @@ -8692,7 +8980,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata, vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } *vd.mask = final_mask; - BKE_pbvh_node_mark_redraw(node); + BKE_pbvh_node_mark_update_mask(node); } } BKE_pbvh_vertex_iter_end; @@ -8724,8 +9012,11 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * if ((event->type == ESCKEY && event->val == KM_PRESS) || (event->type == RIGHTMOUSE && event->val == KM_PRESS)) { + /* Returning OPERATOR_CANCELLED will leak memory due to not finishing + * undo. Better solution could be to make paint_mesh_restore_co work + * for this case. */ sculpt_mask_expand_cancel(C, op); - return OPERATOR_CANCELLED; + return OPERATOR_FINISHED; } if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) || @@ -8743,30 +9034,36 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations"); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); for (int i = 0; i < smooth_iterations; i++) { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - ss->filter_cache->totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); } /* Pivot position */ if (RNA_boolean_get(op->ptr, "update_pivot")) { const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + const float threshold = 0.2f; float avg[3]; int total = 0; - float threshold = 0.2f; zero_v3(avg); - int vertex_count = sculpt_vertex_count_get(ss); - for (int i = 0; i < vertex_count; i++) { - if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) && - sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) && - check_vertex_pivot_symmetry( - sculpt_vertex_co_get(ss, i), ss->filter_cache->mask_expand_initial_co, symm)) { - total++; - add_v3_v3(avg, sculpt_vertex_co_get(ss, i)); + + for (int n = 0; n < ss->filter_cache->totnode; n++) { + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE) + { + const float mask = (vd.mask) ? *vd.mask : 0.0f; + if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) { + if (check_vertex_pivot_symmetry( + vd.co, ss->filter_cache->mask_expand_initial_co, symm)) { + add_v3_v3(avg, vd.co); + total++; + } + } } + BKE_pbvh_vertex_iter_end; } + if (total > 0) { mul_v3_fl(avg, 1.0f / total); copy_v3_v3(ss->pivot_pos, avg); @@ -8783,7 +9080,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * sculpt_filter_cache_free(ss); sculpt_undo_push_end(); - sculpt_flush_update_done(C, ob); + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK); ED_workspace_status_text(C, NULL); return OPERATOR_FINISHED; } @@ -8806,20 +9103,60 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"), .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - ss->filter_cache->totnode > SCULPT_THREADED_LIMIT); - - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); ss->filter_cache->mask_update_current_it = mask_expand_update_it; } - sculpt_flush_update_step(C); + sculpt_flush_update_step(C, SCULPT_UPDATE_MASK); return OPERATOR_RUNNING_MODAL; } +typedef struct MaskExpandFloodFillData { + float original_normal[3]; + float edge_sensitivity; + bool use_normals; +} MaskExpandFloodFillData; + +static bool mask_expand_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) +{ + MaskExpandFloodFillData *data = userdata; + + if (!is_duplicate) { + int to_it = ss->filter_cache->mask_update_it[from_v] + 1; + ss->filter_cache->mask_update_it[to_v] = to_it; + if (to_it > ss->filter_cache->mask_update_last_it) { + ss->filter_cache->mask_update_last_it = to_it; + } + + if (data->use_normals) { + float current_normal[3], prev_normal[3]; + sculpt_vertex_normal_get(ss, to_v, current_normal); + sculpt_vertex_normal_get(ss, from_v, prev_normal); + const float from_edge_factor = ss->filter_cache->edge_factor[from_v]; + ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) * + from_edge_factor; + ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f); + } + } + else { + /* PBVH_GRIDS duplicate handling */ + ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v]; + if (data->use_normals) { + ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v]; + ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v]; + } + } + + return true; +} + static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); @@ -8827,20 +9164,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; PBVH *pbvh = ob->sculpt->pbvh; - float original_normal[3]; bool use_normals = RNA_boolean_get(op->ptr, "use_normals"); - int edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"); SculptCursorGeometryInfo sgi; float mouse[2]; mouse[0] = event->mval[0]; mouse[1] = event->mval[1]; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - sculpt_vertex_random_access_init(ss); op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position"); @@ -8854,16 +9185,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache"); - SculptSearchSphereData searchdata = { - .ss = ss, - .sd = sd, - .radius_squared = FLT_MAX, - }; - BKE_pbvh_search_gather(pbvh, - sculpt_search_sphere_cb, - &searchdata, - &ss->filter_cache->nodes, - &ss->filter_cache->totnode); + BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode); sculpt_undo_push_begin("Mask Expand"); @@ -8877,6 +9199,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (use_normals) { ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count, "mask update normal factor"); + ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count, + "mask update normal factor"); + for (int i = 0; i < vertex_count; i++) { + ss->filter_cache->edge_factor[i] = 1.0f; + } } ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask"); @@ -8886,68 +9213,21 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->mask_update_last_it = 1; ss->filter_cache->mask_update_current_it = 1; - ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)] = 1; - - copy_v3_v3(ss->filter_cache->mask_expand_initial_co, - sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); - - char *visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices"); + ss->filter_cache->mask_update_it[sculpt_active_vertex_get(ss)] = 1; - sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), original_normal); + copy_v3_v3(ss->filter_cache->mask_expand_initial_co, sculpt_active_vertex_co_get(ss)); - GSQueue *queue = BLI_gsqueue_new(sizeof(VertexTopologyIterator)); - VertexTopologyIterator mevit; + SculptFloodFill flood; + sculpt_floodfill_init(ss, &flood); + sculpt_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX); - const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - for (char i = 0; i <= symm; ++i) { - if (is_symmetry_iteration_valid(i, symm)) { - float location[3]; - flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i); - if (i == 0) { - mevit.v = sculpt_active_vertex_get(ss); - mevit.edge_factor = 1.0f; - } - else { - mevit.v = sculpt_nearest_vertex_get(sd, ob, location, FLT_MAX, false); - mevit.edge_factor = 1.0f; - } - if (mevit.v != -1) { - sculpt_vertex_mask_set(ss, mevit.v, 1.0f); - mevit.it = 0; - BLI_gsqueue_push(queue, &mevit); - } - } - } - - while (!BLI_gsqueue_is_empty(queue)) { - VertexTopologyIterator c_mevit; - BLI_gsqueue_pop(queue, &c_mevit); - SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni) - { - if (visited_vertices[(int)ni.index] == 0) { - VertexTopologyIterator new_entry; - new_entry.v = ni.index; - new_entry.it = c_mevit.it + 1; - ss->filter_cache->mask_update_it[(int)new_entry.v] = new_entry.it; - visited_vertices[(int)ni.index] = 1; - if (ss->filter_cache->mask_update_last_it < new_entry.it) { - ss->filter_cache->mask_update_last_it = new_entry.it; - } - if (use_normals) { - float current_normal[3], prev_normal[3]; - sculpt_vertex_normal_get(ss, ni.index, current_normal); - sculpt_vertex_normal_get(ss, c_mevit.v, prev_normal); - new_entry.edge_factor = dot_v3v3(current_normal, prev_normal) * c_mevit.edge_factor; - ss->filter_cache->normal_factor[ni.index] = dot_v3v3(original_normal, current_normal) * - powf(c_mevit.edge_factor, edge_sensitivity); - CLAMP(ss->filter_cache->normal_factor[ni.index], 0, 1); - } - BLI_gsqueue_push(queue, &new_entry); - } - } - sculpt_vertex_neighbors_iter_end(ni); - } + MaskExpandFloodFillData fdata = { + .use_normals = use_normals, + .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"), + }; + sculpt_active_vertex_normal_get(ss, fdata.original_normal); + sculpt_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata); + sculpt_floodfill_free(&flood); if (use_normals) { for (int repeat = 0; repeat < 2; repeat++) { @@ -8962,11 +9242,9 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->normal_factor[i] = avg / ni.size; } } - } - - BLI_gsqueue_free(queue); - MEM_freeN(visited_vertices); + MEM_SAFE_FREE(ss->filter_cache->edge_factor); + } SculptThreadedTaskData data = { .sd = sd, @@ -8977,19 +9255,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"), .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - ss->filter_cache->totnode > SCULPT_THREADED_LIMIT); - - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); const char *status_str = TIP_( "Move the mouse to expand the mask from the active vertex. LBM: confirm mask, ESC/RMB: " "cancel"); ED_workspace_status_text(C, status_str); - sculpt_flush_update_step(C); + sculpt_flush_update_step(C, SCULPT_UPDATE_MASK); WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -9061,46 +9337,47 @@ void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float } float brush_co[3]; - copy_v3_v3(brush_co, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); + copy_v3_v3(brush_co, sculpt_active_vertex_co_get(ss)); char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char), "visited vertices"); + /* Assuming an average of 6 edges per vertex in a triangulated mesh */ + const int max_preview_vertices = sculpt_vertex_count_get(ss) * 3 * 2; + if (ss->preview_vert_index_list == NULL) { - ss->preview_vert_index_list = MEM_callocN(4 * sizeof(int) * sculpt_vertex_count_get(ss), - "preview lines"); + ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); } - BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator), - "Not visited vertices stack"); - VertexTopologyIterator mevit; - mevit.v = sculpt_active_vertex_get(ss); - BLI_stack_push(not_visited_vertices, &mevit); + GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); + int active_v = sculpt_active_vertex_get(ss); + BLI_gsqueue_push(not_visited_vertices, &active_v); - while (!BLI_stack_is_empty(not_visited_vertices)) { - VertexTopologyIterator c_mevit; - BLI_stack_pop(not_visited_vertices, &c_mevit); + while (!BLI_gsqueue_is_empty(not_visited_vertices)) { + int from_v; + BLI_gsqueue_pop(not_visited_vertices, &from_v); SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni) + sculpt_vertex_neighbors_iter_begin(ss, from_v, ni) { - VertexTopologyIterator new_entry; - new_entry.v = ni.index; - new_entry.it = c_mevit.it + 1; - ss->preview_vert_index_list[totpoints] = c_mevit.v; - totpoints++; - ss->preview_vert_index_list[totpoints] = new_entry.v; - totpoints++; - if (visited_vertices[(int)ni.index] == 0) { - visited_vertices[(int)ni.index] = 1; - if (len_squared_v3v3(brush_co, sculpt_vertex_co_get(ss, new_entry.v)) < radius * radius) { - BLI_stack_push(not_visited_vertices, &new_entry); + if (totpoints + (ni.size * 2) < max_preview_vertices) { + int to_v = ni.index; + ss->preview_vert_index_list[totpoints] = from_v; + totpoints++; + ss->preview_vert_index_list[totpoints] = to_v; + totpoints++; + if (visited_vertices[to_v] == 0) { + visited_vertices[to_v] = 1; + const float *co = sculpt_vertex_co_get(ss, to_v); + if (len_squared_v3v3(brush_co, co) < radius * radius) { + BLI_gsqueue_push(not_visited_vertices, &to_v); + } } } } sculpt_vertex_neighbors_iter_end(ni); } - BLI_stack_free(not_visited_vertices); + BLI_gsqueue_free(not_visited_vertices); MEM_freeN(visited_vertices); @@ -9234,8 +9511,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata, } BKE_pbvh_vertex_iter_end; - BKE_pbvh_node_mark_redraw(node); - BKE_pbvh_node_mark_normals_update(node); + BKE_pbvh_node_mark_update(node); } void ED_sculpt_update_modal_transform(struct bContext *C) @@ -9295,18 +9571,17 @@ void ED_sculpt_update_modal_transform(struct bContext *C) mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]); } - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && - ss->filter_cache->totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range( + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings( + &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); + BKE_pbvh_parallel_range( 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); - if (ss->modifiers_active || ss->kb) { + if (ss->deform_modifiers_active || ss->shapekey_active) { sculpt_flush_stroke_deform(sd, ob, true); } - sculpt_flush_update_step(C); + sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS); } void ED_sculpt_end_transform(struct bContext *C) @@ -9317,7 +9592,7 @@ void ED_sculpt_end_transform(struct bContext *C) sculpt_filter_cache_free(ss); } sculpt_undo_push_end(); - sculpt_flush_update_done(C, ob); + sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); } typedef enum eSculptPivotPositionModes { @@ -9366,73 +9641,80 @@ static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const w Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return OPERATOR_CANCELLED; - } - int mode = RNA_enum_get(op->ptr, "mode"); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true); - int vert_count = sculpt_vertex_count_get(ss); - /* Pivot to center */ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) { zero_v3(ss->pivot_pos); } + /* Pivot to active vertex */ + else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) { + copy_v3_v3(ss->pivot_pos, sculpt_active_vertex_co_get(ss)); + } + /* Pivot to raycast surface */ + else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) { + float stroke_location[3]; + float mouse[2]; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + if (sculpt_stroke_get_location(C, stroke_location, mouse)) { + copy_v3_v3(ss->pivot_pos, stroke_location); + } + } + else { + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - /* Pivot to unmasked */ - if (mode == SCULPT_PIVOT_POSITION_UNMASKED) { float avg[3]; int total = 0; zero_v3(avg); - for (int i = 0; i < vert_count; i++) { - if (sculpt_vertex_mask_get(ss, i) < 1.0f && - check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) { - total++; - add_v3_v3(avg, sculpt_vertex_co_get(ss, i)); + + /* Pivot to unmasked */ + if (mode == SCULPT_PIVOT_POSITION_UNMASKED) { + for (int n = 0; n < totnode; n++) { + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + { + const float mask = (vd.mask) ? *vd.mask : 0.0f; + if (mask < 1.0f) { + if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) { + add_v3_v3(avg, vd.co); + total++; + } + } + } + BKE_pbvh_vertex_iter_end; } } - if (total > 0) { - mul_v3_fl(avg, 1.0f / total); - copy_v3_v3(ss->pivot_pos, avg); - } - } + /* Pivot to mask border */ + else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) { + const float threshold = 0.2f; - /* Pivot to mask border */ - if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) { - float avg[3]; - int total = 0; - float threshold = 0.2f; - zero_v3(avg); - for (int i = 0; i < vert_count; i++) { - if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) && - sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) && - check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) { - total++; - add_v3_v3(avg, sculpt_vertex_co_get(ss, i)); + for (int n = 0; n < totnode; n++) { + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + { + const float mask = (vd.mask) ? *vd.mask : 0.0f; + if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) { + if (check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) { + add_v3_v3(avg, vd.co); + total++; + } + } + } + BKE_pbvh_vertex_iter_end; } } + if (total > 0) { mul_v3_fl(avg, 1.0f / total); copy_v3_v3(ss->pivot_pos, avg); } - } - /* Pivot to active vertex */ - if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) { - copy_v3_v3(ss->pivot_pos, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); - } - - /* Pivot to raycast surface */ - if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) { - float stroke_location[3]; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - if (sculpt_stroke_get_location(C, stroke_location, mouse)) { - copy_v3_v3(ss->pivot_pos, stroke_location); - } + MEM_SAFE_FREE(nodes); } ED_region_tag_redraw(ar); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index b814e87fcb0..93e4a777569 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -44,6 +44,13 @@ bool sculpt_mode_poll_view3d(struct bContext *C); bool sculpt_poll(struct bContext *C); bool sculpt_poll_view3d(struct bContext *C); +/* Updates */ + +typedef enum SculptUpdateType { + SCULPT_UPDATE_COORDS = 1 << 0, + SCULPT_UPDATE_MASK = 1 << 1, +} SculptUpdateType; + /* Stroke */ typedef struct SculptCursorGeometryInfo { @@ -58,9 +65,17 @@ bool sculpt_cursor_geometry_info_update(bContext *C, const float mouse[2], bool use_sampled_normal); void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius); +void sculpt_pose_calc_pose_data(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + float initial_location[3], + float radius, + float pose_offset, + float *r_pose_origin, + float *r_pose_factor); /* Sculpt PBVH abstraction API */ -float *sculpt_vertex_co_get(struct SculptSession *ss, int index); +const float *sculpt_vertex_co_get(struct SculptSession *ss, int index); /* Dynamic topology */ void sculpt_pbvh_clear(Object *ob); @@ -179,23 +194,20 @@ typedef struct SculptThreadedTaskData { int filter_type; float filter_strength; - int *node_mask; - /* 0=towards view, 1=flipped */ - float (*area_cos)[3]; - float (*area_nos)[3]; - int *count; + bool use_area_cos; + bool use_area_nos; bool any_vertex_sampled; float *prev_mask; float *pose_origin; float *pose_initial_co; + float *pose_factor; float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4]; float max_distance_squared; float nearest_vertex_search_co[3]; - int nearest_vertex_index; int mask_expand_update_it; bool mask_expand_invert_mask; @@ -204,6 +216,10 @@ typedef struct SculptThreadedTaskData { float transform_mats[8][4][4]; + float dirty_mask_min; + float dirty_mask_max; + bool dirty_mask_dirty_only; + ThreadMutex mutex; } SculptThreadedTaskData; @@ -233,6 +249,7 @@ typedef struct { float radius_squared; float *center; bool original; + bool ignore_fully_masked; } SculptSearchSphereData; typedef struct { @@ -240,6 +257,7 @@ typedef struct { struct SculptSession *ss; float radius_squared; bool original; + bool ignore_fully_masked; struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc; } SculptSearchCircleData; @@ -392,6 +410,7 @@ typedef struct FilterCache { int mask_update_last_it; int *mask_update_it; float *normal_factor; + float *edge_factor; float *prev_mask; float mask_expand_initial_co[3]; } FilterCache; @@ -413,6 +432,4 @@ void sculpt_update_object_bounding_box(struct Object *ob); bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect); -#define SCULPT_THREADED_LIMIT 4 - #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 3783eb17562..5d95cc80280 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -39,8 +39,6 @@ #include "DNA_scene_types.h" #include "DNA_mesh_types.h" #include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_workspace_types.h" #include "BKE_ccg.h" #include "BKE_context.h" @@ -49,7 +47,6 @@ #include "BKE_paint.h" #include "BKE_key.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_scene.h" #include "BKE_subsurf.h" #include "BKE_subdiv_ccg.h" @@ -62,13 +59,11 @@ #include "WM_api.h" #include "WM_types.h" -#include "ED_paint.h" #include "ED_object.h" #include "ED_sculpt.h" #include "ED_undo.h" #include "bmesh.h" -#include "paint_intern.h" #include "sculpt_intern.h" typedef struct UndoSculpt { @@ -91,6 +86,7 @@ static void update_cb(PBVHNode *node, void *rebuild) struct PartialUpdateData { PBVH *pbvh; bool rebuild; + char *modified_grids; }; /** @@ -99,8 +95,24 @@ struct PartialUpdateData { static void update_cb_partial(PBVHNode *node, void *userdata) { struct PartialUpdateData *data = userdata; - if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) { - update_cb(node, &(data->rebuild)); + if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) { + int *node_grid_indices; + int totgrid; + bool update = false; + BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL); + for (int i = 0; i < totgrid; i++) { + if (data->modified_grids[node_grid_indices[i]] == 1) { + update = true; + } + } + if (update) { + update_cb(node, &(data->rebuild)); + } + } + else { + if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) { + update_cb(node, &(data->rebuild)); + } } } @@ -140,7 +152,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt if (unode->maxvert) { /* regular mesh restore */ - if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) { + if (ss->shapekey_active && !STREQ(ss->shapekey_active->name, unode->shapeName)) { /* shape key has been changed before calling undo operator */ Key *key = BKE_key_from_object(ob); @@ -162,12 +174,12 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt index = unode->index; mvert = ss->mvert; - if (ss->kb) { + if (ss->shapekey_active) { float(*vertCos)[3]; - vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb); + vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (unode->orig_co) { - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]); } @@ -185,36 +197,33 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt } /* propagate new coords to keyblock */ - sculpt_vertcos_to_key(ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos); /* pbvh uses it's own mvert array, so coords should be */ /* propagated to pbvh here */ - BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->kb->totelem); + BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->shapekey_active->totelem); MEM_freeN(vertCos); } else { if (unode->orig_co) { - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { for (int i = 0; i < unode->totvert; i++) { - if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } else { for (int i = 0; i < unode->totvert; i++) { - if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } } else { for (int i = 0; i < unode->totvert; i++) { - if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) { - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; - } + swap_v3_v3(mvert[index[i]].co, unode->co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; } } } @@ -351,10 +360,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range( + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); if (nodes) { @@ -491,7 +499,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase SculptUndoNode *unode; bool update = false, rebuild = false; bool need_mask = false; - bool partial_update = true; for (unode = lb->first; unode; unode = unode->next) { /* restore pivot */ @@ -533,6 +540,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase return; } + char *undo_modified_grids = NULL; + bool use_multires_undo = false; + for (unode = lb->first; unode; unode = unode->next) { if (!STREQ(unode->idname, ob->id.name)) { @@ -552,8 +562,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase continue; } - /* multi-res can't do partial updates since it doesn't flag edited vertices */ - partial_update = false; + use_multires_undo = true; } switch (unode->type) { @@ -583,21 +592,29 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } + if (use_multires_undo) { + int max_grid; + unode = lb->first; + max_grid = unode->maxgrid; + undo_modified_grids = MEM_callocN(sizeof(char) * max_grid, "undo_grids"); + for (unode = lb->first; unode; unode = unode->next) { + for (int i = 0; i < unode->totgrid; i++) { + undo_modified_grids[unode->grids[i]] = 1; + } + } + } + if (update || rebuild) { bool tag_update = false; /* we update all nodes still, should be more clever, but also * needs to work correct when exiting/entering sculpt mode and * the nodes get recreated, though in that case it could do all */ - if (partial_update) { - struct PartialUpdateData data = { - .rebuild = rebuild, - .pbvh = ss->pbvh, - }; - BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); - } - else { - BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); - } + struct PartialUpdateData data = { + .rebuild = rebuild, + .pbvh = ss->pbvh, + .modified_grids = undo_modified_grids, + }; + BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data); BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw); if (BKE_sculpt_multires_active(scene, ob)) { @@ -611,7 +628,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase tag_update |= ((Mesh *)ob->data)->id.us > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d); - if (ss->kb || ss->modifiers_active) { + if (ss->shapekey_active || ss->deform_modifiers_active) { Mesh *mesh = ob->data; BKE_mesh_calc_normals(mesh); @@ -626,6 +643,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase sculpt_update_object_bounding_box(ob); } } + + MEM_SAFE_FREE(undo_modified_grids); } static void sculpt_undo_free_list(ListBase *lb) @@ -812,7 +831,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index"); } - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos"); } @@ -834,7 +853,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) normal_float_to_short_v3(unode->no[vd.i], vd.fno); } - if (ss->modifiers_active) { + if (ss->deform_modifiers_active) { copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]); } } @@ -1063,8 +1082,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType copy_v3_v3(unode->pivot_rot, ss->pivot_rot); /* store active shape key */ - if (ss->kb) { - BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name)); + if (ss->shapekey_active) { + BLI_strncpy(unode->shapeName, ss->shapekey_active->name, sizeof(ss->shapekey_active->name)); } else { unode->shapeName[0] = '\0'; diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index de03fea7bb1..8fbaf3396bd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -38,7 +38,6 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_main.h" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 4e710d31cbb..69745663c02 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -273,8 +273,11 @@ static void sound_update_animation_flags(Scene *scene) static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)) { + Scene *scene = CTX_data_scene(C); + BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false); sound_update_animation_flags(CTX_data_scene(C)); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 944a0c74f4c..242acfd0261 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1663,7 +1663,7 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = { {ACTKEYS_SNAP_CFRA, "CFRA", 0, - "Current frame", + "Current Frame", "Snap selected keyframes to the current frame"}, {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", @@ -1789,17 +1789,17 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = { {ACTKEYS_MIRROR_CFRA, "CFRA", 0, - "By Times over Current frame", + "By Times Over Current Frame", "Flip times of selected keyframes using the current frame as the mirror line"}, {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values over Value=0", + "By Values Over Value=0", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {ACTKEYS_MIRROR_MARKER, "MARKER", 0, - "By Times over First Selected Marker", + "By Times Over First Selected Marker", "Flip times of selected keyframes using the first selected marker as the reference point"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 912cd0407e3..ca6efb5f69e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -153,7 +153,8 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac, float region_x, float *r_selx, float *r_frame, - bool *r_found) + bool *r_found, + bool *r_is_selected) { *r_found = false; @@ -182,6 +183,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac, *r_selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); *r_frame = ak->cfra; *r_found = true; + *r_is_selected = (ak->sel & SELECT) != 0; break; } } @@ -197,14 +199,16 @@ static void actkeys_find_key_at_position(bAnimContext *ac, bAnimListElem **r_ale, float *r_selx, float *r_frame, - bool *r_found) + bool *r_found, + bool *r_is_selected) { *r_found = false; *r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y); if (*r_ale != NULL) { - actkeys_find_key_in_list_element(ac, *r_ale, region_x, r_selx, r_frame, r_found); + actkeys_find_key_in_list_element( + ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected); } } @@ -213,9 +217,11 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r bAnimListElem *ale; float selx, frame; bool found; + bool is_selected; int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS; - actkeys_find_key_at_position(ac, filter, region_x, region_y, &ale, &selx, &frame, &found); + actkeys_find_key_at_position( + ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected); if (ale != NULL) { MEM_freeN(ale); @@ -339,7 +345,9 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op) /* set notifier that keyframe selection have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -572,7 +580,9 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op) /* set notifier that keyframe selection have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -805,7 +815,9 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -871,7 +883,9 @@ static int action_circle_select_exec(bContext *C, wmOperator *op) /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -1099,7 +1113,9 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op) /* set notifier that keyframe selection have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -1159,7 +1175,9 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -1243,7 +1261,9 @@ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op)) /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -1278,7 +1298,9 @@ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op)) /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + } return OPERATOR_FINISHED; } @@ -1665,20 +1687,29 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s /* ------------------- */ -static void mouse_action_keys(bAnimContext *ac, - const int mval[2], - short select_mode, - const bool deselect_all, - const bool column, - const bool same_channel) +static int mouse_action_keys(bAnimContext *ac, + const int mval[2], + short select_mode, + const bool deselect_all, + const bool column, + const bool same_channel, + bool wait_to_deselect_others) { int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS; bAnimListElem *ale = NULL; bool found = false; + bool is_selected = false; float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ float selx = 0.0f; /* frame of keyframe under mouse */ - actkeys_find_key_at_position(ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found); + int ret_value = OPERATOR_FINISHED; + + actkeys_find_key_at_position( + ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected); + + if (select_mode != SELECT_REPLACE) { + wait_to_deselect_others = false; + } /* For replacing selection, if we have something to select, we have to clear existing selection. * The same goes if we found nothing to select, and deselect_all is true @@ -1687,56 +1718,61 @@ static void mouse_action_keys(bAnimContext *ac, /* reset selection mode for next steps */ select_mode = SELECT_ADD; - /* deselect all keyframes */ - deselect_action_keys(ac, 0, SELECT_SUBTRACT); - - /* highlight channel clicked on */ - if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight Action-Group or F-Curve? */ - if (ale != NULL && ale->data) { - if (ale->type == ANIMTYPE_GROUP) { - bActionGroup *agrp = ale->data; - - agrp->flag |= AGRP_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); - } - else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { - FCurve *fcu = ale->data; - - fcu->flag |= FCURVE_SELECTED; - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + if (wait_to_deselect_others && is_selected) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + /* deselect all keyframes */ + deselect_action_keys(ac, 0, SELECT_SUBTRACT); + + /* highlight channel clicked on */ + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight Action-Group or F-Curve? */ + if (ale != NULL && ale->data) { + if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp = ale->data; + + agrp->flag |= AGRP_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + } + else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + FCurve *fcu = ale->data; + + fcu->flag |= FCURVE_SELECTED; + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + } } } - } - else if (ac->datatype == ANIMCONT_GPENCIL) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - - /* Highlight GPencil Layer */ - if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) { - bGPdata *gpd = (bGPdata *)ale->id; - bGPDlayer *gpl = ale->data; - - gpl->flag |= GP_LAYER_SELECT; - /* Update other layer status. */ - if (BKE_gpencil_layer_getactive(gpd) != gpl) { - BKE_gpencil_layer_setactive(gpd, gpl); - BKE_gpencil_layer_autolock_set(gpd, false); - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + else if (ac->datatype == ANIMCONT_GPENCIL) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + + /* Highlight GPencil Layer */ + if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) { + bGPdata *gpd = (bGPdata *)ale->id; + bGPDlayer *gpl = ale->data; + + gpl->flag |= GP_LAYER_SELECT; + /* Update other layer status. */ + if (BKE_gpencil_layer_getactive(gpd) != gpl) { + BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_autolock_set(gpd, false); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } } } - } - else if (ac->datatype == ANIMCONT_MASK) { - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + else if (ac->datatype == ANIMCONT_MASK) { + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); - if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) { - MaskLayer *masklay = ale->data; + if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) { + MaskLayer *masklay = ale->data; - masklay->flag |= MASK_LAYERFLAG_SELECT; + masklay->flag |= MASK_LAYERFLAG_SELECT; + } } } } @@ -1771,12 +1807,15 @@ static void mouse_action_keys(bAnimContext *ac, /* free this channel */ MEM_freeN(ale); } + + return ret_value; } /* handle clicking */ -static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int actkeys_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + int ret_value; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) { @@ -1789,20 +1828,26 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent /* select mode is either replace (deselect all, then add) or add/extend */ const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE; const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); + int mval[2]; /* column selection */ const bool column = RNA_boolean_get(op->ptr, "column"); const bool channel = RNA_boolean_get(op->ptr, "channel"); + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + /* select keyframe(s) based upon mouse position*/ - mouse_action_keys(&ac, event->mval, selectmode, deselect_all, column, channel); + ret_value = mouse_action_keys( + &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others); /* set notifier that keyframe selection (and channels too) have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value | OPERATOR_PASS_THROUGH; } void ACTION_OT_clickselect(wmOperatorType *ot) @@ -1815,13 +1860,16 @@ void ACTION_OT_clickselect(wmOperatorType *ot) ot->description = "Select keyframes by clicking on them"; /* callbacks */ - ot->invoke = actkeys_clickselect_invoke; ot->poll = ED_operator_action_active; + ot->exec = actkeys_clickselect_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_UNDO; /* properties */ + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean( ot->srna, "extend", diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index e96dc91cedb..80b58954c8f 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -161,7 +161,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc /* cache background */ ED_region_cache_draw_background(ar); - /* cached segments -- could be usefu lto debug caching strategies */ + /* cached segments -- could be useful to debug caching strategies */ BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points); ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra); @@ -404,177 +404,185 @@ static void draw_stabilization_border( } } -static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track) -{ -#define MAX_STATIC_PATH 64 - int count = sc->path_length; - int i, a, b, curindex = -1; - float path_static[(MAX_STATIC_PATH + 1) * 2][2]; - float(*path)[2]; - int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame; - MovieTrackingMarker *marker; +enum { + PATH_POINT_FLAG_KEYFRAME = (1 << 0), +}; - if (count == 0) { - return; - } +typedef struct TrachPathPoint { + float co[2]; + uchar flag; +} TrackPathPoint; - start_frame = framenr = ED_space_clip_get_clip_frame_number(sc); - - marker = BKE_tracking_marker_get(track, framenr); - if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) { - return; - } - - if (count < MAX_STATIC_PATH) { - path = path_static; - } - else { - path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path"); +static void marker_to_path_point(SpaceClip *sc, + const MovieTrackingTrack *track, + const MovieTrackingMarker *marker, + TrackPathPoint *point) +{ + add_v2_v2v2(point->co, marker->pos, track->offset); + ED_clip_point_undistorted_pos(sc, point->co, point->co); + point->flag = 0; + if ((marker->flag & MARKER_TRACKED) == 0) { + point->flag |= PATH_POINT_FLAG_KEYFRAME; } +} - a = count; - i = framenr - 1; - while (i >= framenr - count) { - marker = BKE_tracking_marker_get(track, i); - - if (!marker || marker->flag & MARKER_DISABLED) { +static int track_to_path_segment(SpaceClip *sc, + MovieTrackingTrack *track, + int direction, + TrackPathPoint *path) +{ + const int count = sc->path_length; + int current_frame = ED_space_clip_get_clip_frame_number(sc); + const MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, current_frame); + /* Check whether there is marker at exact current frame. + * If not, we don't have anything to be put to path. */ + if (marker == NULL || (marker->flag & MARKER_DISABLED)) { + return 0; + } + /* Index inside of path array where we write data to. */ + int point_index = count; + int path_length = 0; + for (int i = 0; i < count; ++i) { + marker_to_path_point(sc, track, marker, &path[point_index]); + /* Move to the next marker along the path segment. */ + path_length++; + point_index += direction; + current_frame += direction; + marker = BKE_tracking_marker_get_exact(track, current_frame); + if (marker == NULL || (marker->flag & MARKER_DISABLED)) { + /* Reached end of tracked segment. */ break; } + } + return path_length; +} - if (marker->framenr == i) { - add_v2_v2v2(path[--a], marker->pos, track->offset); - ED_clip_point_undistorted_pos(sc, path[a], path[a]); +static void draw_track_path_points(const TrackPathPoint *path, + uint position_attribute, + const int start_point, + const int num_points) +{ + if (num_points == 0) { + return; + } + immBegin(GPU_PRIM_POINTS, num_points); + for (int i = 0; i < num_points; i++) { + const TrackPathPoint *point = &path[i + start_point]; + immVertex2fv(position_attribute, point->co); + } + immEnd(); +} - if (marker->framenr == start_frame) { - curindex = a; - } - } - else { - break; +static void draw_track_path_keyframe_points(const TrackPathPoint *path, + uint position_attribute, + const int start_point, + const int num_points) +{ + immBeginAtMost(GPU_PRIM_POINTS, num_points); + for (int i = 0; i < num_points; i++) { + const TrackPathPoint *point = &path[i + start_point]; + if (point->flag & PATH_POINT_FLAG_KEYFRAME) { + immVertex2fv(position_attribute, point->co); } + } + immEnd(); +} - i--; +static void draw_track_path_lines(const TrackPathPoint *path, + uint position_attribute, + const int start_point, + const int num_points) +{ + if (num_points < 2) { + return; + } + immBegin(GPU_PRIM_LINE_STRIP, num_points); + for (int i = 0; i < num_points; i++) { + const TrackPathPoint *point = &path[i + start_point]; + immVertex2fv(position_attribute, point->co); } + immEnd(); +} - b = count; - i = framenr; - while (i <= framenr + count) { - marker = BKE_tracking_marker_get(track, i); +static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track) +{ +#define MAX_STATIC_PATH 64 - if (!marker || marker->flag & MARKER_DISABLED) { - break; - } + const int count = sc->path_length; + TrackPathPoint path_static[(MAX_STATIC_PATH + 1) * 2]; + TrackPathPoint *path; + const bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0; - if (marker->framenr == i) { - if (marker->framenr == start_frame) { - curindex = b; - } + if (count == 0) { + /* Early output, nothing to bother about here. */ + return; + } - add_v2_v2v2(path[b++], marker->pos, track->offset); - ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]); - } - else { - break; - } + /* Try to use stack allocated memory when possibly, only use heap allocation + * for really long paths. */ + path = (count < MAX_STATIC_PATH) ? path_static : + MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path"); + /* Collect path information. */ + const int num_points_before = track_to_path_segment(sc, track, -1, path); + const int num_points_after = track_to_path_segment(sc, track, 1, path); + if (num_points_before == 0 && num_points_after == 0) { + return; + } - i++; + int num_all_points = num_points_before + num_points_after; + /* If both leading and trailing parts of the path are there the center point is counted twice. */ + if (num_points_before != 0 && num_points_after != 0) { + num_all_points -= 1; } - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + const int path_start_index = count - num_points_before + 1; + const int path_center_index = count; + const uint position_attribute = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* Draw path outline. */ if (!tiny) { immUniformThemeColor(TH_MARKER_OUTLINE); - if (TRACK_VIEW_SELECTED(sc, track)) { - if ((b - a - 1) >= 1) { - GPU_point_size(5.0f); - - immBegin(GPU_PRIM_POINTS, b - a - 1); - - for (i = a; i < b; i++) { - if (i != curindex) { - immVertex2f(pos, path[i][0], path[i][1]); - } - } - - immEnd(); - } - } - - if ((b - a) >= 2) { - GPU_line_width(3.0f); - - immBegin(GPU_PRIM_LINE_STRIP, b - a); - - for (i = a; i < b; i++) { - immVertex2f(pos, path[i][0], path[i][1]); - } - - immEnd(); + GPU_point_size(5.0f); + draw_track_path_points(path, position_attribute, path_start_index, num_all_points); + GPU_point_size(7.0f); + draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_all_points); } + /* Draw darker outline for actual path, all line segments at once. */ + GPU_line_width(3.0f); + draw_track_path_lines(path, position_attribute, path_start_index, num_all_points); } - if (TRACK_VIEW_SELECTED(sc, track)) { - GPU_point_size(3.0f); - - if ((curindex - a) >= 1) { - immUniformThemeColor(TH_PATH_BEFORE); - - immBegin(GPU_PRIM_POINTS, curindex - a); - - for (i = a; i < curindex; i++) { - immVertex2f(pos, path[i][0], path[i][1]); - } - - immEnd(); - } - - if ((b - curindex - 1) >= 1) { - immUniformThemeColor(TH_PATH_AFTER); - - immBegin(GPU_PRIM_POINTS, b - curindex - 1); - - for (i = curindex + 1; i < b; i++) { - immVertex2f(pos, path[i][0], path[i][1]); - } - - immEnd(); - } - } + /* Draw all points. */ + GPU_point_size(3.0f); + immUniformThemeColor(TH_PATH_BEFORE); + draw_track_path_points(path, position_attribute, path_start_index, num_points_before); + immUniformThemeColor(TH_PATH_AFTER); + draw_track_path_points(path, position_attribute, path_center_index, num_points_after); + /* Connect points with color coded segments. */ GPU_line_width(1); + immUniformThemeColor(TH_PATH_BEFORE); + draw_track_path_lines(path, position_attribute, path_start_index, num_points_before); + immUniformThemeColor(TH_PATH_AFTER); + draw_track_path_lines(path, position_attribute, path_center_index, num_points_after); + + /* Draw all bigger points corresponding to keyframes. */ + GPU_point_size(5.0f); + immUniformThemeColor(TH_PATH_KEYFRAME_BEFORE); + draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_points_before); + immUniformThemeColor(TH_PATH_KEYFRAME_AFTER); + draw_track_path_keyframe_points(path, position_attribute, path_center_index, num_points_after); - if ((curindex - a + 1) >= 2) { - immUniformThemeColor(TH_PATH_BEFORE); - - immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1); - - for (i = a; i <= curindex; i++) { - immVertex2f(pos, path[i][0], path[i][1]); - } - - immEnd(); - } - - if ((b - curindex) >= 2) { - immUniformThemeColor(TH_PATH_AFTER); - - immBegin(GPU_PRIM_LINE_STRIP, b - curindex); - - for (i = curindex; i < b; i++) { - immVertex2f(pos, path[i][0], path[i][1]); - } - - immEnd(); + if (path != path_static) { + MEM_freeN(path); } immUnbindProgram(); - if (path != path_static) { - MEM_freeN(path); - } #undef MAX_STATIC_PATH } diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 1fae4c91a48..bd54d4f0016 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -94,6 +94,7 @@ void CLIP_OT_view_zoom_out(struct wmOperatorType *ot); void CLIP_OT_view_zoom_ratio(struct wmOperatorType *ot); void CLIP_OT_view_all(struct wmOperatorType *ot); void CLIP_OT_view_selected(struct wmOperatorType *ot); +void CLIP_OT_view_center_cursor(struct wmOperatorType *ot); void CLIP_OT_change_frame(wmOperatorType *ot); void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot); void CLIP_OT_mode_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index da534cf9b40..192449a219d 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -78,7 +78,9 @@ #include "clip_intern.h" // own include -/******************** view navigation utilities *********************/ +/* -------------------------------------------------------------------- */ +/** \name View Navigation Utilities + * \{ */ static void sclip_zoom_set(const bContext *C, float zoom, @@ -162,7 +164,11 @@ static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float ED_region_tag_redraw(ar); } -/******************** open clip operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Open Clip Operator + * \{ */ static void clip_filesel(bContext *C, wmOperator *op, const char *path) { @@ -326,7 +332,11 @@ void CLIP_OT_open(wmOperatorType *ot) FILE_SORT_ALPHA); } -/******************* reload clip operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reload Clip Operator + * \{ */ static int reload_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -355,7 +365,11 @@ void CLIP_OT_reload(wmOperatorType *ot) ot->exec = reload_exec; } -/********************** view pan operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * \{ */ typedef struct ViewPanData { float x, y; @@ -376,7 +390,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) /* Grab will be set when running from gizmo. */ vpd->own_cursor = (win->grabcursor == 0); if (vpd->own_cursor) { - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } vpd->x = event->x; @@ -525,7 +539,11 @@ void CLIP_OT_view_pan(wmOperatorType *ot) FLT_MAX); } -/********************** view zoom operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ typedef struct ViewZoomData { float x, y; @@ -549,7 +567,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) /* Grab will be set when running from gizmo. */ vpd->own_cursor = (win->grabcursor == 0); if (vpd->own_cursor) { - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } if (U.viewzoom == USER_ZOOM_CONT) { @@ -729,7 +747,11 @@ void CLIP_OT_view_zoom(wmOperatorType *ot) WM_operator_properties_use_cursor_init(ot); } -/********************** view zoom in/out operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom In/Out Operator + * \{ */ static int view_zoom_in_exec(bContext *C, wmOperator *op) { @@ -845,7 +867,11 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/********************** view zoom ratio operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Ratio Operator + * \{ */ static int view_zoom_ratio_exec(bContext *C, wmOperator *op) { @@ -887,8 +913,11 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot) -FLT_MAX, FLT_MAX); } +/** \} */ -/********************** view all operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * \{ */ static int view_all_exec(bContext *C, wmOperator *op) { @@ -961,8 +990,41 @@ void CLIP_OT_view_all(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Center View To Cursor Operator + * \{ */ + +static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + + clip_view_center_to_point(sc, sc->cursor[0], sc->cursor[1]); -/********************** view selected operator *********************/ + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void CLIP_OT_view_center_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Center View to Cursor"; + ot->description = "Center the view so that the cursor is in the middle of the view"; + ot->idname = "CLIP_OT_view_center_cursor"; + + /* api callbacks */ + ot->exec = view_center_cursor_exec; + ot->poll = ED_space_clip_maskedit_poll; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Selected Operator + * \{ */ static int view_selected_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -992,8 +1054,11 @@ void CLIP_OT_view_selected(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; } +/** \} */ -/********************** change frame operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name Change Frame Operator + * \{ */ static bool change_frame_poll(bContext *C) { @@ -1109,8 +1174,11 @@ void CLIP_OT_change_frame(wmOperatorType *ot) /* rna */ RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); } +/** \} */ -/********************** rebuild proxies operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name Rebuild Proxies Operator + * \{ */ typedef struct ProxyBuildJob { Scene *scene; @@ -1521,8 +1589,11 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER; } +/** \} */ -/********************** mode set operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name Mode Set Operator + * \{ */ static int mode_set_exec(bContext *C, wmOperator *op) { @@ -1558,7 +1629,12 @@ void CLIP_OT_mode_set(wmOperatorType *ot) } #ifdef WITH_INPUT_NDOF -/********************** NDOF operator *********************/ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Operator + * \{ */ /* Combined pan/zoom from a 3D mouse device. * Z zooms, XY pans @@ -1608,9 +1684,14 @@ void CLIP_OT_view_ndof(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; } + +/** \} */ + #endif /* WITH_INPUT_NDOF */ -/********************** Prefetch operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name Prefetch Operator + * \{ */ static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -1650,8 +1731,11 @@ void CLIP_OT_prefetch(wmOperatorType *ot) ot->invoke = clip_prefetch_invoke; ot->modal = clip_prefetch_modal; } +/** \} */ -/********************** Set scene frames *********************/ +/* -------------------------------------------------------------------- */ +/** \name Set Scene Frames Operator + * \{ */ static int clip_set_scene_frames_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1686,8 +1770,11 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; ot->exec = clip_set_scene_frames_exec; } +/** \} */ -/******************** set 3d cursor operator ********************/ +/* -------------------------------------------------------------------- */ +/** \name Set 3d Cursor Operator + * \{ */ static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op) { @@ -1748,7 +1835,11 @@ void CLIP_OT_cursor_set(wmOperatorType *ot) 10.0f); } -/********************** Toggle lock to selection operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Lock To Selection Operator + * \{ */ static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1773,7 +1864,11 @@ void CLIP_OT_lock_selection_toggle(wmOperatorType *ot) ot->flag = OPTYPE_LOCK_BYPASS; } -/********************** macros *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Macros + * \{ */ void ED_operatormacros_clip(void) { @@ -1797,3 +1892,5 @@ void ED_operatormacros_clip(void) otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); RNA_boolean_set(otmacro->ptr, "release_confirm", true); } + +/** \} */ diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 2964a95648a..16305a9b17b 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -443,6 +443,7 @@ static void clip_operatortypes(void) WM_operatortype_append(CLIP_OT_view_zoom_ratio); WM_operatortype_append(CLIP_OT_view_all); WM_operatortype_append(CLIP_OT_view_selected); + WM_operatortype_append(CLIP_OT_view_center_cursor); WM_operatortype_append(CLIP_OT_change_frame); WM_operatortype_append(CLIP_OT_rebuild_proxy); WM_operatortype_append(CLIP_OT_mode_set); diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 68198acfe52..f1bce00ea0b 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -2090,7 +2090,7 @@ static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op)) void CLIP_OT_keyframe_insert(wmOperatorType *ot) { /* identifiers */ - ot->name = "Insert keyframe"; + ot->name = "Insert Keyframe"; ot->description = "Insert a keyframe to selected tracks at current frame"; ot->idname = "CLIP_OT_keyframe_insert"; @@ -2113,7 +2113,7 @@ static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op)) void CLIP_OT_keyframe_delete(wmOperatorType *ot) { /* identifiers */ - ot->name = "Delete keyframe"; + ot->name = "Delete Keyframe"; ot->description = "Delete a keyframe from selected tracks at current frame"; ot->idname = "CLIP_OT_keyframe_delete"; diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c index 1d2fc239a89..7e2671382b9 100644 --- a/source/blender/editors/space_clip/tracking_ops_solve.c +++ b/source/blender/editors/space_clip/tracking_ops_solve.c @@ -118,7 +118,11 @@ static void solve_camera_freejob(void *scv) MovieClip *clip = scj->clip; int solved; - WM_set_locked_interface(scj->wm, false); + /* WindowManager is missing in the job when initialization is incomplete. + * In this case the interface is not locked either. */ + if (scj->wm != NULL) { + WM_set_locked_interface(scj->wm, false); + } if (!scj->context) { /* job weren't fully initialized due to some error */ diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c index 3970f1381bf..7579c9a49c6 100644 --- a/source/blender/editors/space_clip/tracking_ops_utils.c +++ b/source/blender/editors/space_clip/tracking_ops_utils.c @@ -57,11 +57,11 @@ void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *cli void clip_tracking_hide_cursor(bContext *C) { wmWindow *win = CTX_wm_window(C); - WM_cursor_set(win, CURSOR_NONE); + WM_cursor_set(win, WM_CURSOR_NONE); } void clip_tracking_show_cursor(bContext *C) { wmWindow *win = CTX_wm_window(C); - WM_cursor_set(win, CURSOR_STD); + WM_cursor_set(win, WM_CURSOR_DEFAULT); } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index f5c02dbd724..5cc2f00413a 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -149,11 +149,11 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *ar) static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) { SpaceText *st = sa->spacedata.first; - int wmcursor = BC_TEXTEDITCURSOR; + int wmcursor = WM_CURSOR_TEXT_EDIT; if (st->text && BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) { - wmcursor = CURSOR_STD; + wmcursor = WM_CURSOR_DEFAULT; } WM_cursor_set(win, wmcursor); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 4b86f38f8e4..b0ff67844d8 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -32,10 +32,6 @@ struct FileSelectParams; struct SpaceFile; struct View2D; -/* file_ops.c */ -struct ARegion *file_tools_region(struct ScrArea *sa); -struct ARegion *file_tool_props_region(struct ScrArea *sa); - /* file_draw.c */ #define TILE_BORDER_X (UI_UNIT_X / 4) #define TILE_BORDER_Y (UI_UNIT_Y / 4) @@ -86,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot); void FILE_OT_previous(struct wmOperatorType *ot); void FILE_OT_next(struct wmOperatorType *ot); void FILE_OT_refresh(struct wmOperatorType *ot); -void FILE_OT_bookmark_toggle(struct wmOperatorType *ot); void FILE_OT_filenum(struct wmOperatorType *ot); void FILE_OT_delete(struct wmOperatorType *ot); void FILE_OT_rename(struct wmOperatorType *ot); @@ -112,6 +107,7 @@ void file_sfile_to_operator_ex(bContext *C, struct SpaceFile *sfile, char *filepath); void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile); + void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 127196cca74..3cdcc07f081 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1506,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) bool file_draw_check_exists(SpaceFile *sfile) { if (sfile->op) { /* fails on reload */ - PropertyRNA *prop; - if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) { - if (RNA_property_boolean_get(sfile->op->ptr, prop)) { - char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); - if (BLI_is_file(filepath)) { - return true; - } + if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) { + char filepath[FILE_MAX]; + BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); + if (BLI_is_file(filepath)) { + return true; } } } @@ -2152,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { + char old_dir[sizeof(sfile->params->dir)]; + + BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir)); + file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ @@ -2185,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); if (filelist_is_dir(sfile->files, sfile->params->dir)) { - /* if directory exists, enter it immediately */ - ED_file_change_dir(C); + if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ + /* if directory exists, enter it immediately */ + ED_file_change_dir(C); + } /* don't do for now because it selects entire text instead of * placing cursor at the end */ @@ -2318,78 +2321,6 @@ void FILE_OT_hidedot(struct wmOperatorType *ot) ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } -ARegion *file_tools_region(ScrArea *sa) -{ - ARegion *ar, *arnew; - - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) { - return ar; - } - - /* add subdiv level; after header */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - - /* is error! */ - if (ar == NULL) { - return NULL; - } - - arnew = MEM_callocN(sizeof(ARegion), "tools for file"); - BLI_insertlinkafter(&sa->regionbase, ar, arnew); - arnew->regiontype = RGN_TYPE_TOOLS; - arnew->alignment = RGN_ALIGN_LEFT; - - return arnew; -} - -ARegion *file_tool_props_region(ScrArea *sa) -{ - ARegion *ar, *arnew; - - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) { - return ar; - } - - /* add subdiv level; after execute region */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE); - - /* is error! */ - if (ar == NULL) { - return NULL; - } - - arnew = MEM_callocN(sizeof(ARegion), "tool props for file"); - BLI_insertlinkafter(&sa->regionbase, ar, arnew); - arnew->regiontype = RGN_TYPE_TOOL_PROPS; - arnew->alignment = RGN_ALIGN_RIGHT; - - return arnew; -} - -static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused)) -{ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = file_tools_region(sa); - - if (ar) { - ED_region_toggle_hidden(C, ar); - } - - return OPERATOR_FINISHED; -} - -void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Bookmarks"; - ot->description = "Toggle bookmarks display"; - ot->idname = "FILE_OT_bookmark_toggle"; - - /* api callbacks */ - ot->exec = file_bookmark_toggle_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ -} - static bool file_filenum_poll(bContext *C) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -2398,7 +2329,7 @@ static bool file_filenum_poll(bContext *C) return false; } - return sfile->params && (sfile->params->action_type == FILE_SAVE); + return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING); } /** @@ -2464,60 +2395,49 @@ void FILE_OT_filenum(struct wmOperatorType *ot) RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100); } -static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) +static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + const int numfiles = filelist_files_ensure(sfile->files); - if (sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); + if ((file_idx >= 0) && (file_idx < numfiles)) { + FileDirEntry *file = filelist_file(sfile->files, file_idx); + + if ((require_selected == false) || + (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) { filelist_entry_select_index_set( - sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); + sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); /* We can skip the pending state, * as we can directly set FILE_SEL_EDITING on the expected entry here. */ sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; } + } +} + +static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +{ + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + + if (sfile->params) { + file_rename_state_activate(sfile, sfile->params->active_file, true); ED_area_tag_redraw(sa); } return OPERATOR_FINISHED; } -static bool file_rename_poll(bContext *C) +static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) { - bool poll = ED_operator_file_active(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); - if (FILENAME_IS_CURRPAR(file->relpath)) { - poll = false; - } - } + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - if (sfile->params->highlight_file < 0) { - poll = false; - } - else { - char dir[FILE_MAX_LIBEXTRA]; - if (filelist_islibrary(sfile->files, dir, NULL)) { - poll = false; - } - } - } - else { - poll = false; + if (sfile->params) { + file_rename_state_activate(sfile, sfile->params->highlight_file, false); + ED_area_tag_redraw(sa); } - return poll; + return OPERATOR_FINISHED; } void FILE_OT_rename(struct wmOperatorType *ot) @@ -2528,8 +2448,9 @@ void FILE_OT_rename(struct wmOperatorType *ot) ot->idname = "FILE_OT_rename"; /* api callbacks */ + ot->invoke = file_rename_invoke; ot->exec = file_rename_exec; - ot->poll = file_rename_poll; + ot->poll = ED_operator_file_active; } static bool file_delete_poll(bContext *C) @@ -2573,23 +2494,29 @@ int file_delete_exec(bContext *C, wmOperator *op) int numfiles = filelist_files_ensure(sfile->files); int i; + const char *error_message = NULL; bool report_error = false; errno = 0; for (i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { file = filelist_file(sfile->files, i); BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath); - if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) { + if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) { report_error = true; } } } if (report_error) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not delete file: %s", - errno ? strerror(errno) : "unknown error"); + if (error_message != NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message); + } + else { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not delete file or directory: %s", + errno ? strerror(errno) : "unknown error"); + } } ED_fileselect_clear(wm, sa, sfile); @@ -2602,7 +2529,7 @@ void FILE_OT_delete(struct wmOperatorType *ot) { /* identifiers */ ot->name = "Delete Selected Files"; - ot->description = "Delete selected files"; + ot->description = "Move selected files to the trash or recycle bin"; ot->idname = "FILE_OT_delete"; /* api callbacks */ diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index b0fed1fafd4..9ba098fcf45 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -110,18 +110,22 @@ void file_tool_props_region_panels_register(ARegionType *art) BLI_addtail(&art->paneltypes, pt); } -static void file_panel_execution_cancel_button(uiBlock *block) +static void file_panel_execution_cancel_button(uiLayout *layout) { - uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_cancel", - WM_OP_EXEC_REGION_WIN, - IFACE_("Cancel"), - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - ""); + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetScaleX(row, 0.8f); + uiLayoutSetFixedSize(row, true); + uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel"); +} + +static void file_panel_execution_execute_button(uiLayout *layout, const char *title) +{ + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetScaleX(row, 0.8f); + uiLayoutSetFixedSize(row, true); + /* Just a display hint. */ + uiLayoutSetActiveDefault(row, true); + uiItemO(row, title, ICON_NONE, "FILE_OT_execute"); } static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) @@ -145,7 +149,6 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, ¶ms_rna_ptr); row = uiLayoutRow(pa->layout, false); - uiLayoutSetScaleX(row, 1.3f); uiLayoutSetScaleY(row, 1.3f); /* callbacks for operator check functions */ @@ -176,7 +179,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) * immediate ui_apply_but_func but only after button deactivates */ UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); - if (params->action_type == FILE_SAVE) { + if (params->flag & FILE_CHECK_EXISTING) { but_extra_rna_ptr = UI_but_extra_operator_icon_add( but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD); RNA_int_set(but_extra_rna_ptr, "increment", 1); @@ -192,23 +195,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa) UI_block_func_set(block, NULL, NULL, NULL); { - if (windows_layout == false) { - file_panel_execution_cancel_button(block); - } - but = uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_execute", - WM_OP_EXEC_REGION_WIN, - params->title, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - ""); - /* Just a display hint. */ - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); + uiLayout *sub = uiLayoutRow(row, false); + uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN); + if (windows_layout) { - file_panel_execution_cancel_button(block); + file_panel_execution_execute_button(sub, params->title); + file_panel_execution_cancel_button(sub); + } + else { + file_panel_execution_cancel_button(sub); + file_panel_execution_execute_button(sub, params->title); } } } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 27cccf6bab1..d29233618de 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -831,7 +831,7 @@ void filelist_setfilter_options(FileList *filelist, } if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { filelist->filter_data.filter = filter; - filelist->filter_data.filter_id = filter_id; + filelist->filter_data.filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL; update = true; } if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e54f13e9356..bb3906a961b 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -49,6 +49,8 @@ #include "BLI_utildefines.h" #include "BLI_fnmatch.h" +#include "BLO_readfile.h" + #include "BLT_translation.h" #include "BKE_appdir.h" @@ -101,10 +103,9 @@ short ED_fileselect_set_params(SpaceFile *sfile) sizeof(sfile->params->dir), sizeof(sfile->params->file)); sfile->params->filter_glob[0] = '\0'; - /* set the default thumbnails size */ - sfile->params->thumbnail_size = 128; - /* Show size column by default. */ - sfile->params->details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; + sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size; + sfile->params->details_flags = U_default.file_space_data.details_flags; + sfile->params->filter_id = U_default.file_space_data.filter_id; } params = sfile->params; @@ -167,6 +168,9 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->flag &= ~FILE_DIRSEL_ONLY; } + if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) { + params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0; + } if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) { params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0; } @@ -241,15 +245,6 @@ short ED_fileselect_set_params(SpaceFile *sfile) } } - /* For now, always init filterid to 'all true' */ - params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | - FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | - FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | - FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | - FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | - FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | - FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP; - if (U.uiflag & USER_HIDE_DOT) { params->flag |= FILE_HIDE_DOT; } @@ -271,30 +266,11 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->sort = RNA_property_enum_get(op->ptr, prop); } else { - params->sort = FILE_SORT_ALPHA; - } - - if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) { - params->action_type = RNA_property_enum_get(op->ptr, prop); + params->sort = U_default.file_space_data.sort_type; } if (params->display == FILE_DEFAULTDISPLAY) { - if (params->display_previous == FILE_DEFAULTDISPLAY) { - if (U.uiflag & USER_SHOW_THUMBNAILS) { - if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) { - params->display = FILE_IMGDISPLAY; - } - else { - params->display = FILE_VERTICALDISPLAY; - } - } - else { - params->display = FILE_VERTICALDISPLAY; - } - } - else { - params->display = params->display_previous; - } + params->display = U_default.file_space_data.display_type; } if (is_relative_path) { @@ -308,10 +284,9 @@ short ED_fileselect_set_params(SpaceFile *sfile) else { /* default values, if no operator */ params->type = FILE_UNIX; - params->flag |= FILE_HIDE_DOT; + params->flag |= U_default.file_space_data.flag; params->flag &= ~FILE_DIRSEL_ONLY; params->display = FILE_VERTICALDISPLAY; - params->display_previous = FILE_DEFAULTDISPLAY; params->sort = FILE_SORT_ALPHA; params->filter = 0; params->filter_glob[0] = '\0'; @@ -347,6 +322,65 @@ short ED_fileselect_set_params(SpaceFile *sfile) return 1; } +/* The subset of FileSelectParams.flag items we store into preferences. */ +#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT) + +void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) +{ + wmOperator *op = sfile->op; + UserDef_FileSpaceData *sfile_udata = &U.file_space_data; + + ED_fileselect_set_params(sfile); + + if (!op) { + return; + } + + if (!RNA_struct_property_is_set(op->ptr, "display_type")) { + sfile->params->display = sfile_udata->display_type; + } + if (!RNA_struct_property_is_set(op->ptr, "sort_method")) { + sfile->params->sort = sfile_udata->sort_type; + } + sfile->params->thumbnail_size = sfile_udata->thumbnail_size; + sfile->params->details_flags = sfile_udata->details_flags; + sfile->params->filter_id = sfile_udata->filter_id; + + /* Combine flags we take from params with the flags we take from userdef. */ + sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) | + (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED); +} + +/** + * Update the user-preference data for the file space. In fact, this also contains some + * non-FileSelectParams data, but we can safely ignore this. + * + * \param temp_win_size: If the browser was opened in a temporary window, + * pass its size here so we can store that in the preferences. Otherwise NULL. + */ +void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2]) +{ + UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data; + UserDef_FileSpaceData sfile_udata_old = U.file_space_data; + + sfile_udata_new->display_type = sfile->params->display; + sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size; + sfile_udata_new->sort_type = sfile->params->sort; + sfile_udata_new->details_flags = sfile->params->details_flags; + sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED; + sfile_udata_new->filter_id = sfile->params->filter_id; + + if (temp_win_size) { + sfile_udata_new->temp_win_sizex = temp_win_size[0]; + sfile_udata_new->temp_win_sizey = temp_win_size[1]; + } + + /* Tag prefs as dirty if something has changed. */ + if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) { + U.runtime.is_dirty = true; + } +} + void ED_fileselect_reset_params(SpaceFile *sfile) { sfile->params->type = FILE_UNIX; @@ -767,7 +801,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) layout->tile_border_x * 2; layout->flag = FILE_LAYOUT_HOR; } - params->display_previous = params->display; layout->dirty = false; } @@ -924,6 +957,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) return; } if (sfile->op) { + wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL; + int win_size[2]; + + if (temp_win) { + /* Get DPI/pixelsize independent size to be stored in preferences. */ + WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */ + win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC; + win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC; + } + ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL); + WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); sfile->op = NULL; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index d6a4eafc658..d63fcf402de 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -55,6 +55,40 @@ #include "filelist.h" #include "GPU_framebuffer.h" +static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev) +{ + ARegion *ar; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) { + return ar; + } + + ar = MEM_callocN(sizeof(ARegion), "execute region for file"); + BLI_insertlinkafter(&sa->regionbase, ar_prev, ar); + ar->regiontype = RGN_TYPE_EXECUTE; + ar->alignment = RGN_ALIGN_BOTTOM; + ar->flag = RGN_FLAG_DYNAMIC_SIZE; + + return ar; +} + +static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev) +{ + ARegion *ar; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) { + return ar; + } + + /* add subdiv level; after execute region */ + ar = MEM_callocN(sizeof(ARegion), "tool props for file"); + BLI_insertlinkafter(&sa->regionbase, ar_prev, ar); + ar->regiontype = RGN_TYPE_TOOL_PROPS; + ar->alignment = RGN_ALIGN_RIGHT; + + return ar; +} + /* ******************** default callbacks for file space ***************** */ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) @@ -72,40 +106,20 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen /* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */ ar->alignment = RGN_ALIGN_TOP; - /* ui list region */ - ar = MEM_callocN(sizeof(ARegion), "ui region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_UI; - ar->alignment = RGN_ALIGN_TOP; - ar->flag |= RGN_FLAG_DYNAMIC_SIZE; - /* Tools region */ ar = MEM_callocN(sizeof(ARegion), "tools region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_TOOLS; ar->alignment = RGN_ALIGN_LEFT; - /* Tools region (lower split region) */ - ar = MEM_callocN(sizeof(ARegion), "lower tools region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - ar->flag |= RGN_FLAG_DYNAMIC_SIZE; - /* Execute region */ - ar = MEM_callocN(sizeof(ARegion), "execute region for file"); + /* ui list region */ + ar = MEM_callocN(sizeof(ARegion), "ui region for file"); BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_EXECUTE; - ar->alignment = RGN_ALIGN_BOTTOM; + ar->regiontype = RGN_TYPE_UI; + ar->alignment = RGN_ALIGN_TOP; ar->flag |= RGN_FLAG_DYNAMIC_SIZE; - /* Tool props region is added as needed. */ -#if 0 - /* Tool props (aka operator) region */ - ar = MEM_callocN(sizeof(ARegion), "tool props region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_RIGHT; -#endif + /* Tool props and execute region are added as needed, see file_refresh(). */ /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for file"); @@ -218,6 +232,46 @@ static SpaceLink *file_duplicate(SpaceLink *sl) return (SpaceLink *)sfilen; } +static void file_ensure_valid_region_state(bContext *C, + wmWindowManager *wm, + wmWindow *win, + ScrArea *sa, + SpaceFile *sfile, + FileSelectParams *params) +{ + ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI); + ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS); + ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE); + bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */ + + /* If there's an file-operation, ensure we have the option and execute region */ + if (sfile->op && (ar_props == NULL)) { + ar_execute = file_execute_region_ensure(sa, ar_ui); + ar_props = file_tool_props_region_ensure(sa, ar_execute); + + if (params->flag & FILE_HIDE_TOOL_PROPS) { + ar_props->flag |= RGN_FLAG_HIDDEN; + } + else { + ar_props->flag &= ~RGN_FLAG_HIDDEN; + } + + needs_init = true; + } + /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */ + else if ((sfile->op == NULL) && (ar_props != NULL)) { + BLI_assert(ar_execute != NULL); + + ED_region_remove(C, sa, ar_props); + ED_region_remove(C, sa, ar_execute); + needs_init = true; + } + + if (needs_init) { + ED_area_initialize(wm, win, sa); + } +} + static void file_refresh(const bContext *C, ScrArea *sa) { wmWindowManager *wm = CTX_wm_manager(C); @@ -287,21 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa) } /* Might be called with NULL sa, see file_main_region_draw() below. */ - if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) { - /* Create TOOLS region. */ - file_tools_region(sa); - - ED_area_initialize(wm, win, sa); - } - if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) { - /* Create TOOL_PROPS region. */ - ARegion *region_props = file_tool_props_region(sa); - - if (params->flag & FILE_HIDE_TOOL_PROPS) { - region_props->flag |= RGN_FLAG_HIDDEN; - } - - ED_area_initialize(wm, win, sa); + if (sa) { + file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params); } ED_area_tag_redraw(sa); @@ -495,7 +536,6 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_previous); WM_operatortype_append(FILE_OT_next); WM_operatortype_append(FILE_OT_refresh); - WM_operatortype_append(FILE_OT_bookmark_toggle); WM_operatortype_append(FILE_OT_bookmark_add); WM_operatortype_append(FILE_OT_bookmark_delete); WM_operatortype_append(FILE_OT_bookmark_cleanup); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 708d91a82bb..33cb1cb0075 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -862,7 +862,11 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar sub = uiLayoutColumn(layout, true); uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE); - if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) { + if (ELEM(dtar->transChan, + DTAR_TRANSCHAN_ROTX, + DTAR_TRANSCHAN_ROTY, + DTAR_TRANSCHAN_ROTZ, + DTAR_TRANSCHAN_ROTW)) { uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE); } @@ -1152,8 +1156,12 @@ static void graph_draw_driver_settings_panel(uiLayout *layout, if ((dvar->type == DVAR_TYPE_ROT_DIFF) || (dvar->type == DVAR_TYPE_TRANSFORM_CHAN && - dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX && - dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) { + ELEM(dvar->targets[0].transChan, + DTAR_TRANSCHAN_ROTX, + DTAR_TRANSCHAN_ROTY, + DTAR_TRANSCHAN_ROTZ, + DTAR_TRANSCHAN_ROTW) && + dvar->targets[0].rotation_mode != DTAR_ROTMODE_QUATERNION)) { BLI_snprintf( valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval)); } diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index c94f1f1d79f..42a1566629a 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -879,10 +879,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) float offset; float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset); - /* for now, only show when debugging driver... */ - // if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0) - // return; - const uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 329067de545..59cf5f63de3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2506,28 +2506,28 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = { {GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, - "By Times over Current Frame", + "By Times Over Current Frame", "Flip times of selected keyframes using the current frame as the mirror line"}, {GRAPHKEYS_MIRROR_VALUE, "VALUE", 0, - "By Values over Cursor Value", + "By Values Over Cursor Value", "Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the " "mirror line"}, {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, - "By Times over Time=0", + "By Times Over Time=0", "Flip times of selected keyframes, effectively reversing the order they appear in"}, {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values over Value=0", + "By Values Over Value=0", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, - "By Times over First Selected Marker", + "By Times Over First Selected Marker", "Flip times of selected keyframes using the first selected marker as the reference point"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 61e6b065cba..5abcff436f1 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC ../../makesrna ../../render/extern/include ../../windowmanager + ../../../../intern/clog ../../../../intern/glew-mx ../../../../intern/guardedalloc ) @@ -42,6 +43,7 @@ set(SRC image_draw.c image_edit.c image_ops.c + image_undo.c space_image.c image_intern.h diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index ccd0a2bfd79..ec2b1cc7fbe 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -301,6 +301,18 @@ void ED_image_mouse_pos(SpaceImage *sima, ARegion *ar, const int mval[2], float co[1] = ((mval[1] - sy) / zoomy) / height; } +void ED_image_view_center_to_point(SpaceImage *sima, float x, float y) +{ + int width, height; + float aspx, aspy; + + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_aspect(sima, &aspx, &aspy); + + sima->xof = (x - 0.5f) * width * aspx; + sima->yof = (y - 0.5f) * height * aspy; +} + void ED_image_point_pos(SpaceImage *sima, ARegion *ar, float x, float y, float *xr, float *yr) { int sx, sy, width, height; @@ -476,3 +488,9 @@ bool ED_space_image_maskedit_mask_poll(bContext *C) return false; } + +bool ED_space_image_cursor_poll(bContext *C) +{ + return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) || + ED_space_image_paint_curve(C); +} diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 1abb6715fdb..f8ce065d46c 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -44,10 +44,12 @@ void draw_image_sample_line(struct SpaceImage *sima); /* image_ops.c */ bool space_image_main_region_poll(struct bContext *C); +bool space_image_view_center_cursor_poll(struct bContext *C); void IMAGE_OT_view_all(struct wmOperatorType *ot); void IMAGE_OT_view_pan(struct wmOperatorType *ot); void IMAGE_OT_view_selected(struct wmOperatorType *ot); +void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot); void IMAGE_OT_view_zoom(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot); @@ -70,6 +72,7 @@ void IMAGE_OT_pack(struct wmOperatorType *ot); void IMAGE_OT_unpack(struct wmOperatorType *ot); void IMAGE_OT_invert(struct wmOperatorType *ot); +void IMAGE_OT_resize(struct wmOperatorType *ot); void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot); void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index e338a450db6..a8dfad85232 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -103,7 +103,9 @@ #include "image_intern.h" -/******************** view navigation utilities *********************/ +/* -------------------------------------------------------------------- */ +/** \name View Navigation Utilities + * \{ */ static void sima_zoom_set( SpaceImage *sima, ARegion *ar, float zoom, const float location[2], const bool zoom_to_pos) @@ -211,7 +213,7 @@ static ImageUser *image_user_from_context(const bContext *C) } } -static bool image_buffer_exists_from_context(bContext *C) +static bool image_from_context_has_data_poll(bContext *C) { Image *ima = image_from_context(C); ImageUser *iuser = image_user_from_context(C); @@ -227,6 +229,16 @@ static bool image_buffer_exists_from_context(bContext *C) return has_buffer; } +/** + * Use this when the image buffer is accessed without the image user. + */ +static bool image_from_contect_has_data_poll_no_image_user(bContext *C) +{ + Image *ima = image_from_context(C); + + return BKE_image_has_ibuf(ima, NULL); +} + static bool image_not_packed_poll(bContext *C) { /* Do not run 'replace' on packed images, it does not give user expected results at all. */ @@ -280,7 +292,12 @@ static bool image_sample_poll(bContext *C) return true; } -/********************** view pan operator *********************/ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * \{ */ typedef struct ViewPanData { float x, y; @@ -300,7 +317,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even /* Grab will be set when running from gizmo. */ vpd->own_cursor = (win->grabcursor == 0); if (vpd->own_cursor) { - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } vpd->x = event->x; @@ -423,7 +440,11 @@ void IMAGE_OT_view_pan(wmOperatorType *ot) FLT_MAX); } -/********************** view zoom operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ typedef struct ViewZoomData { float origx, origy; @@ -453,7 +474,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve /* Grab will be set when running from gizmo. */ vpd->own_cursor = (win->grabcursor == 0); if (vpd->own_cursor) { - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } vpd->origx = event->x; @@ -671,7 +692,12 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot) } #ifdef WITH_INPUT_NDOF -/********************** NDOF operator *********************/ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name NDOF Operator + * \{ */ /* Combined pan/zoom from a 3D mouse device. * Z zooms, XY pans @@ -721,9 +747,14 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; } + +/** \} */ + #endif /* WITH_INPUT_NDOF */ -/********************** view all operator *********************/ +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * \{ */ /* Updates the fields of the View2D member of the SpaceImage struct. * Default behavior is to reset the position of the image and set the zoom to 1 @@ -800,7 +831,41 @@ void IMAGE_OT_view_all(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/********************** view selected operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Center View To Cursor Operator + * \{ */ + +static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceImage *sima = CTX_wm_space_image(C); + ARegion *ar = CTX_wm_region(C); + + ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]); + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void IMAGE_OT_view_center_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Center View to Cursor"; + ot->description = "Center the view so that the cursor is in the middle of the view"; + ot->idname = "IMAGE_OT_view_center_cursor"; + + /* api callbacks */ + ot->exec = view_center_cursor_exec; + ot->poll = ED_space_image_cursor_poll; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Selected Operator + * \{ */ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -866,7 +931,11 @@ void IMAGE_OT_view_selected(wmOperatorType *ot) ot->poll = image_view_selected_poll; } -/********************** view zoom in/out operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom In/Out Operator + * \{ */ static int image_view_zoom_in_exec(bContext *C, wmOperator *op) { @@ -984,7 +1053,11 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/********************** view zoom ratio operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Ratio Operator + * \{ */ static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op) { @@ -1028,7 +1101,11 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot) FLT_MAX); } -/********************** view border-zoom operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Border-Zoom Operator + * \{ */ static int image_view_zoom_border_exec(bContext *C, wmOperator *op) { @@ -1084,14 +1161,18 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot) WM_operator_properties_gesture_box_zoom(ot); } -/**************** load/replace/save callbacks ******************/ +/* load/replace/save callbacks */ static void image_filesel(bContext *C, wmOperator *op, const char *path) { RNA_string_set(op->ptr, "filepath", path); WM_event_add_fileselect(C, op); } -/******************** open image operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Open Image Operator + * \{ */ typedef struct ImageOpenData { PropertyPointerRNA pprop; @@ -1525,7 +1606,12 @@ void IMAGE_OT_open(wmOperatorType *ot) "Automatically detect animated sequences in selected images (based on file names)"); } -/******************** Match movie length operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Match Movie Length Operator + * \{ */ + static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -1571,7 +1657,11 @@ void IMAGE_OT_match_movie_length(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */; } -/******************** replace image operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Replace Image Operator + * \{ */ static int image_replace_exec(bContext *C, wmOperator *op) { @@ -1656,7 +1746,11 @@ void IMAGE_OT_replace(wmOperatorType *ot) FILE_SORT_ALPHA); } -/******************** save image as operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Save Image As Operator + * \{ */ static char imtype_best_depth(ImBuf *ibuf, const char imtype) { @@ -1970,7 +2064,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) static bool image_save_as_poll(bContext *C) { - if (!image_buffer_exists_from_context(C)) { + if (!image_from_context_has_data_poll(C)) { return false; } @@ -2021,12 +2115,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); } -/******************** save image operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Save Image Operator + * \{ */ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser) { @@ -2067,7 +2165,7 @@ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser) static bool image_save_poll(bContext *C) { /* Can't save if there are no pixels. */ - if (image_buffer_exists_from_context(C) == false) { + if (image_from_context_has_data_poll(C) == false) { return false; } @@ -2147,7 +2245,11 @@ void IMAGE_OT_save(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/******************* save sequence operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Save Sequence Operator + * \{ */ static int image_save_sequence_exec(bContext *C, wmOperator *op) { @@ -2233,13 +2335,17 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) /* api callbacks */ ot->exec = image_save_sequence_exec; - ot->poll = image_buffer_exists_from_context; + ot->poll = image_from_context_has_data_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/********************** save all operator **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Save All Operator + * \{ */ static bool image_should_be_saved_when_modified(Image *ima) { @@ -2389,7 +2495,11 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/******************** reload image operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reload Image Operator + * \{ */ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2426,7 +2536,12 @@ void IMAGE_OT_reload(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */ } -/********************** new image operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name New Image Operator + * \{ */ + #define IMA_DEF_NAME N_("Untitled") enum { @@ -2642,22 +2757,18 @@ void IMAGE_OT_new(wmOperatorType *ot) #undef IMA_DEF_NAME -/********************* invert operators *********************/ - -static bool image_invert_poll(bContext *C) -{ - Image *ima = image_from_context(C); +/** \} */ - return BKE_image_has_ibuf(ima, NULL); -} +/* -------------------------------------------------------------------- */ +/** \name Invert Operators + * \{ */ static int image_invert_exec(bContext *C, wmOperator *op) { Image *ima = image_from_context(C); ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); SpaceImage *sima = CTX_wm_space_image(C); - /* undo is supported only on image paint mode currently */ - bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); + const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); /* flags indicate if this channel should be inverted */ const bool r = RNA_boolean_get(op->ptr, "invert_r"); @@ -2672,14 +2783,12 @@ static int image_invert_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (support_undo) { - ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); - /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles - * but better do this right in case someone copies this for a tool that uses partial - * redraw better */ + ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf); + + if (is_paint) { ED_imapaint_clear_partial_redraw(); - ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false); } + /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */ if (ibuf->rect_float) { @@ -2733,9 +2842,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) ibuf->userflags |= IB_MIPMAP_INVALID; } - if (support_undo) { - ED_image_undo_push_end(); - } + ED_image_undo_push_end(); /* force GPU reupload, all image is invalid */ GPU_free_image(ima); @@ -2758,7 +2865,7 @@ void IMAGE_OT_invert(wmOperatorType *ot) /* api callbacks */ ot->exec = image_invert_exec; - ot->poll = image_invert_poll; + ot->poll = image_from_contect_has_data_poll_no_image_user; /* properties */ prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel"); @@ -2771,10 +2878,96 @@ void IMAGE_OT_invert(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Scale Operator + * \{ */ + +static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Image *ima = image_from_context(C); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size"); + if (!RNA_property_is_set(op->ptr, prop)) { + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + const int size[2] = {ibuf->x, ibuf->y}; + RNA_property_int_set_array(op->ptr, prop, size); + BKE_image_release_ibuf(ima, ibuf, NULL); + } + return WM_operator_props_dialog_popup(C, op, 200, 200); +} + +static int image_scale_exec(bContext *C, wmOperator *op) +{ + Image *ima = image_from_context(C); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + SpaceImage *sima = CTX_wm_space_image(C); + const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT)); + + if (ibuf == NULL) { + /* TODO: this should actually never happen, but does for render-results -> cleanup */ + return OPERATOR_CANCELLED; + } + + if (is_paint) { + ED_imapaint_clear_partial_redraw(); + } + + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size"); + int size[2]; + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_int_get_array(op->ptr, prop, size); + } + else { + size[0] = ibuf->x; + size[1] = ibuf->y; + RNA_property_int_set_array(op->ptr, prop, size); + } + + ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + IMB_scaleImBuf(ibuf, size[0], size[1]); + BKE_image_release_ibuf(ima, ibuf, NULL); + + ED_image_undo_push_end(); + + /* force GPU reupload, all image is invalid */ + GPU_free_image(ima); + + DEG_id_tag_update(&ima->id, 0); + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); + + return OPERATOR_FINISHED; } -/********************* pack operator *********************/ +void IMAGE_OT_resize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Resize Image"; + ot->idname = "IMAGE_OT_resize"; + ot->description = "Resize the image"; + + /* api callbacks */ + ot->invoke = image_scale_invoke; + ot->exec = image_scale_exec; + ot->poll = image_from_contect_has_data_poll_no_image_user; + + /* properties */ + RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX); + + /* flags */ + ot->flag = OPTYPE_REGISTER; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Pack Operator + * \{ */ static bool image_pack_test(bContext *C, wmOperator *op) { @@ -2827,7 +3020,11 @@ void IMAGE_OT_pack(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/********************* unpack operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Unpack Operator + * \{ */ static int image_unpack_exec(bContext *C, wmOperator *op) { @@ -2926,7 +3123,11 @@ void IMAGE_OT_unpack(wmOperatorType *ot) ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack"); } -/******************** sample image operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Image Operator + * \{ */ typedef struct ImageSampleInfo { ARegionType *art; @@ -3339,7 +3540,12 @@ void IMAGE_OT_sample(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/******************** sample line operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Line Operator + * \{ */ + static int image_sample_line_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); @@ -3421,10 +3627,14 @@ void IMAGE_OT_sample_line(wmOperatorType *ot) /* flags */ ot->flag = 0; /* no undo/register since this operates on the space */ - WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); + WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT); } -/******************** set curve point operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Curve Point Operator + * \{ */ void IMAGE_OT_curves_point_set(wmOperatorType *ot) { @@ -3458,7 +3668,11 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/********************* cycle render slot operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cycle Render Slot Operator + * \{ */ static bool image_cycle_render_slot_poll(bContext *C) { @@ -3504,7 +3718,11 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot) RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", ""); } -/********************* clear render slot operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Render Slot Operator + * \{ */ static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3535,7 +3753,11 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } -/********************* add render slot operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Render Slot Operator + * \{ */ static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3564,7 +3786,11 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } -/********************* remove render slot operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Render Slot Operator + * \{ */ static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3595,7 +3821,11 @@ void IMAGE_OT_remove_render_slot(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } -/********************** change frame operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Change Frame Operator + * \{ */ static bool change_frame_poll(bContext *C) { @@ -3746,7 +3976,11 @@ void IMAGE_OT_read_viewlayers(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Render Border Operator + * \{ */ static int render_border_exec(bContext *C, wmOperator *op) { @@ -3815,7 +4049,11 @@ void IMAGE_OT_render_border(wmOperatorType *ot) WM_operator_properties_border(ot); } -/* ********************* Clear render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Render Border Operator + * \{ */ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3840,3 +4078,5 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c new file mode 100644 index 00000000000..577c4e24b11 --- /dev/null +++ b/source/blender/editors/space_image/image_undo.c @@ -0,0 +1,1058 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spimage + * + * Overview + * ======== + * + * - Each undo step is a #ImageUndoStep + * - Each #ImageUndoStep stores a list of #UndoImageHandle + * - Each #UndoImageHandle stores a list of #UndoImageBuf + * (this is the undo systems equivalent of an #ImBuf). + * - Each #UndoImageBuf stores an array of #UndoImageTile + * The tiles are shared between #UndoImageBuf's to avoid duplication. + * + * When the undo system manages an image, there will always be a full copy (as a #UndoImageBuf) + * each new undo step only stores modified tiles. + */ + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_threads.h" + +#include "DNA_image_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_paint.h" +#include "BKE_undo_system.h" + +#include "DEG_depsgraph.h" + +#include "ED_paint.h" +#include "ED_undo.h" +#include "ED_util.h" +#include "ED_object.h" + +#include "GPU_draw.h" + +#include "WM_api.h" + +static CLG_LogRef LOG = {"ed.image.undo"}; + +/* -------------------------------------------------------------------- */ +/** \name Thread Locking + * \{ */ + +/* This is a non-global static resource, + * Maybe it should be exposed as part of the + * paint operation, but for now just give a public interface */ +static SpinLock paint_tiles_lock; + +void ED_image_paint_tile_lock_init(void) +{ + BLI_spin_init(&paint_tiles_lock); +} + +void ED_image_paint_tile_lock_end(void) +{ + BLI_spin_end(&paint_tiles_lock); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paint Tiles + * + * Created on demand while painting, + * use to access the previous state for some paint operations. + * + * These buffers are also used for undo when available. + * + * \{ */ + +static ImBuf *imbuf_alloc_temp_tile(void) +{ + return IMB_allocImBuf( + ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect); +} + +typedef struct PaintTile { + struct PaintTile *next, *prev; + Image *image; + ImBuf *ibuf; + union { + float *fp; + uint *uint; + void *pt; + } rect; + ushort *mask; + bool valid; + bool use_float; + int x, y; +} PaintTile; + +static void ptile_free(PaintTile *ptile) +{ + if (ptile->rect.pt) { + MEM_freeN(ptile->rect.pt); + } + if (ptile->mask) { + MEM_freeN(ptile->mask); + } + MEM_freeN(ptile); +} + +static void ptile_free_list(ListBase *paint_tiles) +{ + for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) { + ptile_next = ptile->next; + ptile_free(ptile); + } + BLI_listbase_clear(paint_tiles); +} + +static void ptile_invalidate_list(ListBase *paint_tiles) +{ + for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) { + ptile->valid = false; + } +} + +void *ED_image_paint_tile_find(ListBase *paint_tiles, + Image *image, + ImBuf *ibuf, + int x_tile, + int y_tile, + ushort **r_mask, + bool validate) +{ + for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) { + if (ptile->x == x_tile && ptile->y == y_tile) { + if (ptile->image == image && ptile->ibuf == ibuf) { + if (r_mask) { + /* allocate mask if requested. */ + if (!ptile->mask) { + ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), + "UndoImageTile.mask"); + } + *r_mask = ptile->mask; + } + if (validate) { + ptile->valid = true; + } + return ptile->rect.pt; + } + } + } + return NULL; +} + +void *ED_image_paint_tile_push(ListBase *paint_tiles, + Image *image, + ImBuf *ibuf, + ImBuf **tmpibuf, + int x_tile, + int y_tile, + ushort **r_mask, + bool **r_valid, + bool use_thread_lock, + bool find_prev) +{ + const bool has_float = (ibuf->rect_float != NULL); + + /* check if tile is already pushed */ + + /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ + if (find_prev) { + void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true); + if (data) { + return data; + } + } + + if (*tmpibuf == NULL) { + *tmpibuf = imbuf_alloc_temp_tile(); + } + + PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile"); + + ptile->image = image; + ptile->ibuf = ibuf; + + ptile->x = x_tile; + ptile->y = y_tile; + + /* add mask explicitly here */ + if (r_mask) { + *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), + "PaintTile.mask"); + } + + ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) * + SQUARE(ED_IMAGE_UNDO_TILE_SIZE), + "PaintTile.rect"); + + ptile->use_float = has_float; + ptile->valid = true; + + if (r_valid) { + *r_valid = &ptile->valid; + } + + IMB_rectcpy(*tmpibuf, + ibuf, + 0, + 0, + x_tile * ED_IMAGE_UNDO_TILE_SIZE, + y_tile * ED_IMAGE_UNDO_TILE_SIZE, + ED_IMAGE_UNDO_TILE_SIZE, + ED_IMAGE_UNDO_TILE_SIZE); + + if (has_float) { + SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float); + } + else { + SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect); + } + + if (use_thread_lock) { + BLI_spin_lock(&paint_tiles_lock); + } + BLI_addtail(paint_tiles, ptile); + + if (use_thread_lock) { + BLI_spin_unlock(&paint_tiles_lock); + } + return ptile->rect.pt; +} + +static void ptile_restore_runtime_list(ListBase *paint_tiles) +{ + ImBuf *tmpibuf = imbuf_alloc_temp_tile(); + + for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) { + Image *image = ptile->image; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + const bool has_float = (ibuf->rect_float != NULL); + + if (has_float) { + SWAP(float *, ptile->rect.fp, tmpibuf->rect_float); + } + else { + SWAP(uint *, ptile->rect.uint, tmpibuf->rect); + } + + IMB_rectcpy( + ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE); + + if (has_float) { + SWAP(float *, ptile->rect.fp, tmpibuf->rect_float); + } + else { + SWAP(uint *, ptile->rect.uint, tmpibuf->rect); + } + + GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */ + if (ibuf->rect_float) { + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + } + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */ + } + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + BKE_image_release_ibuf(image, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image Undo Tile + * \{ */ + +static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2]) +{ + BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]); + return (tile_y * tiles_dims[0]) + tile_x; +} + +typedef struct UndoImageTile { + union { + float *fp; + uint *uint; + void *pt; + } rect; + int users; +} UndoImageTile; + +static UndoImageTile *utile_alloc(bool has_float) +{ + UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile"); + if (has_float) { + utile->rect.fp = MEM_mallocN(sizeof(float[4]) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__); + } + else { + utile->rect.uint = MEM_mallocN(sizeof(uint) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__); + } + return utile; +} + +static void utile_init_from_imbuf( + UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf) +{ + const bool has_float = ibuf->rect_float; + + if (has_float) { + SWAP(float *, utile->rect.fp, tmpibuf->rect_float); + } + else { + SWAP(uint *, utile->rect.uint, tmpibuf->rect); + } + + IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE); + + if (has_float) { + SWAP(float *, utile->rect.fp, tmpibuf->rect_float); + } + else { + SWAP(uint *, utile->rect.uint, tmpibuf->rect); + } +} + +static void utile_restore( + const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf) +{ + const bool has_float = ibuf->rect_float; + float *prev_rect_float = tmpibuf->rect_float; + uint *prev_rect = tmpibuf->rect; + + if (has_float) { + tmpibuf->rect_float = utile->rect.fp; + } + else { + tmpibuf->rect = utile->rect.uint; + } + + IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE); + + tmpibuf->rect_float = prev_rect_float; + tmpibuf->rect = prev_rect; +} + +static void utile_decref(UndoImageTile *utile) +{ + utile->users -= 1; + BLI_assert(utile->users >= 0); + if (utile->users == 0) { + MEM_freeN(utile->rect.pt); + MEM_freeN(utile); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image Undo Buffer + * \{ */ + +typedef struct UndoImageBuf { + struct UndoImageBuf *next, *prev; + + /** + * The buffer after the undo step has executed. + */ + struct UndoImageBuf *post; + + char ibuf_name[IMB_FILENAME_SIZE]; + + UndoImageTile **tiles; + + /** Can calculate these from dims, just for convenience. */ + uint tiles_len; + uint tiles_dims[2]; + + uint image_dims[2]; + + /** Store variables from the image. */ + struct { + short source; + bool use_float; + char gen_type; + } image_state; + +} UndoImageBuf; + +static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf) +{ + UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__); + + ubuf->image_dims[0] = ibuf->x; + ubuf->image_dims[1] = ibuf->y; + + ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]); + ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]); + + ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1]; + ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__); + + BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name)); + ubuf->image_state.gen_type = image->gen_type; + ubuf->image_state.source = image->source; + ubuf->image_state.use_float = ibuf->rect_float != NULL; + + return ubuf; +} + +static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf) +{ + ImBuf *tmpibuf = imbuf_alloc_temp_tile(); + + const bool has_float = ibuf->rect_float; + int i = 0; + for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) { + uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS; + for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) { + uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS; + + BLI_assert(ubuf->tiles[i] == NULL); + UndoImageTile *utile = utile_alloc(has_float); + utile->users = 1; + utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf); + ubuf->tiles[i] = utile; + + i += 1; + } + } + + IMB_freeImBuf(tmpibuf); +} + +/** Ensure we can copy the ubuf into the ibuf. */ +static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf) +{ + /* We could have both float and rect buffers, + * in this case free the float buffer if it's unused. */ + if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) { + imb_freerectfloatImBuf(ibuf); + } + + if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] && + (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) { + return; + } + + imb_freerectImbuf_all(ibuf); + IMB_rect_size_set(ibuf, ubuf->image_dims); + + if (ubuf->image_state.use_float) { + imb_addrectfloatImBuf(ibuf); + } + else { + imb_addrectImBuf(ibuf); + } +} + +static void ubuf_free(UndoImageBuf *ubuf) +{ + UndoImageBuf *ubuf_post = ubuf->post; + for (uint i = 0; i < ubuf->tiles_len; i++) { + UndoImageTile *utile = ubuf->tiles[i]; + utile_decref(utile); + } + MEM_freeN(ubuf->tiles); + MEM_freeN(ubuf); + if (ubuf_post) { + ubuf_free(ubuf_post); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image Undo Handle + * \{ */ + +typedef struct UndoImageHandle { + struct UndoImageHandle *next, *prev; + + /** Each undo handle refers to a single image which may have multiple buffers. */ + UndoRefID_Image image_ref; + + /** + * List of #UndoImageBuf's to support multiple buffers per image. + * + * \note To properly support multiple buffers per image + * we would need to store an #ImageUser for each #UndoImageBuf. + * since when restoring the image we use: + * `BKE_image_acquire_ibuf(image, NULL, NULL)`. + */ + ListBase buffers; + +} UndoImageHandle; + +static void uhandle_restore_list(ListBase *undo_handles, bool use_init) +{ + ImBuf *tmpibuf = imbuf_alloc_temp_tile(); + + for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) { + /* Tiles only added to second set of tiles. */ + Image *image = uh->image_ref.ptr; + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + if (UNLIKELY(ibuf == NULL)) { + CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2); + continue; + } + bool changed = false; + for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) { + UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post; + ubuf_ensure_compat_ibuf(ubuf, ibuf); + + int i = 0; + for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) { + uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS; + for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) { + uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS; + utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf); + changed = true; + i += 1; + } + } + } + + if (changed) { + BKE_image_mark_dirty(image, ibuf); + GPU_free_image(image); /* force OpenGL reload */ + + if (ibuf->rect_float) { + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + } + if (ibuf->mipmap[0]) { + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */ + } + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + DEG_id_tag_update(&image->id, 0); + } + BKE_image_release_ibuf(image, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + +static void uhandle_free_list(ListBase *undo_handles) +{ + LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) { + LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) { + ubuf_free(ubuf); + } + MEM_freeN(uh); + } + BLI_listbase_clear(undo_handles); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image Undo Internal Utilities + * \{ */ + +/** #UndoImageHandle utilities */ + +static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh, + const Image *UNUSED(image), + const char *ibuf_name) +{ + for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) { + if (STREQ(ubuf->ibuf_name, ibuf_name)) { + return ubuf; + } + } + return NULL; +} + +static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf) +{ + BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL); + UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf); + BLI_addtail(&uh->buffers, ubuf); + + ubuf->post = NULL; + + return ubuf; +} + +static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf) +{ + UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name); + if (ubuf == NULL) { + ubuf = uhandle_add_ubuf(uh, image, ibuf); + } + return ubuf; +} + +static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image) +{ + for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) { + if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) { + return uh; + } + } + return NULL; +} + +static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image) +{ + for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) { + if (image == uh->image_ref.ptr) { + return uh; + } + } + return NULL; +} + +static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image) +{ + BLI_assert(uhandle_lookup(undo_handles, image) == NULL); + UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__); + uh->image_ref.ptr = image; + BLI_addtail(undo_handles, uh); + return uh; +} + +static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image) +{ + UndoImageHandle *uh = uhandle_lookup(undo_handles, image); + if (uh == NULL) { + uh = uhandle_add(undo_handles, image); + } + return uh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct ImageUndoStep { + UndoStep step; + + /** #UndoImageHandle */ + ListBase handles; + + /** + * #PaintTile + * Run-time only data (active during a paint stroke). + */ + ListBase paint_tiles; + + bool is_encode_init; + ePaintMode paint_mode; + +} ImageUndoStep; + +/** + * Find the previous undo buffer from this one. + * \note We could look into undo steps even further back. + */ +static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev, + const Image *image, + const UndoImageBuf *ubuf) +{ + /* Use name lookup because because the pointer is cleared for previous steps. */ + UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image); + if (uh_prev != NULL) { + UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name); + if (ubuf_reference) { + ubuf_reference = ubuf_reference->post; + if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) && + (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) { + return ubuf_reference; + } + } + } + return NULL; +} + +static bool image_undosys_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + ScrArea *sa = CTX_wm_area(C); + if (sa && (sa->spacetype == SPACE_IMAGE)) { + SpaceImage *sima = (SpaceImage *)sa->spacedata.first; + if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { + return true; + } + } + else { + if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) { + return true; + } + } + return false; +} + +static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + /* dummy, memory is cleared anyway. */ + us->is_encode_init = true; + BLI_listbase_clear(&us->handles); + BLI_listbase_clear(&us->paint_tiles); +} + +static bool image_undosys_step_encode(struct bContext *C, + struct Main *UNUSED(bmain), + UndoStep *us_p) +{ + /* Encoding is done along the way by adding tiles + * to the current 'ImageUndoStep' added by encode_init. + * + * This function ensures there are previous and current states of the image in the undo buffer. + */ + ImageUndoStep *us = (ImageUndoStep *)us_p; + + BLI_assert(us->step.data_size == 0); + + if (us->is_encode_init) { + + ImBuf *tmpibuf = imbuf_alloc_temp_tile(); + + ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active; + while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) { + us_reference = (ImageUndoStep *)us_reference->step.prev; + } + + /* Initialize undo tiles from ptiles (if they exist). */ + for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) { + if (ptile->valid) { + UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image); + UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf); + + UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile"); + utile->users = 1; + utile->rect.pt = ptile->rect.pt; + ptile->rect.pt = NULL; + const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims); + + BLI_assert(ubuf_pre->tiles[tile_index] == NULL); + ubuf_pre->tiles[tile_index] = utile; + } + ptile_next = ptile->next; + ptile_free(ptile); + } + BLI_listbase_clear(&us->paint_tiles); + + for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) { + for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) { + + ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL); + + const bool has_float = ibuf->rect_float; + + BLI_assert(ubuf_pre->post == NULL); + ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf); + UndoImageBuf *ubuf_post = ubuf_pre->post; + + if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] || + ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) { + ubuf_from_image_all_tiles(ubuf_post, ibuf); + } + else { + /* Search for the previous buffer. */ + UndoImageBuf *ubuf_reference = (us_reference ? + ubuf_lookup_from_reference( + us_reference, uh->image_ref.ptr, ubuf_post) : + NULL); + + int i = 0; + for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) { + uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS; + for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) { + uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS; + + if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) || + /* In this case the paint stroke as has added a tile + * which we have a duplicate reference available. */ + (ubuf_pre->tiles[i]->users == 1))) { + if (ubuf_pre->tiles[i] != NULL) { + /* If we have a reference, re-use this single use tile for the post state. */ + BLI_assert(ubuf_pre->tiles[i]->users == 1); + ubuf_post->tiles[i] = ubuf_pre->tiles[i]; + ubuf_pre->tiles[i] = NULL; + utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf); + } + else { + BLI_assert(ubuf_post->tiles[i] == NULL); + ubuf_post->tiles[i] = ubuf_reference->tiles[i]; + ubuf_post->tiles[i]->users += 1; + } + BLI_assert(ubuf_pre->tiles[i] == NULL); + ubuf_pre->tiles[i] = ubuf_reference->tiles[i]; + ubuf_pre->tiles[i]->users += 1; + + BLI_assert(ubuf_pre->tiles[i] != NULL); + BLI_assert(ubuf_post->tiles[i] != NULL); + } + else { + UndoImageTile *utile = utile_alloc(has_float); + utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf); + + if (ubuf_pre->tiles[i] != NULL) { + ubuf_post->tiles[i] = utile; + utile->users = 1; + } + else { + ubuf_pre->tiles[i] = utile; + ubuf_post->tiles[i] = utile; + utile->users = 2; + } + } + BLI_assert(ubuf_pre->tiles[i] != NULL); + BLI_assert(ubuf_post->tiles[i] != NULL); + i += 1; + } + } + } + BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL); + } + } + + IMB_freeImBuf(tmpibuf); + + /* Useful to debug tiles are stored correctly. */ + if (false) { + uhandle_restore_list(&us->handles, false); + } + } + else { + /* Happens when switching modes. */ + ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); + BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); + us->paint_mode = paint_mode; + } + + us_p->is_applied = true; + + return true; +} + +static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final) +{ + BLI_assert(us->step.is_applied == true); + uhandle_restore_list(&us->handles, !is_final); + us->step.is_applied = false; +} + +static void image_undosys_step_decode_redo_impl(ImageUndoStep *us) +{ + BLI_assert(us->step.is_applied == false); + uhandle_restore_list(&us->handles, false); + us->step.is_applied = true; +} + +static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final) +{ + ImageUndoStep *us_iter = us; + while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { + if (us_iter->step.next->is_applied == false) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.next; + } + while (us_iter != us || (!is_final && us_iter == us)) { + + image_undosys_step_decode_undo_impl(us_iter, is_final); + if (us_iter == us) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.prev; + } +} + +static void image_undosys_step_decode_redo(ImageUndoStep *us) +{ + ImageUndoStep *us_iter = us; + while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { + if (us_iter->step.prev->is_applied == true) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.prev; + } + while (us_iter && (us_iter->step.is_applied == false)) { + image_undosys_step_decode_redo_impl(us_iter); + if (us_iter == us) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.next; + } +} + +static void image_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + if (dir < 0) { + image_undosys_step_decode_undo(us, is_final); + } + else { + image_undosys_step_decode_redo(us); + } + + if (us->paint_mode == PAINT_MODE_TEXTURE_3D) { + ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT); + } + + /* Refresh texture slots. */ + ED_editors_init_for_undo(bmain); +} + +static void image_undosys_step_free(UndoStep *us_p) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + uhandle_free_list(&us->handles); + + /* Typically this list will have been cleared. */ + ptile_free_list(&us->paint_tiles); +} + +static void image_undosys_foreach_ID_ref(UndoStep *us_p, + UndoTypeForEachIDRefFn foreach_ID_ref_fn, + void *user_data) +{ + ImageUndoStep *us = (ImageUndoStep *)us_p; + for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) { + foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref)); + } +} + +/* Export for ED_undo_sys. */ +void ED_image_undosys_type(UndoType *ut) +{ + ut->name = "Image"; + ut->poll = image_undosys_poll; + ut->step_encode_init = image_undosys_step_encode_init; + ut->step_encode = image_undosys_step_encode; + ut->step_decode = image_undosys_step_decode; + ut->step_free = image_undosys_step_free; + + ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; + + ut->use_context = true; + + ut->step_size = sizeof(ImageUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +ListBase *ED_image_paint_tile_list_get(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + UndoStep *us_prev = ustack->step_init; + UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); + ImageUndoStep *us = (ImageUndoStep *)us_p; + /* We should always have an undo push started when accessing tiles, + * not doing this means we won't have paint_mode correctly set. */ + BLI_assert(us_p == us_prev); + if (us_p != us_prev) { + /* Fallback value until we can be sure this never happens. */ + us->paint_mode = PAINT_MODE_TEXTURE_2D; + } + return &us->paint_tiles; +} + +/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ +void ED_image_undo_restore(UndoStep *us) +{ + ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles; + ptile_restore_runtime_list(paint_tiles); + ptile_invalidate_list(paint_tiles); +} + +static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode) +{ + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); + ImageUndoStep *us = (ImageUndoStep *)us_p; + BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); + us->paint_mode = paint_mode; + return us; +} + +void ED_image_undo_push_begin(const char *name, int paint_mode) +{ + image_undo_push_begin(name, paint_mode); +} + +void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf) +{ + ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D); + + UndoImageHandle *uh = uhandle_ensure(&us->handles, image); + UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf); + BLI_assert(ubuf_pre->post == NULL); + + ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active; + while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) { + us_reference = (ImageUndoStep *)us_reference->step.prev; + } + UndoImageBuf *ubuf_reference = (us_reference ? + ubuf_lookup_from_reference(us_reference, image, ubuf_pre) : + NULL); + + if (ubuf_reference) { + memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len); + for (uint i = 0; i < ubuf_pre->tiles_len; i++) { + UndoImageTile *utile = ubuf_pre->tiles[i]; + utile->users += 1; + } + } + else { + ubuf_from_image_all_tiles(ubuf_pre, ibuf); + } +} + +void ED_image_undo_push_end(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); + WM_file_tag_modified(); +} + +/** \} */ diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 5fa4fe3e077..a88ecc91868 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -207,6 +207,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_view_all); WM_operatortype_append(IMAGE_OT_view_pan); WM_operatortype_append(IMAGE_OT_view_selected); + WM_operatortype_append(IMAGE_OT_view_center_cursor); WM_operatortype_append(IMAGE_OT_view_zoom); WM_operatortype_append(IMAGE_OT_view_zoom_in); WM_operatortype_append(IMAGE_OT_view_zoom_out); @@ -229,6 +230,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_unpack); WM_operatortype_append(IMAGE_OT_invert); + WM_operatortype_append(IMAGE_OT_resize); WM_operatortype_append(IMAGE_OT_cycle_render_slot); WM_operatortype_append(IMAGE_OT_clear_render_slot); diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 1abf1a64263..938e7f09881 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -597,13 +597,19 @@ void NLA_OT_select_leftright(wmOperatorType *ot) /* ******************** Mouse-Click Select Operator *********************** */ /* select strip directly under mouse */ -static void mouse_nla_strips( - bContext *C, bAnimContext *ac, const int mval[2], short select_mode, const bool deselect_all) +static int mouse_nla_strips(bContext *C, + bAnimContext *ac, + const int mval[2], + short select_mode, + const bool deselect_all, + bool wait_to_deselect_others) { Scene *scene = ac->scene; bAnimListElem *ale = NULL; NlaStrip *strip = NULL; + int ret_value = OPERATOR_FINISHED; + nlaedit_strip_at_region_position(ac, mval[0], mval[1], &ale, &strip); /* if currently in tweakmode, exit tweakmode before changing selection states @@ -613,6 +619,10 @@ static void mouse_nla_strips( WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL); } + if (select_mode != SELECT_REPLACE) { + wait_to_deselect_others = false; + } + /* For replacing selection, if we have something to select, we have to clear existing selection. * The same goes if we found nothing to select, and deselect_all is true * (deselect on nothing behavior). */ @@ -620,11 +630,16 @@ static void mouse_nla_strips( /* reset selection mode for next steps */ select_mode = SELECT_ADD; - /* deselect all strips */ - deselect_nla_strips(ac, 0, SELECT_SUBTRACT); + if (strip && wait_to_deselect_others && (strip->flag & DESELECT_STRIPS_CLEARACTIVE)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + /* deselect all strips */ + deselect_nla_strips(ac, 0, SELECT_SUBTRACT); - /* deselect all other channels first */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + /* deselect all other channels first */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + } } /* only select strip if we clicked on a valid channel and hit something */ @@ -658,14 +673,17 @@ static void mouse_nla_strips( /* free this channel */ MEM_freeN(ale); } + + return ret_value; } /* ------------------- */ /* handle clicking */ -static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int nlaedit_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + int ret_value; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) { @@ -675,15 +693,19 @@ static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent /* select mode is either replace (deselect all, then add) or add/extend */ const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE; const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); /* select strips based upon mouse position */ - mouse_nla_strips(C, &ac, event->mval, selectmode, deselect_all); + ret_value = mouse_nla_strips(C, &ac, mval, selectmode, deselect_all, wait_to_deselect_others); /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL); /* for tweak grab to work */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value | OPERATOR_PASS_THROUGH; } void NLA_OT_click_select(wmOperatorType *ot) @@ -695,14 +717,17 @@ void NLA_OT_click_select(wmOperatorType *ot) ot->idname = "NLA_OT_click_select"; ot->description = "Handle clicks to select NLA Strips"; - /* api callbacks - absolutely no exec() this yet... */ - ot->invoke = nlaedit_clickselect_invoke; + /* callbacks */ ot->poll = ED_operator_nla_active; + ot->exec = nlaedit_clickselect_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; /* flags */ ot->flag = OPTYPE_UNDO; /* properties */ + WM_operator_properties_generic_select(ot); prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 93121a6bef9..a5b18ff7589 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -47,6 +47,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" +#include "GPU_platform.h" #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" @@ -815,51 +816,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) { - PointerRNA imaptr = RNA_pointer_get(ptr, "image"); PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); - Image *ima = imaptr.data; - - uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, - C, - ptr, - "image", - "IMAGE_OT_new", - "IMAGE_OT_open", - NULL, - UI_TEMPLATE_ID_FILTER_ALL, - false); - - if (!ima) { - return; - } - - uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE); - - if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) { - uiLayout *row = uiLayoutRow(layout, true); - const bool is_packed = BKE_image_has_packedfile(ima); - - if (is_packed) { - uiItemO(row, "", ICON_PACKAGE, "image.unpack"); - } - else { - uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); - } - - row = uiLayoutRow(row, true); - uiLayoutSetEnabled(row, !is_packed); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); - uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); - } - - /* multilayer? */ - if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { - uiTemplateImageLayers(layout, C, ima, iuserptr.data); - } - else if (ima->source != IMA_SRC_GENERATED) { - uiTemplateImageInfo(layout, C, ima, iuserptr.data); - } + uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 01a30f677a3..664349b3c3b 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -309,7 +309,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot) prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); /* internal */ - RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); + RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } /* ****************** Add File Node Operator ******************* */ diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 770e6dd2a9e..2081c69a1a4 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1456,16 +1456,16 @@ static void node_draw_hidden(const bContext *C, int node_get_resize_cursor(int directions) { if (directions == 0) { - return CURSOR_STD; + return WM_CURSOR_DEFAULT; } else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) { - return CURSOR_Y_MOVE; + return WM_CURSOR_Y_MOVE; } else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) { - return CURSOR_X_MOVE; + return WM_CURSOR_X_MOVE; } else { - return CURSOR_EDIT; + return WM_CURSOR_EDIT; } } @@ -1474,7 +1474,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]) bNodeTree *ntree = snode->edittree; bNode *node; bNodeSocket *sock; - int wmcursor = CURSOR_STD; + int wmcursor = WM_CURSOR_DEFAULT; if (ntree) { if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) { diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 588fc4d4307..5d020ff5ab4 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -241,6 +241,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) node->flag |= NODE_SELECT; } + bNodeLink *glinks_first = ntree->links.last; + /* Add internal links to the ntree */ for (link = wgroup->links.first; link; link = linkn) { linkn = link->next; @@ -248,6 +250,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) BLI_addtail(&ntree->links, link); } + bNodeLink *glinks_last = ntree->links.last; + /* and copy across the animation, * note that the animation data's action can be NULL here */ if (wgroup->adt) { @@ -280,70 +284,64 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) BKE_id_free(bmain, wgroup); /* restore external links to and from the gnode */ - /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node), - * then transferred to ntree (new_node pointers remain valid). - */ /* input links */ - for (link = ngroup->links.first; link; link = link->next) { - if (link->fromnode->type == NODE_GROUP_INPUT) { - const char *identifier = link->fromsock->identifier; - int num_external_links = 0; - - /* find external links to this input */ - for (tlink = ntree->links.first; tlink; tlink = tlink->next) { - if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, - tlink->fromnode, - tlink->fromsock, - link->tonode->new_node, - link->tosock->new_sock); - num_external_links++; + if (glinks_first != NULL) { + for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + if (link->fromnode->type == NODE_GROUP_INPUT) { + const char *identifier = link->fromsock->identifier; + int num_external_links = 0; + + /* find external links to this input */ + for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); + num_external_links++; + } } - } - /* if group output is not externally linked, - * convert the constant input value to ensure somewhat consistent behavior */ - if (num_external_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); - BLI_assert(sock);*/ + /* if group output is not externally linked, + * convert the constant input value to ensure somewhat consistent behavior */ + if (num_external_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); + BLI_assert(sock);*/ - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, - * ntree, sock, gnode);*/ + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, + * ntree, sock, gnode);*/ + } } } - } - /* output links */ - for (link = ntree->links.first; link; link = link->next) { - if (link->fromnode == gnode) { - const char *identifier = link->fromsock->identifier; - int num_internal_links = 0; - - /* find internal links to this output */ - for (tlink = ngroup->links.first; tlink; tlink = tlink->next) { - /* only use active output node */ - if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { - if (STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, - tlink->fromnode->new_node, - tlink->fromsock->new_sock, - link->tonode, - link->tosock); - num_internal_links++; + /* Also iterate over new links to cover passthrough links. */ + glinks_last = ntree->links.last; + + /* output links */ + for (link = ntree->links.first; link != glinks_first->next; link = link->next) { + if (link->fromnode == gnode) { + const char *identifier = link->fromsock->identifier; + int num_internal_links = 0; + + /* find internal links to this output */ + for (tlink = glinks_first->next; tlink != glinks_last->next; tlink = tlink->next) { + /* only use active output node */ + if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { + if (STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); + num_internal_links++; + } } } - } - /* if group output is not internally linked, - * convert the constant output value to ensure somewhat consistent behavior */ - if (num_internal_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); - BLI_assert(sock);*/ + /* if group output is not internally linked, + * convert the constant output value to ensure somewhat consistent behavior */ + if (num_internal_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); + BLI_assert(sock);*/ - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + } } } } @@ -717,7 +715,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, ListBase anim_basepaths = {NULL, NULL}; float min[2], max[2], center[2]; int totselect; - bool expose_all = false; + bool expose_visible = false; bNode *input_node, *output_node; /* XXX rough guess, not nice but we don't have access to UI constants here ... */ @@ -735,7 +733,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, /* auto-add interface for "solo" nodes */ if (totselect == 1) { - expose_all = true; + expose_visible = true; } /* move nodes over */ @@ -879,8 +877,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, } } - /* expose all unlinked sockets too */ - if (expose_all) { + /* expose all unlinked sockets too but only the visible ones*/ + if (expose_visible) { for (node = ngroup->nodes.first; node; node = node->next) { if (node_group_make_use_node(node, gnode)) { for (sock = node->inputs.first; sock; sock = sock->next) { @@ -892,6 +890,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, break; } } + if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { + skip = true; + } if (skip) { continue; } @@ -913,6 +914,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, skip = true; } } + if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { + skip = true; + } if (skip) { continue; } diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index eef3f85319c..357ef31c51f 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -1103,7 +1103,7 @@ void NODE_OT_links_cut(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); /* internal */ - RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); + RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } /* ********************** Detach links operator ***************** */ diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 450cf28cce1..e22ef389516 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -430,11 +430,9 @@ void node_select_single(bContext *C, bNode *node) } static int node_mouse_select(bContext *C, + wmOperator *op, const int mval[2], - const bool extend, - const bool socket_select, - const bool deselect_all, - const bool wait_to_deselect_others) + bool wait_to_deselect_others) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -445,8 +443,15 @@ static int node_mouse_select(bContext *C, float cursor[2]; int ret_value = OPERATOR_CANCELLED; - /* Waiting to deselect others is only allowed for basic selection. */ - BLI_assert(!(extend || socket_select) || !wait_to_deselect_others); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + /* always do socket_select when extending selection. */ + const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select"); + const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + + /* These cases are never modal. */ + if (extend || socket_select) { + wait_to_deselect_others = false; + } /* get mouse coordinates in view2d space */ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); @@ -552,115 +557,40 @@ static int node_mouse_select(bContext *C, static int node_select_exec(bContext *C, wmOperator *op) { - int mval[2]; + const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); /* get settings from RNA properties for operator */ + int mval[2]; mval[0] = RNA_int_get(op->ptr, "mouse_x"); mval[1] = RNA_int_get(op->ptr, "mouse_y"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - /* always do socket_select when extending selection. */ - const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select"); - const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - /* perform the select */ - const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); + const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others); /* allow tweak event to work too */ return ret_value | OPERATOR_PASS_THROUGH; } -static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - const short init_event_type = (short)POINTER_AS_INT(op->customdata); - - /* get settings from RNA properties for operator */ - int mval[2]; - mval[0] = RNA_int_get(op->ptr, "mouse_x"); - mval[1] = RNA_int_get(op->ptr, "mouse_y"); - - const bool extend = RNA_boolean_get(op->ptr, "extend"); - /* always do socket_select when extending selection. */ - const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select"); - const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - - /* These cases are never modal. */ - if (extend || socket_select) { - return node_select_exec(C, op); - } - - if (init_event_type == 0) { - if (event->val == KM_PRESS) { - const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true); - - op->customdata = POINTER_FROM_INT((int)event->type); - if (ret_value & OPERATOR_RUNNING_MODAL) { - WM_event_add_modal_handler(C, op); - } - return ret_value | OPERATOR_PASS_THROUGH; - } - else { - /* If we are in init phase, and cannot validate init of modal operations, - * just fall back to basic exec. - */ - return node_select_exec(C, op); - } - } - else if (event->type == init_event_type && event->val == KM_RELEASE) { - const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); - return ret_value | OPERATOR_PASS_THROUGH; - } - else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - const int drag_delta[2] = { - mval[0] - event->mval[0], - mval[1] - event->mval[1], - }; - /* If user moves mouse more than defined threshold, we consider select operator as - * finished. Otherwise, it is still running until we get an 'release' event. In any - * case, we pass through event, but select op is not finished yet. */ - if (WM_event_drag_test_with_delta(event, drag_delta)) { - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; - } - else { - /* Important not to return anything other than PASS_THROUGH here, - * otherwise it prevents underlying tweak detection code to work properly. */ - return OPERATOR_PASS_THROUGH; - } - } - - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; -} - -static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - RNA_int_set(op->ptr, "mouse_x", event->mval[0]); - RNA_int_set(op->ptr, "mouse_y", event->mval[1]); - - op->customdata = POINTER_FROM_INT(0); - - return node_select_modal(C, op, event); -} - void NODE_OT_select(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Select"; ot->idname = "NODE_OT_select"; ot->description = "Select the node under the cursor"; /* api callbacks */ - ot->invoke = node_select_invoke; ot->exec = node_select_exec; - ot->modal = node_select_modal; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; ot->poll = ED_operator_node_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - PropertyRNA *prop; - RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); + WM_operator_properties_generic_select(ot); RNA_def_boolean(ot->srna, "extend", false, "Extend", ""); RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", ""); prop = RNA_def_boolean(ot->srna, diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 309446db83b..03606282fcd 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -965,7 +965,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); if (extend) { - BKE_layer_collection_isolate(scene, view_layer, layer_collection, true); + BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true); } else { PointerRNA ptr; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index a2ca3254b30..3b86e04308e 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2419,7 +2419,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case OB_GPENCIL: data.icon = ICON_OUTLINER_OB_GREASEPENCIL; break; - break; } } else { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 943993cb810..c55140db46f 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -674,7 +674,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Outliner ID data Remap"; + ot->name = "Outliner ID Data Remap"; ot->idname = "OUTLINER_OT_id_remap"; /* callbacks */ @@ -770,7 +770,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_save(bmain, str, op->reports); - BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); return OPERATOR_FINISHED; } @@ -804,7 +804,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); - BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted); + BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted); return OPERATOR_FINISHED; } @@ -2257,7 +2257,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op) BKE_id_multi_tagged_delete(bmain); - BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]); + BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", num_tagged[INDEX_ID_NULL]); /* XXX: tree management normally happens from draw_outliner(), but when * you're clicking to fast on Delete object from context menu in diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 44e67fa1508..f1e884adc3d 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -263,7 +263,8 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, for (base = FIRSTBASE(view_layer); base; base = base->next) { Object *ob = base->object; - if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { + if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) && + BKE_object_is_child_recursive(ob_parent, ob))) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); } } @@ -1198,7 +1199,7 @@ static void do_outliner_item_activate_tree_element(bContext *C, Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); if ((ob != NULL) && (ob->data == tselem->id)) { Base *base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { do_outliner_activate_obdata(C, scene, view_layer, base, extend); } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index fd6a052b84d..7f7cfff12ef 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1365,7 +1365,7 @@ static void outliner_add_layer_collection_objects( TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); te_object->directdata = base; - if (!(base->flag & BASE_VISIBLE)) { + if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) { te_object->flag |= TE_DISABLED; } } @@ -1398,7 +1398,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, tselem->flag &= ~TSE_CLOSED; } - if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { + if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) == 0) { ten->flag |= TE_DISABLED; } } @@ -2085,12 +2085,12 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { - if ((base->flag & BASE_VISIBLE) == 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { return false; } } else if (exclude_filter & SO_FILTER_OB_STATE_HIDDEN) { - if ((base->flag & BASE_VISIBLE) != 0) { + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) { return false; } } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 79880c68120..68eea4f278b 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -229,6 +229,11 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win), ED_region_tag_redraw(ar); } break; + case NC_TEXT: + if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) { + ED_region_tag_redraw(ar); + } + break; } } diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index 48248fe1dd2..2be05785d2b 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -106,6 +106,7 @@ static bool script_test_modal_operators(bContext *C) static int script_reload_exec(bContext *C, wmOperator *op) { + #ifdef WITH_PYTHON /* clear running operators */ @@ -114,6 +115,8 @@ static int script_reload_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + WM_script_tag_reload(); + /* TODO, this crashes on netrender and keying sets, need to look into why * disable for now unless running in debug mode */ WM_cursor_wait(1); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index b24f8e8d00f..8a15c05dd4a 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -336,7 +336,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) } seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ seq->scene = sce_seq; @@ -420,7 +420,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) } seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + seq->blend_mode = SEQ_TYPE_CROSS; seq->clip = clip; id_us_ensure_real(&seq->clip->id); @@ -504,7 +504,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) } seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + seq->blend_mode = SEQ_TYPE_CROSS; seq->mask = mask; id_us_ensure_real(&seq->mask->id); @@ -1091,8 +1091,14 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) if (seq->type == SEQ_TYPE_COLOR) { SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; RNA_float_get_array(op->ptr, "color", colvars->col); + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + } + else if (seq->type == SEQ_TYPE_ADJUSTMENT) { + seq->blend_mode = SEQ_TYPE_CROSS; + } + else if (seq->type == SEQ_TYPE_TEXT) { + seq->blend_mode = SEQ_TYPE_ALPHAOVER; } - seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* an unset channel is a special case where we automatically go above * the other strips. */ @@ -1169,7 +1175,7 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, - SEQ_TYPE_ALPHAOVER, + SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); RNA_def_float_vector(ot->srna, diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c index 6740c2baad2..7bec913900d 100644 --- a/source/blender/editors/space_sequencer/sequencer_buttons.c +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -117,5 +117,6 @@ void sequencer_buttons_register(ARegionType *art) pt->poll = metadata_panel_context_poll; pt->draw = metadata_panel_context_draw; pt->flag |= PNL_DEFAULT_CLOSED; + pt->order = 10; BLI_addtail(&art->paneltypes, pt); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index bf555e8fe09..1a788237e6e 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -334,7 +334,7 @@ static void drawseqwave(View2D *v2d, value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4]; } - if (fcu) { + if (fcu && !BKE_fcurve_is_empty(fcu)) { float evaltime = x1_offset + (i * stepsize); volume = evaluate_fcurve(fcu, evaltime); } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 22b73c32bfe..865dfb45278 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1600,6 +1600,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op) if (success) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); return OPERATOR_FINISHED; } else { @@ -1693,6 +1694,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even if (sa) { ED_area_status_text(sa, NULL); } + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; } @@ -3894,7 +3896,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, - SEQ_TYPE_ALPHAOVER, + SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); } diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index affb6d3fd88..4c20fc1707a 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -319,7 +319,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int sequencer_select_exec(bContext *C, wmOperator *op) { View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = CTX_data_scene(C); @@ -328,7 +328,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle"); const bool linked_time = RNA_boolean_get(op->ptr, "linked_time"); + bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others"); int left_right = RNA_enum_get(op->ptr, "left_right"); + int mval[2]; + int ret_value = OPERATOR_CANCELLED; + + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); Sequence *seq, *neighbor, *act_orig; int hand, sel_side; @@ -338,9 +344,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e return OPERATOR_CANCELLED; } + if (extend) { + wait_to_deselect_others = false; + } + marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now - seq = find_nearest_seq(scene, v2d, &hand, event->mval); + seq = find_nearest_seq(scene, v2d, &hand, mval); // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) { @@ -364,6 +374,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e /* deselect_markers(0, 0); */ marker->flag |= SELECT; } + + ret_value = OPERATOR_FINISHED; } else if (left_right != SEQ_SELECT_LR_NONE) { /* use different logic for this */ @@ -374,7 +386,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e switch (left_right) { case SEQ_SELECT_LR_MOUSE: - x = UI_view2d_region_to_view_x(v2d, event->mval[0]); + x = UI_view2d_region_to_view_x(v2d, mval[0]); break; case SEQ_SELECT_LR_LEFT: x = CFRA - 1.0f; @@ -409,13 +421,27 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e } } } + + ret_value = OPERATOR_FINISHED; } else { act_orig = ed->act_seq; if (seq) { - if (!extend && !linked_handle) { + /* Are we trying to select a handle that's already selected? */ + const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) || + ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL)); + + if (wait_to_deselect_others && (seq->flag & SELECT) && + (hand == SEQ_SIDE_NONE || handle_selected)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else if (!extend && !linked_handle) { ED_sequencer_deselect_all(scene); + ret_value = OPERATOR_FINISHED; + } + else { + ret_value = OPERATOR_FINISHED; } BKE_sequencer_active_set(scene, seq); @@ -509,6 +535,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp); } } + + ret_value = OPERATOR_FINISHED; } else { if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) { @@ -525,6 +553,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e seq->flag ^= SEQ_RIGHTSEL; break; } + ret_value = OPERATOR_FINISHED; } else { seq->flag |= SELECT; @@ -542,9 +571,12 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e if (linked_time) { select_linked_time(ed->seqbasep, seq); } + + BLI_assert((ret_value & OPERATOR_CANCELLED) == 0); } else if (deselect_all) { ED_sequencer_deselect_all(scene); + ret_value = OPERATOR_FINISHED; } } @@ -552,8 +584,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); - /* allowing tweaks */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + return ret_value; } void SEQUENCER_OT_select(wmOperatorType *ot) @@ -565,6 +596,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"}, {0, NULL, 0, NULL, NULL}, }; + PropertyRNA *prop; /* identifiers */ ot->name = "Select"; @@ -572,14 +604,16 @@ void SEQUENCER_OT_select(wmOperatorType *ot) ot->description = "Select a strip (last selected becomes the \"active strip\")"; /* api callbacks */ - ot->invoke = sequencer_select_invoke; + ot->exec = sequencer_select_exec; + ot->invoke = WM_generic_select_invoke; + ot->modal = WM_generic_select_modal; ot->poll = ED_operator_sequencer_active; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - PropertyRNA *prop; + WM_operator_properties_generic_select(ot); RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); prop = RNA_def_boolean(ot->srna, "deselect_all", diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 9f39313b9ab..088f06e9da8 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -311,11 +311,11 @@ static void text_main_region_draw(const bContext *C, ARegion *ar) static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) { SpaceText *st = sa->spacedata.first; - int wmcursor = BC_TEXTEDITCURSOR; + int wmcursor = WM_CURSOR_TEXT_EDIT; if (st->text && BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) { - wmcursor = CURSOR_STD; + wmcursor = WM_CURSOR_DEFAULT; } WM_cursor_set(win, wmcursor); diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c index 347d46a4234..935e288c7be 100644 --- a/source/blender/editors/space_text/text_format_lua.c +++ b/source/blender/editors/space_text/text_format_lua.c @@ -48,7 +48,7 @@ static int txtfmt_lua_find_keyword(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len; @@ -66,8 +66,7 @@ static int txtfmt_lua_find_keyword(const char *string) } else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len; - } else { i = 0; -} + } else { i = 0; } /* clang-format on */ @@ -96,7 +95,7 @@ static int txtfmt_lua_find_specialvar(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len; @@ -124,8 +123,7 @@ static int txtfmt_lua_find_specialvar(const char *string) } else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len; - } else { i = 0; -} + } else { i = 0; } /* clang-format on */ @@ -140,18 +138,13 @@ static int txtfmt_lua_find_bool(const char *string) { int i, len; - if (STR_LITERAL_STARTSWITH(string, "nil", len)) { - i = len; - } - else if (STR_LITERAL_STARTSWITH(string, "true", len)) { - i = len; - } - else if (STR_LITERAL_STARTSWITH(string, "false", len)) { - i = len; - } - else { - i = 0; - } + /* Keep aligned args for readability. */ + /* clang-format off */ + + if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; + } else { i = 0; } /* clang-format on */ @@ -169,10 +162,9 @@ static char txtfmt_lua_format_identifier(const char *str) /* Keep aligned args for readability. */ /* clang-format off */ - if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; + if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; } else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD; - } else { fmt = FMT_TYPE_DEFAULT; -} + } else { fmt = FMT_TYPE_DEFAULT; } /* clang-format on */ diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c index fb9ddcb09cb..2da4488e901 100644 --- a/source/blender/editors/space_text/text_format_osl.c +++ b/source/blender/editors/space_text/text_format_osl.c @@ -40,7 +40,7 @@ static int txtfmt_osl_find_builtinfunc(const char *string) /* list is from * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf */ - if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len; @@ -86,7 +86,7 @@ static int txtfmt_osl_find_reserved(const char *string) /* list is from... * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf */ - if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len; @@ -149,7 +149,7 @@ static int txtfmt_osl_find_specialvar(const char *string) /* clang-format off */ /* OSL shader types */ - if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len; @@ -189,7 +189,7 @@ static char txtfmt_osl_format_identifier(const char *str) /* Keep aligned args for readability. */ /* clang-format off */ - if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; + if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL; } else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD; } else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED; } else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE; @@ -323,7 +323,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_ /* Special vars(v) or built-in keywords(b) */ /* keep in sync with 'txtfmt_osl_format_identifier()' */ - if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL; + if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL; } else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD; } else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED; } else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE; diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c index a5e1a3845cf..21df7b5b76a 100644 --- a/source/blender/editors/space_text/text_format_pov.c +++ b/source/blender/editors/space_text/text_format_pov.c @@ -48,7 +48,7 @@ static int txtfmt_pov_find_keyword(const char *string) int i, len; /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "version", len)) { i = len; @@ -101,7 +101,7 @@ static int txtfmt_pov_find_reserved_keywords(const char *string) /* clang-format off */ /* Float Functions */ - if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) { i = len; @@ -261,7 +261,7 @@ static int txtfmt_pov_find_reserved_builtins(const char *string) /* clang-format off */ /* Language Keywords */ - if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) { i = len; @@ -500,7 +500,7 @@ static int txtfmt_pov_find_specialvar(const char *string) { int i, len; /* Modifiers */ - if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) { i = len; @@ -710,7 +710,7 @@ static int txtfmt_pov_find_bool(const char *string) /* clang-format off */ /* Built-in Constants */ - if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len; diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c index 04f4b992cc6..b349b38e551 100644 --- a/source/blender/editors/space_text/text_format_pov_ini.c +++ b/source/blender/editors/space_text/text_format_pov_ini.c @@ -49,7 +49,7 @@ static int txtfmt_ini_find_keyword(const char *string) /* clang-format off */ /* Language Directives */ - if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "declare", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len; @@ -111,7 +111,7 @@ static int txtfmt_ini_find_reserved(const char *string) * list is from... * http://www.povray.org/documentation/view/3.7.0/212/ */ - if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) { i = len; @@ -321,7 +321,7 @@ static int txtfmt_ini_find_bool(const char *string) /* clang-format off */ /* Built-in Constants */ - if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len; diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 98eeee61c3a..d84beb79be6 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -58,11 +58,11 @@ static int txtfmt_py_find_builtinfunc(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len; @@ -114,7 +114,7 @@ static int txtfmt_py_find_specialvar(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "class", len)) { i = len; } else { i = 0; } @@ -155,7 +155,7 @@ static int txtfmt_py_find_bool(const char *string) /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len; } else { i = 0; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index caefb5070fb..f9557225b6b 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -443,6 +443,8 @@ static int text_reload_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 1); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); + text->flags &= ~TXT_ISDIRTY; + /* return to scroll position */ st->top = orig_top; txt_screen_clamp(st, ar); @@ -3482,7 +3484,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) } else { if (!found) { - BKE_reportf(op->reports, RPT_ERROR, "Text not found: %s", st->findstr); + BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr); } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index b32bb0baec9..c7f13ce0e51 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -311,13 +311,6 @@ static void view3d_free(SpaceLink *sl) MEM_freeN(vd->runtime.properties_storage); } - if (vd->fx_settings.ssao) { - MEM_freeN(vd->fx_settings.ssao); - } - if (vd->fx_settings.dof) { - MEM_freeN(vd->fx_settings.dof); - } - if (vd->shading.prop) { IDP_FreeProperty(vd->shading.prop); vd->shading.prop = NULL; @@ -341,19 +334,20 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) v3dn->runtime.properties_storage = NULL; } + v3dn->local_collections_uuid = 0; + v3dn->flag &= ~V3D_LOCAL_COLLECTIONS; + if (v3dn->shading.type == OB_RENDER) { v3dn->shading.type = OB_SOLID; } + if (v3dn->shading.prop) { + v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop); + } + /* copy or clear inside new stuff */ v3dn->runtime.properties_storage = NULL; - if (v3dn->fx_settings.dof) { - v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof); - } - if (v3dn->fx_settings.ssao) { - v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao); - } return (SpaceLink *)v3dn; } @@ -577,7 +571,7 @@ static void view3d_lightcache_update(bContext *C) Scene *scene = CTX_data_scene(C); - if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) { + if (!BKE_scene_uses_blender_eevee(scene)) { /* Only do auto bake if eevee is the active engine */ return; } @@ -1039,10 +1033,10 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) ViewLayer *view_layer = WM_window_get_active_view_layer(win); Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (obedit) { - WM_cursor_set(win, CURSOR_EDIT); + WM_cursor_set(win, WM_CURSOR_EDIT); } else { - WM_cursor_set(win, CURSOR_STD); + WM_cursor_set(win, WM_CURSOR_DEFAULT); } } @@ -1093,6 +1087,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win), if (wmn->data & ND_GPENCIL_EDITMODE) { ED_region_tag_redraw(ar); } + else if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } break; case NC_BRUSH: ED_region_tag_redraw(ar); @@ -1457,7 +1454,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (view_layer->basact) { Object *ob = view_layer->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) { + if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || (ob->mode & OB_MODE_EDIT)) { CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); } } @@ -1469,7 +1466,8 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (view_layer->basact) { Object *ob = view_layer->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) { + if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || + (ob->mode & OB_MODE_EDIT) != 0) { CTX_data_id_pointer_set(result, &ob->id); } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index aafd36a5bb8..3ee9755cb06 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1422,18 +1422,24 @@ static void draw_grid_unit_name( { if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) { const char *grid_unit = NULL; + int font_id = BLF_default(); ED_view3d_grid_view_scale(scene, v3d, rv3d, &grid_unit); if (grid_unit) { char numstr[32] = ""; - UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + UI_FontThemeColor(font_id, TH_TEXT_HI); if (v3d->grid != 1.0f) { BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); } *yoffset -= U.widget_unit; + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); BLF_draw_default_ascii( xoffset, *yoffset, 0.0f, numstr[0] ? numstr : grid_unit, sizeof(numstr)); + + BLF_disable(font_id, BLF_SHADOW); } } } diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index f77a42fb1c1..17b575cedae 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -179,7 +179,7 @@ static void validate_object_select_id( return; } - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { Base *base = BKE_view_layer_base_find(view_layer, obact); DRW_select_buffer_context_create(&base, 1, -1); } @@ -226,7 +226,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) ARegion *ar = vc->ar; Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0); DRW_draw_depth_object(vc->ar, viewport, obact_eval); } @@ -383,6 +383,14 @@ void ED_view3d_datamask(const bContext *C, r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; r_cddata_masks->vmask |= CD_MASK_ORCO; } + else if (v3d->shading.type == OB_SOLID) { + if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) { + r_cddata_masks->lmask |= CD_MASK_MLOOPUV; + } + if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) { + r_cddata_masks->lmask |= CD_MASK_MLOOPCOL; + } + } if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 4bc74ab8fba..3ad194a5d2b 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -2997,7 +2997,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) ok = paintface_minmax(ob_eval, min, max); } else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) { - ok = PE_minmax(scene, CTX_data_view_layer(C), min, max); + ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max); } else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 615589347da..dbad06da5ec 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -25,6 +25,7 @@ #include "BKE_armature.h" #include "BKE_action.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 42931d5abb5..ba5ca5fbd15 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -24,6 +24,7 @@ #include "BKE_camera.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "DNA_object_types.h" #include "DNA_camera_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c index b37f1e41294..793aec42dcd 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -22,6 +22,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "BKE_image.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c index 44ad1d14dba..90b1539c8a7 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c @@ -21,6 +21,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c index 35677b2e4c2..890de0ae611 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_light.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c @@ -22,6 +22,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_object.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c index b5b924c7f4a..d6d3a3dc563 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -518,9 +518,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv static int gizmo_axis_cursor_get(wmGizmo *gz) { if (gz->highlight_part > 0) { - return CURSOR_EDIT; + return WM_CURSOR_EDIT; } - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt) diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 2189191ad53..a5b7fac624d 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -407,6 +407,17 @@ static bool view3d_ruler_item_mousemove(RulerInfo *ruler_info, /** \name Ruler/Grease Pencil Conversion * \{ */ +/* Helper: Find the layer created as ruler. */ +static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) +{ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->flag & GP_LAYER_IS_RULER) { + return gpl; + } + } + return NULL; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) { @@ -427,12 +438,12 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) } gpd = scene->gpd; - gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = view3d_ruler_layer_get(gpd); if (gpl == NULL) { gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; - gpl->flag |= GP_LAYER_HIDE; + gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER; } gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); @@ -485,8 +496,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) if (scene->gpd) { bGPDlayer *gpl; - const char *ruler_name = RULER_ID; - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = view3d_ruler_layer_get(scene->gpd); if (gpl) { bGPDframe *gpf; gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); @@ -1013,9 +1023,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) static int gizmo_ruler_cursor_get(wmGizmo *gz) { if (gz->highlight_part == PART_LINE) { - return BC_CROSSCURSOR; + return WM_CURSOR_CROSS; } - return BC_NSEW_SCROLLCURSOR; + return WM_CURSOR_NSEW_SCROLL; } void VIEW3D_GT_ruler_item(wmGizmoType *gzt) diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index e5a145b0411..cfdd3dcbb6f 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -79,7 +79,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); BKE_copybuffer_save(bmain, str, op->reports); - BKE_reportf(op->reports, RPT_INFO, "Copied %d selected objects", num_copied); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); return OPERATOR_FINISHED; } @@ -118,7 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_WINDOW, NULL); - BKE_reportf(op->reports, RPT_INFO, "%d objects pasted", num_pasted); + BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bcffad454fe..3eee76277e8 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -120,13 +120,13 @@ float ED_view3d_select_dist_px(void) } /* TODO: should return whether there is valid context to continue */ -void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) +void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph) { memset(vc, 0, sizeof(ViewContext)); vc->C = C; vc->ar = CTX_wm_region(C); vc->bmain = CTX_data_main(C); - vc->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + vc->depsgraph = depsgraph; vc->scene = CTX_data_scene(C); vc->view_layer = CTX_data_view_layer(C); vc->v3d = CTX_wm_view3d(C); @@ -1020,10 +1020,12 @@ static void do_lasso_select_armature__doSelectBone(void *userData, is_ignore_flag |= BONESEL_TIP; } - if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { - is_inside_flag |= BONESEL_BONE; + if (is_ignore_flag == 0) { + if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || + BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + is_inside_flag |= BONESEL_BONE; + } } ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16); @@ -1344,11 +1346,12 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); @@ -1889,6 +1892,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, /* mval comes from event->mval, only use within region handlers */ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; Base *basact = NULL; uint buffer[MAXPICKBUF]; @@ -1897,7 +1901,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); const bool do_nearest = !XRAY_ACTIVE(vc.v3d); const int hits = mixed_bones_object_selectbuffer( @@ -1955,9 +1959,10 @@ static bool ed_object_select_pick(bContext *C, bool enumerate, bool object) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; /* setup view context for argument to callbacks */ - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); @@ -3203,6 +3208,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e static int view3d_box_select_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; rcti rect; bool changed_multi = false; @@ -3214,7 +3220,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); WM_operator_properties_border_to_rcti(op, &rect); @@ -4004,6 +4010,7 @@ static bool object_circle_select(ViewContext *vc, /* not a real operator, only for circle test */ static int view3d_circle_select_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; const int radius = RNA_int_get(op->ptr, "radius"); const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")}; @@ -4016,7 +4023,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), WM_gesture_is_modal_first(gesture)); - ED_view3d_viewcontext_init(C, &vc); + ED_view3d_viewcontext_init(C, &vc, depsgraph); Object *obact = vc.obact; Object *obedit = vc.obedit; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index e5e1b1297f6..d7af307bc53 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -196,8 +196,8 @@ void ED_view3d_smooth_view_ex( sms.to_camera = true; /* restore view3d values in end */ } - /* skip smooth viewing for render engine draw */ - if (smooth_viewtx && v3d->shading.type != OB_RENDER) { + /* skip smooth viewing for external render engine draw */ + if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) { bool changed = false; /* zero means no difference */ if (sview->camera_old != sview->camera) { @@ -508,7 +508,7 @@ static bool view3d_camera_to_view_poll(bContext *C) void VIEW3D_OT_camera_to_view(wmOperatorType *ot) { /* identifiers */ - ot->name = "Align Camera To View"; + ot->name = "Align Camera to View"; ot->description = "Set camera view to active view"; ot->idname = "VIEW3D_OT_camera_to_view"; @@ -1583,7 +1583,13 @@ static uint free_localcollection_bit(Main *bmain, static void local_collections_reset_uuid(LayerCollection *layer_collection, const unsigned short local_view_bit) { - layer_collection->local_collections_bits |= local_view_bit; + if (layer_collection->flag & LAYER_COLLECTION_HIDE) { + layer_collection->local_collections_bits &= ~local_view_bit; + } + else { + layer_collection->local_collections_bits |= local_view_bit; + } + LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { local_collections_reset_uuid(child, local_view_bit); } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 91c05f5cac6..a7402a622d5 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -204,6 +204,8 @@ typedef struct WalkInfo { * (this would need to un-key all previous frames). */ bool anim_playing; + bool need_rotation_keyframe; + bool need_translation_keyframe; /** Previous 2D mouse values. */ int prev_mval[2]; @@ -538,6 +540,8 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) #endif walk->anim_playing = ED_screen_animation_playing(wm); + walk->need_rotation_keyframe = false; + walk->need_translation_keyframe = false; walk->time_lastdraw = PIL_check_seconds_timer(); @@ -577,7 +581,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar->winrct.ymin + walk->center_mval[1]); /* remove the mouse cursor temporarily */ - WM_cursor_modal_set(win, CURSOR_NONE); + WM_cursor_modal_set(win, WM_CURSOR_NONE); return 1; } @@ -930,9 +934,12 @@ static void walkMoveCamera(bContext *C, /* we only consider autokeying on playback or if user confirmed walk on the same frame * otherwise we get a keyframe even if the user cancels. */ const bool use_autokey = is_confirm || walk->anim_playing; - ED_view3d_cameracontrol_update( walk->v3d_camera_control, use_autokey, C, do_rotate, do_translate); + if (use_autokey) { + walk->need_rotation_keyframe = false; + walk->need_translation_keyframe = false; + } } static float getFreeFallDistance(const float gravity, const float time) @@ -1280,9 +1287,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm) add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { - const bool do_rotate = (moffset[0] || moffset[1]); - const bool do_translate = (walk->speed != 0.0f); - walkMoveCamera(C, walk, do_rotate, do_translate, is_confirm); + walk->need_rotation_keyframe |= (moffset[0] || moffset[1]); + walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON); + walkMoveCamera( + C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm); } } else { @@ -1322,7 +1330,10 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm) walk->redraw = true; if (walk->rv3d->persp == RV3D_CAMOB) { - walkMoveCamera(C, walk, has_rotate, has_translate, is_confirm); + walk->need_rotation_keyframe |= has_rotate; + walk->need_translation_keyframe |= has_translate; + walkMoveCamera( + C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm); } } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index a95c7cf7456..b98c14150d5 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2299,7 +2299,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if (t->options & CTX_SCULPT) { + if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) { ED_sculpt_end_transform(C); } @@ -2346,9 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - Object *ob = CTX_data_active_object(C); - if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) { - options |= CTX_SCULPT; + if (CTX_wm_view3d(C) != NULL) { + Object *ob = CTX_data_active_object(C); + if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) { + options |= CTX_SCULPT; + } } t->options = options; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index b90fff29a84..ff2afbc0cd7 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -267,7 +267,6 @@ typedef struct TransDataNla { int handle; } TransDataNla; -struct GHash; struct LinkNode; /* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */ diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 1e783e0e7b8..64ad8b2091e 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -429,7 +429,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) bone->flag |= BONE_TRANSFORM_CHILD; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } bone_children_clear_transflag(mode, around, &bone->childbase); @@ -455,14 +455,14 @@ int count_set_pose_transflags(Object *ob, bone->flag |= BONE_TRANSFORM; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; bone->flag &= ~BONE_TRANSFORM_CHILD; } else { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; } } @@ -1542,8 +1542,8 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t } for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) { - + if ((pchan->bone->flag & BONE_TRANSFORM) || + ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) { ListBase dsources = {NULL, NULL}; /* clear any 'unkeyed' flag it may have */ @@ -2237,9 +2237,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* Update motion paths once for all transformed bones in an object. */ GSetIterator gs_iter; GSET_ITER (gs_iter, motionpath_updates) { - bool current_frame_only = canceled; + const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME : + POSE_PATH_CALC_RANGE_CHANGED; ob = BLI_gsetIterator_getKey(&gs_iter); - ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only); + ED_pose_recalculate_paths(C, t->scene, ob, range); } BLI_gset_free(motionpath_updates, NULL); } @@ -2250,7 +2251,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* pass */ } else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) && - (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) { + (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->depsgraph, t->scene, ob)) { /* do nothing */ } else if (t->flag & T_CURSOR) { @@ -2320,8 +2321,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) if (motionpath_update) { /* Update motion paths once for all transformed objects. */ - bool current_frame_only = canceled; - ED_objects_recalculate_paths(C, t->scene, current_frame_only); + const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME : + OBJECT_PATH_CALC_RANGE_CHANGED; + ED_objects_recalculate_paths(C, t->scene, range); } } @@ -2399,7 +2401,7 @@ void createTransData(bContext *C, TransInfo *t) } countAndCleanTransDataContainer(t); } - else if (t->options & CTX_SCULPT) { + else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) { createTransSculpt(t); countAndCleanTransDataContainer(t); } @@ -2666,7 +2668,8 @@ void createTransData(bContext *C, TransInfo *t) } } } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) { + else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && + PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) { createTransParticleVerts(C, t); countAndCleanTransDataContainer(t); t->flag |= T_POINTS; diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c index 3eb4d220cb0..f3d7592127c 100644 --- a/source/blender/editors/transform/transform_convert_graph.c +++ b/source/blender/editors/transform/transform_convert_graph.c @@ -621,10 +621,10 @@ void flushTransGraphData(TransInfo *t) float inv_unit_scale = 1.0f / tdg->unit_scale; - /* handle snapping for time values - * - we should still be in NLA-mapping timespace - * - only apply to keyframes (but never to handles) - * - don't do this when canceling, or else these changes won't go away + /* Handle snapping for time values: + * - We should still be in NLA-mapping time-space. + * - Only apply to keyframes (but never to handles). + * - Don't do this when canceling, or else these changes won't go away. */ if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) { switch (sipo->autosnap) { diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 9c46094ee83..f1928433491 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1044,7 +1044,6 @@ void trans_mesh_customdata_correction_init(TransInfo *t) * accidentally break uv maps or vertex colors then */ (bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) { use_origfaces = true; - cd_loop_mdisp_offset = cd_loop_mdisp_offset; } else { use_origfaces = false; @@ -1452,7 +1451,7 @@ void createTransUVs(bContext *C, TransInfo *t) const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0; elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true); if (elementmap == NULL) { - return; + continue; } if (is_prop_connected) { diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 6142e9628a4..6e85f6b9bf0 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -501,8 +501,12 @@ static void set_trans_object_base_deps_flag_cb(ID *id, static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object) { object->id.tag |= LIB_TAG_DOIT; - DEG_foreach_dependent_ID_component( - depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL); + DEG_foreach_dependent_ID_component(depsgraph, + &object->id, + DEG_OB_COMP_TRANSFORM, + DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS, + set_trans_object_base_deps_flag_cb, + NULL); } static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer) @@ -930,11 +934,13 @@ void createTransTexspace(TransInfo *t) normalize_m3(td->axismtx); pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); - if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) { + if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size)) { ob->dtx |= OB_TEXSPACE; *texflag &= ~ME_AUTOSPACE; } + zero_v3(td->ext->rot); + copy_v3_v3(td->iloc, td->loc); copy_v3_v3(td->ext->irot, td->ext->rot); copy_v3_v3(td->ext->isize, td->ext->size); diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c index 3b11e604cab..2a961da018b 100644 --- a/source/blender/editors/transform/transform_convert_particle.c +++ b/source/blender/editors/transform/transform_convert_particle.c @@ -51,7 +51,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t) TransDataExtension *tx; Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(t->scene); - PTCacheEdit *edit = PE_get_current(t->scene, ob); + PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob); ParticleSystem *psys = NULL; PTCacheEditPoint *point; PTCacheEditKey *key; @@ -200,7 +200,7 @@ void flushTransParticles(TransInfo *t) Scene *scene = t->scene; ViewLayer *view_layer = t->view_layer; Object *ob = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob); ParticleSystem *psys = edit->psys; PTCacheEditPoint *point; PTCacheEditKey *key; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 76f699e3dc4..2e4f4344481 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -794,6 +794,12 @@ static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; pchan_orig = pchan_orig->next) { + /* Clear the MIRROR flag from previous runs */ + pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR; + } + + for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; + pchan_orig = pchan_orig->next) { /* no layer check, correct mirror is more important */ if (pchan_orig->bone->flag & BONE_TRANSFORM) { bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); @@ -1088,12 +1094,12 @@ static void recalcData_objects(TransInfo *t) GSetIterator gs_iter; GSET_ITER (gs_iter, motionpath_updates) { Object *ob = BLI_gsetIterator_getKey(&gs_iter); - ED_pose_recalculate_paths(t->context, t->scene, ob, true); + ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME); } BLI_gset_free(motionpath_updates, NULL); } else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && - PE_get_current(t->scene, base->object)) { + PE_get_current(t->depsgraph, t->scene, base->object)) { if (t->state != TRANS_CANCEL) { applyProject(t); } @@ -1146,7 +1152,7 @@ static void recalcData_objects(TransInfo *t) if (motionpath_update) { /* Update motion paths once for all transformed objects. */ - ED_objects_recalculate_paths(t->context, t->scene, true); + ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED); } if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { @@ -1707,7 +1713,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } else { - if (ISMOUSE(t->launch_event) && (U.flag & USER_RELEASECONFIRM)) { + /* Release confirms preference should not affect node editor (T69288, T70504). */ + if (ISMOUSE(t->launch_event) && + ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) { /* Global "release confirm" on mouse bindings */ t->flag |= T_RELEASE_CONFIRM; } @@ -1832,7 +1840,7 @@ static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCusto custom_data->data = NULL; } /* In case modes are switched in the same transform session. */ - custom_data->free_cb = false; + custom_data->free_cb = NULL; custom_data->use_free = false; } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 25cf0fbbba2..157cf96a85e 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -516,9 +516,15 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags) } /* for pose mode */ -static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan) +static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, + const bPoseChannel *pchan, + short orientation_type) { - protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); + /* Protect-flags apply to local space in pose mode, so only let them influence axis + * visibility if we show the global orientation, otherwise it's confusing. */ + if (orientation_type == V3D_ORIENT_LOCAL) { + protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); + } } /* for editmode*/ @@ -742,7 +748,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C, bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); int a, totsel = 0; + const int pivot_point = scene->toolsettings->transform_pivot_point; + const short orientation_type = params->orientation_type ? + (params->orientation_type - 1) : + scene->orientation_slots[SCE_ORIENT_DEFAULT].type; + const short orientation_index_custom = + params->orientation_type ? params->orientation_index_custom : + scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; /* transform widget matrix */ unit_m4(rv3d->twmat); @@ -756,12 +769,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* global, local or normal orientation? * if we could check 'totsel' now, this should be skipped with no selection. */ if (ob) { - const short orientation_type = params->orientation_type ? - (params->orientation_type - 1) : - scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = - params->orientation_type ? params->orientation_index_custom : - scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; float mat[3][3]; ED_transform_calc_orientation_from_type_ex( C, mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); @@ -888,7 +895,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local); totsel++; } - if (ebo->flag & BONE_SELECTED) { + if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) { protectflag_to_drawflags_ebone(rv3d, ebo); } } @@ -1038,7 +1045,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, Bone *bone = pchan->bone; if (bone && (bone->flag & BONE_TRANSFORM)) { calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local); - protectflag_to_drawflags_pchan(rv3d, pchan); + protectflag_to_drawflags_pchan(rv3d, pchan, orientation_type); } } totsel += totsel_iter; @@ -1063,7 +1070,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, } } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); PTCacheEditPoint *point; PTCacheEditKey *ek; int k; @@ -1122,7 +1129,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C, calc_tw_center(tbounds, co); } } - protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); + + /* Protect-flags apply to world space in object mode, so only let them influence axis + * visibility if we show the global orientation, otherwise it's confusing. */ + if (orientation_type == V3D_ORIENT_GLOBAL) { + protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); + } totsel++; } @@ -1168,16 +1180,20 @@ static void gizmo_prepare_mat(const bContext *C, if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT(view_layer); if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { /* pass */ } - else if (ob->sculpt) { - SculptSession *ss = ob->sculpt; - copy_v3_v3(rv3d->twmat[3], ss->pivot_pos); - } - else if (ob != NULL) { - ED_object_calc_active_center(ob, false, rv3d->twmat[3]); + else { + Object *ob = OBACT(view_layer); + if (ob != NULL) { + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { + SculptSession *ss = ob->sculpt; + copy_v3_v3(rv3d->twmat[3], ss->pivot_pos); + } + else { + ED_object_calc_active_center(ob, false, rv3d->twmat[3]); + } + } } } break; @@ -1293,7 +1309,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, PointerRNA toolsettings_ptr; RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr); - if (type_fn == VIEW3D_GGT_xform_gizmo) { + if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) { extern PropertyRNA rna_ToolSettings_transform_pivot_point; const PropertyRNA *props[] = { &rna_ToolSettings_transform_pivot_point, @@ -1334,6 +1350,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup, } WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh); } void drawDial3d(const TransInfo *t) diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index e771fe43bd8..2821277ffa0 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -389,7 +389,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) /* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */ if (t->flag & T_MODAL) { t->flag |= T_MODAL_CURSOR_SET; - WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); } break; case HLP_SPRING: @@ -400,7 +400,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode) case HLP_CARROW: if (t->flag & T_MODAL) { t->flag |= T_MODAL_CURSOR_SET; - WM_cursor_modal_set(win, CURSOR_NONE); + WM_cursor_modal_set(win, WM_CURSOR_NONE); } break; default: diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 1c264ba48ae..b2d8671fbce 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -302,11 +302,11 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot) WM_operatortype_props_advanced_begin(ot); RNA_def_boolean( - ot->srna, "use", false, "Use after creation", "Select orientation after its creation"); + ot->srna, "use", false, "Use After Creation", "Select orientation after its creation"); RNA_def_boolean(ot->srna, "overwrite", false, - "Overwrite previous", + "Overwrite Previous", "Overwrite previously created orientation with same name"); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index cbe9505d3f2..3159464072e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -44,6 +44,7 @@ #include "BKE_curve.h" #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_workspace.h" diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 9c2642a46c1..f35a2808f22 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -47,6 +47,7 @@ #include "BKE_object.h" #include "BKE_anim.h" /* for duplis */ #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_tracking.h" #include "BKE_context.h" @@ -1717,7 +1718,7 @@ static short snapCurve(SnapData *snapdata, if (use_obedit == false) { /* Test BoundBox */ - BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL); + BoundBox *bb = BKE_curve_boundbox_get(ob); if (bb && !snap_bound_box_check_dist( bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) { return 0; @@ -2367,6 +2368,7 @@ static short snapEditMesh(SnapObjectContext *sctx, if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) { BM_mesh_elem_table_ensure(em->bm, BM_VERT); + BM_mesh_elem_index_ensure(em->bm, BM_VERT); BLI_bvhtree_find_nearest_projected(treedata_vert->tree, lpmat, snapdata->win_size, @@ -2382,6 +2384,7 @@ static short snapEditMesh(SnapObjectContext *sctx, int last_index = nearest.index; nearest.index = -1; BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT); + BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT); BLI_bvhtree_find_nearest_projected(treedata_edge->tree, lpmat, snapdata->win_size, diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index c2566d111cf..f5548119e0a 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -245,7 +245,7 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render) * may cause a flush on saving: T53986. */ if ((ob->sculpt && ob->sculpt->cache) == 0) { /* flush multires changes (for sculpt) */ - multires_force_update(ob); + multires_flush_sculpt_updates(ob); has_edited = true; if (for_render) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index bd941968418..fafd54804c0 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -177,6 +177,7 @@ static void uvedit_get_batches(Object *ob, float *tot_area, float *tot_area_uv) { + float *tmp_tot_area, *tmp_tot_area_uv; int drawfaces = draw_uvs_face_check(scene->toolsettings); const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0; @@ -193,7 +194,8 @@ static void uvedit_get_batches(Object *ob, } if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) { - batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, NULL, NULL); + batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area( + ob->data, &tmp_tot_area, &tmp_tot_area_uv); } else if (draw_stretch) { batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data); @@ -207,11 +209,11 @@ static void uvedit_get_batches(Object *ob, DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false); - /* after create_requested we can load the actual areas */ - float tmp_tot_area, tmp_tot_area_uv; - DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, &tmp_tot_area, &tmp_tot_area_uv); - *tot_area += tmp_tot_area; - *tot_area_uv += tmp_tot_area_uv; + if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) { + /* after create_requested we can load the actual areas */ + *tot_area += *tmp_tot_area; + *tot_area_uv += *tmp_tot_area_uv; + } } static void draw_uvs_shadow(SpaceImage *UNUSED(sima), diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 57e2a84d248..0d258ba542b 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -4872,12 +4872,6 @@ static void UV_OT_reveal(wmOperatorType *ot) /** \name Set 2D Cursor Operator * \{ */ -static bool uv_set_2d_cursor_poll(bContext *C) -{ - return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) || - ED_space_image_paint_curve(C); -} - static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); @@ -4923,7 +4917,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot) /* api callbacks */ ot->exec = uv_set_2d_cursor_exec; ot->invoke = uv_set_2d_cursor_invoke; - ot->poll = uv_set_2d_cursor_poll; + ot->poll = ED_space_image_cursor_poll; /* properties */ RNA_def_float_vector(ot->srna, diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index f4fd2b132e8..263b5429161 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -590,7 +590,8 @@ class Stroke : public Interface1D { /*! Resampling method. * Resamples the curve so that it eventually has iNPoints. That means it is going to add * iNPoints-vertices_size, if vertices_size is the number of points we already have. If - * vertices_size >= iNPoints, no resampling is done. \param iNPoints: The number of vertices we + * vertices_size >= iNPoints, no resampling is done. + * \param iNPoints: The number of vertices we * eventually want in our stroke. */ int Resample(int iNPoints); @@ -840,8 +841,10 @@ class Stroke : public Interface1D { vertex_iterator vertices_end(); /*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the Stroke. One can - * specify a sampling value to resample the Stroke on the fly if needed. \param t: The resampling - * value with which we want our Stroke to be resampled. If 0 is specified, no resampling is done. + * specify a sampling value to resample the Stroke on the fly if needed. + * + * \param t: The resampling value with which we want our Stroke to be resampled. + * If 0 is specified, no resampling is done. */ StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t = 0.0f); diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h index 7a72a176902..ab489bff4c9 100644 --- a/source/blender/freestyle/intern/view_map/Interface1D.h +++ b/source/blender/freestyle/intern/view_map/Interface1D.h @@ -156,15 +156,17 @@ class Interface1D { /*! Returns an iterator over the Interface1D points, pointing to the first point. The difference * with verticesBegin() is that here we can iterate over points of the 1D element at a any given - * sampling. Indeed, for each iteration, a virtual point is created. \param t: The sampling with - * which we want to iterate over points of this 1D element. + * sampling. Indeed, for each iteration, a virtual point is created. + * + * \param t: The sampling with which we want to iterate over points of this 1D element. */ virtual Interface0DIterator pointsBegin(float t = 0.0f); /*! Returns an iterator over the Interface1D points, pointing after the last point. The * difference with verticesEnd() is that here we can iterate over points of the 1D element at a - * any given sampling. Indeed, for each iteration, a virtual point is created. \param t: The - * sampling with which we want to iterate over points of this 1D element. + * any given sampling. Indeed, for each iteration, a virtual point is created. + * + * \param t: The sampling with which we want to iterate over points of this 1D element. */ virtual Interface0DIterator pointsEnd(float t = 0.0f); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 72385fd2f2c..b3321b693a4 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -80,15 +80,15 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) bool is_stroke_affected_by_modifier(Object *ob, char *mlayername, char *mmaterialname, - int mpassindex, - int gpl_passindex, - int minpoints, + const int mpassindex, + const int gpl_passindex, + const int minpoints, bGPDlayer *gpl, bGPDstroke *gps, - bool inv1, - bool inv2, - bool inv3, - bool inv4) + const bool inv1, + const bool inv2, + const bool inv3, + const bool inv4) { Material *ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1); MaterialGPencilStyle *gp_style = ma->gp_style; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index 7f00e072cda..2b1f8dbc71a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -35,15 +35,15 @@ struct bGPDstroke; bool is_stroke_affected_by_modifier(struct Object *ob, char *mlayername, char *mmaterialname, - int mpassindex, - int gpl_passindex, - int minpoints, + const int mpassindex, + const int gpl_passindex, + const int minpoints, bGPDlayer *gpl, bGPDstroke *gps, - bool inv1, - bool inv2, - bool inv3, - bool inv4); + const bool inv1, + const bool inv2, + const bool inv3, + const bool inv4); float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 1f2f0554dd5..27c8175af3f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -203,5 +203,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index c311497ffbb..bb70b548675 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -317,14 +317,6 @@ static void foreachObjectLink(GpencilModifierData *md, walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } -static int getDuplicationFactor(GpencilModifierData *md) -{ - ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md; - int t = mmd->count; - CLAMP_MIN(t, 1); - return t; -} - GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* name */ "Array", /* structName */ "ArrayGpencilModifierData", @@ -347,5 +339,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index d72ace7a191..e3e7168330d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -550,5 +550,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index cb429b874a2..cbe2d9a4c4f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -168,5 +168,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 810a2ba7e25..bc62d0d69bb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -63,8 +63,8 @@ struct GPHookData_cb { float falloff_sq; float fac_orig; - unsigned int use_falloff : 1; - unsigned int use_uniform : 1; + uint use_falloff : 1; + uint use_uniform : 1; float cent[3]; @@ -357,5 +357,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 6b74f96ce31..9dbf7b35bc5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -219,5 +219,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index e391adde829..ef06e14b3d7 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -203,21 +203,6 @@ static void foreachObjectLink(GpencilModifierData *md, walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } -static int getDuplicationFactor(GpencilModifierData *md) -{ - MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; - int factor = 1; - /* create a duplication for each axis */ - for (int xi = 0; xi < 3; xi++) { - if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { - factor++; - } - } - CLAMP_MIN(factor, 1); - - return factor; -} - GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* name */ "Mirror", /* structName */ "MirrorGpencilModifierData", @@ -240,5 +225,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index b286b55829e..f34477aaab2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -274,5 +274,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 08f67eedc86..70d463fff76 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -148,5 +148,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 22610771045..c0892a1d91a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -206,5 +206,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 25a56c4385c..9594fc8581e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -144,5 +144,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index 5ec7fe4ff18..68060711681 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -155,5 +155,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 741555722b5..89d6565d0dd 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -65,12 +65,16 @@ static void deformStroke(GpencilModifierData *md, { SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md; + /* It makes sense when adding points to a straight line */ + /* e.g. for creating thickness variation in later modifiers. */ + const int minimum_vert = (mmd->flag & GP_SUBDIV_SIMPLE) ? 2 : 3; + if (!is_stroke_affected_by_modifier(ob, mmd->layername, mmd->materialname, mmd->pass_index, mmd->layer_pass, - 3, + minimum_vert, gpl, gps, mmd->flag & GP_SUBDIV_INVERT_LAYER, @@ -99,14 +103,6 @@ static void bakeModifier(struct Main *UNUSED(bmain), } } -static int getDuplicationFactor(GpencilModifierData *md) -{ - SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md; - int t = (mmd->level + 1) * (mmd->level + 1); - CLAMP_MIN(t, 2); - return t; -} - GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* name */ "Subdivision", /* structName */ "SubdivGpencilModifierData", @@ -129,5 +125,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index cc38df141d1..111b02a3a9d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -220,5 +220,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index 296e01d6d31..01bb0ae2b93 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -182,5 +182,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index f6ddcf89bcf..f03bc489521 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -174,5 +174,4 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, - /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8d2355ff5ac..9320e849194 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -69,6 +69,7 @@ set(SRC intern/gpu_init_exit.c intern/gpu_material.c intern/gpu_matrix.c + intern/gpu_platform.c intern/gpu_primitive.c intern/gpu_select.c intern/gpu_select_pick.c @@ -101,6 +102,7 @@ set(SRC GPU_legacy_stubs.h GPU_material.h GPU_matrix.h + GPU_platform.h GPU_primitive.h GPU_select.h GPU_shader.h @@ -330,6 +332,8 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC) +data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC) + if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 175033f70d9..d7218e97bf0 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -193,6 +193,19 @@ GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff #endif /* future plans */ +/** + * #GPUDrawList is an API to do lots of similar draw-calls very fast using multi-draw-indirect. + * There is a fallback if the feature is not supported. + */ +typedef struct GPUDrawList GPUDrawList; + +GPUDrawList *GPU_draw_list_create(int length); +void GPU_draw_list_discard(GPUDrawList *list); +void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch); +void GPU_draw_list_command_add( + GPUDrawList *list, int v_first, int v_count, int i_first, int i_count); +void GPU_draw_list_submit(GPUDrawList *list); + void gpu_batch_init(void); void gpu_batch_exit(void); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 9009c134837..6d2b0ad3be3 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -31,6 +31,7 @@ struct CCGElem; struct CCGKey; struct DMFlagMat; struct GSet; +struct Mesh; struct MLoop; struct MLoopCol; struct MLoopTri; @@ -41,21 +42,28 @@ struct PBVH; /* Buffers for drawing from PBVH grids. */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; -/* build */ +/* Build must be called once before using the other functions, used every time + * mesh topology changes. Threaded. */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri, const struct MVert *verts, const int *face_indices, - const int face_indices_len); + const int face_indices_len, + const struct Mesh *mesh); GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden); GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading); -/* update */ +/* Free part of data for update. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers); +void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, + const struct DMFlagMat *grid_flag_mats, + int *grid_indices); +/* Update mesh buffers without topology changes. Threaded. */ enum { GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1), GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 1), @@ -85,6 +93,12 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, const struct CCGKey *key, const int update_flags); +/* Finish update. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers); + +/* Free buffers. Not thread safe, must run in OpenGL main thread. */ +void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); + /* draw */ struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires); @@ -92,8 +106,4 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers); bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers); -void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); - -void GPU_pbvh_fix_linking(void); - #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 023cbb804d9..245f7f47510 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -55,34 +55,6 @@ void GPU_mem_stats_get(int *totalmem, int *freemem); void GPU_code_generate_glsl_lib(void); -/* GPU Types */ - -typedef enum eGPUDeviceType { - GPU_DEVICE_NVIDIA = (1 << 0), - GPU_DEVICE_ATI = (1 << 1), - GPU_DEVICE_INTEL = (1 << 2), - GPU_DEVICE_INTEL_UHD = (1 << 3), - GPU_DEVICE_SOFTWARE = (1 << 4), - GPU_DEVICE_UNKNOWN = (1 << 5), - GPU_DEVICE_ANY = (0xff), -} eGPUDeviceType; - -typedef enum eGPUOSType { - GPU_OS_WIN = (1 << 8), - GPU_OS_MAC = (1 << 9), - GPU_OS_UNIX = (1 << 10), - GPU_OS_ANY = (0xff00), -} eGPUOSType; - -typedef enum eGPUDriverType { - GPU_DRIVER_OFFICIAL = (1 << 16), - GPU_DRIVER_OPENSOURCE = (1 << 17), - GPU_DRIVER_SOFTWARE = (1 << 18), - GPU_DRIVER_ANY = (0xff0000), -} eGPUDriverType; - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h new file mode 100644 index 00000000000..f199a748cb5 --- /dev/null +++ b/source/blender/gpu/GPU_platform.h @@ -0,0 +1,75 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#ifndef __GPU_PLATFORM_H__ +#define __GPU_PLATFORM_H__ + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* GPU platform support */ + +/* GPU Types */ +typedef enum eGPUDeviceType { + GPU_DEVICE_NVIDIA = (1 << 0), + GPU_DEVICE_ATI = (1 << 1), + GPU_DEVICE_INTEL = (1 << 2), + GPU_DEVICE_INTEL_UHD = (1 << 3), + GPU_DEVICE_SOFTWARE = (1 << 4), + GPU_DEVICE_UNKNOWN = (1 << 5), + GPU_DEVICE_ANY = (0xff), +} eGPUDeviceType; + +typedef enum eGPUOSType { + GPU_OS_WIN = (1 << 8), + GPU_OS_MAC = (1 << 9), + GPU_OS_UNIX = (1 << 10), + GPU_OS_ANY = (0xff00), +} eGPUOSType; + +typedef enum eGPUDriverType { + GPU_DRIVER_OFFICIAL = (1 << 16), + GPU_DRIVER_OPENSOURCE = (1 << 17), + GPU_DRIVER_SOFTWARE = (1 << 18), + GPU_DRIVER_ANY = (0xff0000), +} eGPUDriverType; + +typedef enum eGPUSupportLevel { + GPU_SUPPORT_LEVEL_SUPPORTED, + GPU_SUPPORT_LEVEL_LIMITED, + GPU_SUPPORT_LEVEL_UNSUPPORTED, +} eGPUSupportLevel; + +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); +eGPUSupportLevel GPU_platform_support_level(void); +const char *GPU_platform_support_level_key(void); +const char *GPU_platform_gpu_name(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_PLATFORM_H__ */ diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index ec97e1b085e..e336aa53d24 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -45,13 +45,12 @@ typedef enum { GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */ - GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */ + GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */ GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */ - GPU_UNIFORM_COLOR, /* vec4 color */ - GPU_UNIFORM_CALLID, /* int callId */ - GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */ - GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */ + GPU_UNIFORM_COLOR, /* vec4 color */ + GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ + GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index e7600279d6f..4bbcb6a4335 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -37,14 +37,20 @@ typedef struct GPUViewport GPUViewport; /* Contains memory pools information */ typedef struct ViewportMemoryPool { - struct BLI_memblock *calls; - struct BLI_memblock *states; + struct BLI_memblock *commands; + struct BLI_memblock *commands_small; + struct BLI_memblock *callbuffers; + struct BLI_memblock *obmats; + struct BLI_memblock *obinfos; struct BLI_memblock *cullstates; struct BLI_memblock *shgroups; struct BLI_memblock *uniforms; struct BLI_memblock *views; struct BLI_memblock *passes; struct BLI_memblock *images; + struct GPUUniformBuffer **matrices_ubo; + struct GPUUniformBuffer **obinfos_ubo; + uint ubo_len; } ViewportMemoryPool; /* All FramebufferLists are just the same pointers with different names */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index e0c0aea576c..168d741f92a 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -29,6 +29,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" @@ -39,8 +40,9 @@ #include <stdlib.h> #include <string.h> +#include <limits.h> -static void batch_update_program_bindings(GPUBatch *batch, uint v_first); +static void batch_update_program_bindings(GPUBatch *batch, uint i_first); void GPU_batch_vao_cache_clear(GPUBatch *batch) { @@ -211,7 +213,9 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo) if (batch->verts[v] == NULL) { #if TRUST_NO_ONE /* for now all VertexBuffers must have same vertex_len */ - assert(verts->vertex_len == batch->verts[0]->vertex_len); + if (batch->verts[0] != NULL) { + assert(verts->vertex_len == batch->verts[0]->vertex_len); + } #endif batch->verts[v] = verts; /* TODO: mark dirty so we can keep attribute bindings up-to-date */ @@ -446,16 +450,16 @@ static void create_bindings(GPUVertBuf *verts, } } -static void batch_update_program_bindings(GPUBatch *batch, uint v_first) +static void batch_update_program_bindings(GPUBatch *batch, uint i_first) { /* Reverse order so first vbos have more prevalence (in term of attrib override). */ for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) { if (batch->verts[v] != NULL) { - create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false); + create_bindings(batch->verts[v], batch->interface, 0, false); } } if (batch->inst) { - create_bindings(batch->inst, batch->interface, v_first, true); + create_bindings(batch->inst, batch->interface, i_first, true); } if (batch->elem) { GPU_indexbuf_use(batch->elem); @@ -618,12 +622,18 @@ void GPU_batch_draw(GPUBatch *batch) GPU_batch_program_use_end(batch); } +#if GPU_TRACK_INDEX_RANGE +# define BASE_INDEX(el) ((el)->base_index) +# define INDEX_TYPE(el) ((el)->gl_index_type) +#else +# define BASE_INDEX(el) 0 +# define INDEX_TYPE(el) GL_UNSIGNED_INT +#endif + void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count) { -#if TRUST_NO_ONE BLI_assert(batch->program_in_use); /* TODO could assert that VAO is bound. */ -#endif if (v_count == 0) { v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; @@ -632,8 +642,21 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi i_count = (batch->inst) ? batch->inst->vertex_len : 1; } + if (v_count == 0 || i_count == 0) { + /* Nothing to draw. */ + return; + } + + /* Verify there is enough data do draw. */ + /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls. + * The right assert would be to check if there is an enabled attrib from each VBO + * and check their length. */ + // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX)); + // BLI_assert(v_first + v_count <= + // (batch->elem ? batch->elem->index_len : batch->verts[0]->vertex_len)); + if (!GPU_arb_base_instance_is_supported()) { - if (i_first > 0 && i_count > 0) { + if (i_first > 0) { /* If using offset drawing with instancing, we must * use the default VAO and redo bindings. */ glBindVertexArray(GPU_vao_default()); @@ -648,13 +671,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi if (batch->elem) { const GPUIndexBuf *el = batch->elem; -#if GPU_TRACK_INDEX_RANGE - GLenum index_type = el->gl_index_type; - GLint base_index = el->base_index; -#else - GLenum index_type = GL_UNSIGNED_INT; - GLint base_index = 0; -#endif + GLenum index_type = INDEX_TYPE(el); + GLint base_index = BASE_INDEX(el); void *v_first_ofs = elem_offset(el, v_first); if (GPU_arb_base_instance_is_supported()) { @@ -697,6 +715,192 @@ void GPU_draw_primitive(GPUPrimType prim_type, int v_count) } /* -------------------------------------------------------------------- */ +/** \name Indirect Draw Calls + * \{ */ + +#if 0 +# define USE_MULTI_DRAW_INDIRECT 0 +#else +/* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards, + * that breaks instancing when using indirect draw-call (see T70011). */ +# define USE_MULTI_DRAW_INDIRECT \ + (GL_ARB_multi_draw_indirect && GPU_arb_base_instance_is_supported() && \ + !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) +#endif + +typedef struct GPUDrawCommand { + uint v_count; + uint i_count; + uint v_first; + uint i_first; +} GPUDrawCommand; + +typedef struct GPUDrawCommandIndexed { + uint v_count; + uint i_count; + uint v_first; + uint base_index; + uint i_first; +} GPUDrawCommandIndexed; + +struct GPUDrawList { + GPUBatch *batch; + uint base_index; /* Avoid dereferencing batch. */ + uint cmd_offset; /* in bytes, offset inside indirect command buffer. */ + uint cmd_len; /* Number of used command for the next call. */ + uint buffer_size; /* in bytes, size of indirect command buffer. */ + GLuint buffer_id; /* Draw Indirect Buffer id */ + union { + GPUDrawCommand *commands; + GPUDrawCommandIndexed *commands_indexed; + }; +}; + +GPUDrawList *GPU_draw_list_create(int length) +{ + GPUDrawList *list = MEM_callocN(sizeof(GPUDrawList), "GPUDrawList"); + /* Alloc the biggest possible command list which is indexed. */ + list->buffer_size = sizeof(GPUDrawCommandIndexed) * length; + if (USE_MULTI_DRAW_INDIRECT) { + list->buffer_id = GPU_buf_alloc(); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); + glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW); + } + else { + list->commands = MEM_mallocN(list->buffer_size, "GPUDrawList data"); + } + return list; +} + +void GPU_draw_list_discard(GPUDrawList *list) +{ + if (list->buffer_id) { + GPU_buf_free(list->buffer_id); + } + else { + MEM_SAFE_FREE(list->commands); + } + MEM_freeN(list); +} + +void GPU_draw_list_init(GPUDrawList *list, GPUBatch *batch) +{ + BLI_assert(batch->phase == GPU_BATCH_READY_TO_DRAW); + list->batch = batch; + list->base_index = batch->elem ? BASE_INDEX(batch->elem) : UINT_MAX; + list->cmd_len = 0; + + if (USE_MULTI_DRAW_INDIRECT) { + if (list->commands == NULL) { + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); + if (list->cmd_offset >= list->buffer_size) { + /* Orphan buffer data and start fresh. */ + glBufferData(GL_DRAW_INDIRECT_BUFFER, list->buffer_size, NULL, GL_DYNAMIC_DRAW); + list->cmd_offset = 0; + } + GLenum flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; + list->commands = glMapBufferRange( + GL_DRAW_INDIRECT_BUFFER, list->cmd_offset, list->buffer_size - list->cmd_offset, flags); + } + } + else { + list->cmd_offset = 0; + } +} + +void GPU_draw_list_command_add( + GPUDrawList *list, int v_first, int v_count, int i_first, int i_count) +{ + BLI_assert(list->commands); + + if (v_count == 0 || i_count == 0) { + return; + } + + if (list->base_index != UINT_MAX) { + GPUDrawCommandIndexed *cmd = list->commands_indexed + list->cmd_len; + cmd->v_first = v_first; + cmd->v_count = v_count; + cmd->i_count = i_count; + cmd->base_index = list->base_index; + cmd->i_first = i_first; + } + else { + GPUDrawCommand *cmd = list->commands + list->cmd_len; + cmd->v_first = v_first; + cmd->v_count = v_count; + cmd->i_count = i_count; + cmd->i_first = i_first; + } + + list->cmd_len++; + uint offset = list->cmd_offset + list->cmd_len * sizeof(GPUDrawCommandIndexed); + + if (offset == list->buffer_size) { + GPU_draw_list_submit(list); + GPU_draw_list_init(list, list->batch); + } +} + +void GPU_draw_list_submit(GPUDrawList *list) +{ + GPUBatch *batch = list->batch; + + if (list->cmd_len == 0) { + return; + } + + BLI_assert(list->commands); + BLI_assert(batch->program_in_use); + /* TODO could assert that VAO is bound. */ + + /* TODO We loose a bit of memory here if we only draw arrays. Fix that. */ + uintptr_t offset = list->cmd_offset; + uint cmd_len = list->cmd_len; + size_t bytes_used = cmd_len * sizeof(GPUDrawCommandIndexed); + list->cmd_len = 0; /* Avoid reuse. */ + + /* Only do multi-draw indirect if doing more than 2 drawcall. + * This avoids the overhead of buffer mapping if scene is + * not very instance friendly. */ + if (USE_MULTI_DRAW_INDIRECT && cmd_len > 2) { + GLenum prim = batch->gl_prim_type; + + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, list->buffer_id); + glFlushMappedBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, bytes_used); + glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); + list->commands = NULL; /* Unmapped */ + list->cmd_offset += bytes_used; + + if (batch->elem) { + glMultiDrawElementsIndirect(prim, INDEX_TYPE(batch->elem), (void *)offset, cmd_len, 0); + } + else { + glMultiDrawArraysIndirect(prim, (void *)offset, cmd_len, 0); + } + } + else { + /* Fallback */ + if (batch->elem) { + GPUDrawCommandIndexed *cmd = list->commands_indexed; + for (int i = 0; i < cmd_len; i++, cmd++) { + /* Index start was added by Draw manager. Avoid counting it twice. */ + cmd->v_first -= batch->elem->index_start; + GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + } + } + else { + GPUDrawCommand *cmd = list->commands; + for (int i = 0; i < cmd_len; i++, cmd++) { + GPU_batch_draw_advanced(batch, cmd->v_first, cmd->v_count, cmd->i_first, cmd->i_count); + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Utilities * \{ */ diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c index 3a8b392ef1d..825f72e175b 100644 --- a/source/blender/gpu/intern/gpu_batch_utils.c +++ b/source/blender/gpu/intern/gpu_batch_utils.c @@ -164,7 +164,6 @@ GPUBatch *GPU_batch_wire_from_poly_2d_encoded(const uchar *polys_flat, BLI_assert(polys_step_len >= 2); for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) { union { - uint8_t as_u8[4]; uint16_t as_u16[2]; uint32_t as_u32; } data; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 3511c7438cb..2c74afd2d8e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -45,6 +45,8 @@ #include "GPU_buffers.h" #include "GPU_batch.h" +#include "gpu_private.h" + #include "bmesh.h" /* XXX: the rest of the code in this file is used for optimized PBVH @@ -78,6 +80,7 @@ struct GPU_PBVH_Buffers { int totgrid; bool use_bmesh; + bool clear_bmesh_on_flush; uint tot_tri, tot_quad; @@ -91,8 +94,9 @@ struct GPU_PBVH_Buffers { }; static struct { + GPUVertFormat format; uint pos, nor, msk, col; -} g_vbo_id = {0}; +} g_vbo_id = {{0}}; /** \} */ @@ -100,6 +104,27 @@ static struct { /** \name PBVH Utils * \{ */ +void gpu_pbvh_init() +{ + /* Initialize vertex buffer (match 'VertexBufferFormat'). */ + if (g_vbo_id.format.attr_len == 0) { + g_vbo_id.pos = GPU_vertformat_attr_add( + &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + g_vbo_id.nor = GPU_vertformat_attr_add( + &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ + g_vbo_id.msk = GPU_vertformat_attr_add( + &g_vbo_id.format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + g_vbo_id.col = GPU_vertformat_attr_add( + &g_vbo_id.format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } +} + +void gpu_pbvh_exit() +{ + /* Nothing to do. */ +} + /* Allocates a non-initialized buffer to be sent to GPU. * Return is false it indicates that the memory map failed. */ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) @@ -110,14 +135,7 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) #if 0 if (buffers->vert_buf == NULL) { /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - g_vbo_id.nor = GPU_vertformat_attr_add( - &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC); + buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC); GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); } else if (vert_len != buffers->vert_buf->vertex_len) { @@ -126,30 +144,16 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) #else if (buffers->vert_buf == NULL) { /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - g_vbo_id.nor = GPU_vertformat_attr_add( - &format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ - g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - g_vbo_id.col = GPU_vertformat_attr_add( - &format, "ac", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC); + buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC); } GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); #endif + return buffers->vert_buf->data != NULL; } static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) { - /* force flushing to the GPU */ - if (buffers->vert_buf->data) { - GPU_vertbuf_use(buffers->vert_buf); - } - if (buffers->triangles == NULL) { buffers->triangles = GPU_batch_create(prim, buffers->vert_buf, @@ -180,6 +184,7 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) /** \name Mesh PBVH * \{ */ +/* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MVert *mvert, const int *vert_indices, @@ -189,8 +194,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const int (*face_vert_indices)[3], const int update_flags) { - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; + const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; + const bool show_vcol = vcol && (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; bool empty_mask = true; { @@ -198,30 +203,38 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, /* Build VBO */ if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) { + GPUVertBufRaw pos_step = {0}; + GPUVertBufRaw nor_step = {0}; + GPUVertBufRaw msk_step = {0}; + GPUVertBufRaw col_step = {0}; + + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step); + if (show_mask) { + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step); + } + if (show_vcol) { + GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step); + } + /* Vertex data is shared if smooth-shaded, but separate * copies are made for flat shading because normals * shouldn't be shared. */ if (buffers->smooth) { for (uint i = 0; i < totvert; i++) { - const MVert *v = &mvert[vert_indices[i]]; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no); - } - - if (vmask && show_mask) { - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - for (uint j = 0; j < 3; j++) { - int vidx = face_vert_indices[i][j]; - int v_index = buffers->mloop[lt->tri[j]].v; - float fmask = vmask[v_index]; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vidx, &fmask); - empty_mask = empty_mask && (fmask == 0.0f); - } + const int vidx = vert_indices[i]; + const MVert *v = &mvert[vidx]; + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); + copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no); + + if (show_mask) { + float mask = vmask[vidx]; + *(float *)GPU_vertbuf_raw_step(&msk_step) = mask; + empty_mask = empty_mask && (mask == 0.0f); } } - if (vcol && show_vcol) { + if (show_vcol) { for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; for (int j = 0; j < 3; j++) { @@ -236,8 +249,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, else { /* calculate normal for each polygon only once */ uint mpoly_prev = UINT_MAX; - short no[3]; - int vbo_index = 0; + short no[3] = {0, 0, 0}; for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; @@ -261,27 +273,26 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, } float fmask = 0.0f; - if (vmask && show_mask) { + if (show_mask) { fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f; } for (uint j = 0; j < 3; j++) { const MVert *v = &mvert[vtri[j]]; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); + copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no); + if (show_mask) { + *(float *)GPU_vertbuf_raw_step(&msk_step) = fmask; + empty_mask = empty_mask && (fmask == 0.0f); + } - if (vcol && show_vcol) { + if (show_vcol) { const uint loop_index = lt->tri[j]; const uchar *elem = &vcol[loop_index].r; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, elem); + memcpy(GPU_vertbuf_raw_step(&col_step), elem, sizeof(uchar) * 4); } - - vbo_index++; } - - empty_mask = empty_mask && (fmask == 0.0f); } } @@ -298,16 +309,19 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, buffers->mvert = mvert; } +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, const MVert *mvert, const int *face_indices, - const int face_indices_len) + const int face_indices_len, + const struct Mesh *mesh) { GPU_PBVH_Buffers *buffers; int i, tottri; + int tot_real_edges = 0; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); @@ -320,6 +334,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], for (i = 0, tottri = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; if (!paint_is_face_hidden(lt, mvert, mloop)) { + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + for (int j = 0; j < 3; j++) { + if (r_edges[j] != -1) { + tot_real_edges++; + } + } tottri++; } } @@ -336,11 +357,6 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], return buffers; } - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - /* An element index buffer is used for smooth shading, but flat * shading requires separate vertex normals so an index buffer * can't be used there. */ @@ -348,7 +364,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], /* Fill the triangle and line buffers. */ GPUIndexBufBuilder elb, elb_lines; GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); for (i = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; @@ -359,11 +375,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], } GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i])); + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); - /* TODO skip "non-real" edges. */ - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]); - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]); - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]); + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]); + } + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]); + } } buffers->index_buf = GPU_indexbuf_build(&elb); buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); @@ -371,7 +394,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], else { /* Fill the only the line buffer. */ GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, INT_MAX); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); int vert_idx = 0; for (i = 0; i < face_indices_len; i++) { @@ -382,10 +405,18 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], continue; } - /* TODO skip "non-real" edges. */ - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); + } + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + } + vert_idx++; } buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); @@ -537,6 +568,27 @@ static void gpu_pbvh_grid_fill_index_buffers( buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast); } +void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, + const struct DMFlagMat *grid_flag_mats, + int *grid_indices) +{ + const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; + + if (buffers->smooth != smooth) { + buffers->smooth = smooth; + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); + } +} + +/* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, CCGElem **grids, const DMFlagMat *grid_flag_mats, @@ -550,26 +602,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, bool empty_mask = true; int i, j, k, x, y; - const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - /* Build VBO */ const int has_mask = key->has_mask; - uint vert_per_grid = (smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4); - uint vert_count = totgrid * vert_per_grid; - - if (buffers->smooth != smooth) { - buffers->smooth = smooth; - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - } + uint vert_per_grid = (buffers->smooth) ? key->grid_area : (SQUARE(key->grid_size - 1) * 4); + uint vert_count = totgrid * vert_per_grid; if (buffers->index_buf == NULL) { uint visible_quad_len = BKE_pbvh_count_grid_quads( @@ -692,6 +731,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, buffers->show_mask = !empty_mask; } +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden) { GPU_PBVH_Buffers *buffers; @@ -713,47 +753,36 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid /** \name BMesh PBVH * \{ */ -/* Output a BMVert into a VertexBufferFormat array - * - * The vertex is skipped if hidden, otherwise the output goes into - * index '*v_index' in the 'vert_data' array and '*v_index' is - * incremented. - */ -static void gpu_bmesh_vert_to_buffer_copy__gwn(BMVert *v, - GPUVertBuf *vert_buf, - int *v_index, - const float fno[3], - const float *fmask, - const int cd_vert_mask_offset, - const bool show_mask, - const bool show_vcol, - bool *empty_mask) +/* Output a BMVert into a VertexBufferFormat array at v_index. */ +static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, + GPUVertBuf *vert_buf, + int v_index, + const float fno[3], + const float *fmask, + const int cd_vert_mask_offset, + const bool show_mask, + const bool show_vcol, + bool *empty_mask) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + /* Vertex should always be visible if it's used by a visible face. */ + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN)); - /* Set coord, normal, and mask */ - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co); + /* Set coord, normal, and mask */ + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co); - short no_short[3]; - normal_float_to_short_v3(no_short, fno ? fno : v->no); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short); + short no_short[3]; + normal_float_to_short_v3(no_short, fno ? fno : v->no); + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short); - if (show_mask) { - float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, *v_index, &effective_mask); - *empty_mask = *empty_mask && (effective_mask == 0.0f); - } - - if (show_vcol) { - static char vcol[4] = {255, 255, 255, 255}; - GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, *v_index, &vcol); - } - - /* Assign index for use in the triangle index buffer */ - /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ - BM_elem_index_set(v, (*v_index)); /* set_dirty! */ + if (show_mask) { + float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &effective_mask); + *empty_mask = *empty_mask && (effective_mask == 0.0f); + } - (*v_index)++; + if (show_vcol) { + static char vcol[4] = {255, 255, 255, 255}; + GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol); } } @@ -796,8 +825,24 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces) return totface; } +void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) +{ + if (buffers->smooth) { + /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + } + else { + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + } +} + /* Creates a vertex buffer (coordinate, normal, color) and, if smooth - * shading, an element index buffer. */ + * shading, an element index buffer. + * Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, BMesh *bm, GSet *bm_faces, @@ -807,7 +852,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, { const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; - int tottri, totvert, maxvert = 0; + int tottri, totvert; bool empty_mask = true; BMFace *f = NULL; @@ -815,17 +860,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, tottri = gpu_bmesh_face_visible_count(bm_faces); if (buffers->smooth) { - /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); /* Count visible vertices */ totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts); } else { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); totvert = tottri * 3; } @@ -834,9 +872,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /* Node is just hidden. */ } else { - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->clear_bmesh_on_flush = true; } buffers->tot_tri = 0; return; @@ -846,135 +882,118 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); /* Fill vertex buffer */ - if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) { - int v_index = 0; - - if (buffers->smooth) { - GSetIterator gs_iter; - - /* Vertices get an index assigned for use in the triangle - * index buffer */ - bm->elem_index_dirty |= BM_VERT; - - GSET_ITER (gs_iter, bm_unique_verts) { - gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, - &v_index, - NULL, - NULL, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - } - - GSET_ITER (gs_iter, bm_other_verts) { - gpu_bmesh_vert_to_buffer_copy__gwn(BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, - &v_index, - NULL, - NULL, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - } + if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) { + /* Memory map failed */ + return; + } - maxvert = v_index; - } - else { - GSetIterator gs_iter; + int v_index = 0; - GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); + if (buffers->smooth) { + /* Fill the vertex and triangle buffer in one pass over faces. */ + GPUIndexBufBuilder elb, elb_lines; + GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert); + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); + GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert); - BLI_assert(f->len == 3); + GSetIterator gs_iter; + GSET_ITER (gs_iter, bm_faces) { + f = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; - float fmask = 0.0f; - int i; + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BMVert *v[3]; + BM_face_as_array_vert_tri(f, v); - BM_face_as_array_vert_tri(f, v); + uint idx[3]; + for (int i = 0; i < 3; i++) { + void **idx_p; + if (!BLI_ghash_ensure_p(bm_vert_to_index, v[i], &idx_p)) { + /* Add vertex to the vertex buffer each time a new one is encountered */ + *idx_p = POINTER_FROM_UINT(v_index); - /* Average mask value */ - for (i = 0; i < 3; i++) { - fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset); + gpu_bmesh_vert_to_buffer_copy(v[i], + buffers->vert_buf, + v_index, + NULL, + NULL, + cd_vert_mask_offset, + show_mask, + show_vcol, + &empty_mask); + + idx[i] = v_index; + v_index++; } - fmask /= 3.0f; - - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); - - for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy__gwn(v[i], - buffers->vert_buf, - &v_index, - f->no, - &fmask, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); + else { + /* Vertex already in the vertex buffer, just get the index. */ + idx[i] = POINTER_AS_UINT(*idx_p); } } - } - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - buffers->tot_tri = tottri; + GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); + + GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]); + GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]); + GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]); + } } - /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ - bm->elem_index_dirty |= BM_VERT; + BLI_ghash_free(bm_vert_to_index, NULL, NULL); + + buffers->tot_tri = tottri; + if (buffers->index_buf == NULL) { + buffers->index_buf = GPU_indexbuf_build(&elb); + } + else { + GPU_indexbuf_build_in_place(&elb, buffers->index_buf); + } + buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); } else { - /* Memory map failed */ - return; - } + GSetIterator gs_iter; - if (buffers->smooth) { - /* Fill the triangle buffer */ - GPUIndexBufBuilder elb, elb_lines; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, maxvert); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, maxvert); - - /* Fill triangle index buffer */ - { - GSetIterator gs_iter; + GPUIndexBufBuilder elb_lines; + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3); - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); + GSET_ITER (gs_iter, bm_faces) { + f = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; + BLI_assert(f->len == 3); - BM_face_as_array_vert_tri(f, v); + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BMVert *v[3]; + float fmask = 0.0f; + int i; - const uint idx[3] = { - BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2])}; - GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); + BM_face_as_array_vert_tri(f, v); - GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]); + /* Average mask value */ + for (i = 0; i < 3; i++) { + fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset); + } + fmask /= 3.0f; + + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); + + for (i = 0; i < 3; i++) { + gpu_bmesh_vert_to_buffer_copy(v[i], + buffers->vert_buf, + v_index++, + f->no, + &fmask, + cd_vert_mask_offset, + show_mask, + show_vcol, + &empty_mask); } } - - buffers->tot_tri = tottri; - - if (buffers->index_buf == NULL) { - buffers->index_buf = GPU_indexbuf_build(&elb); - } - else { - GPU_indexbuf_build_in_place(&elb, buffers->index_buf); - } - - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); } + + buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); + buffers->tot_tri = tottri; } /* Get material index from the last face we iterated on. */ @@ -991,6 +1010,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /** \name Generic * \{ */ +/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) { GPU_PBVH_Buffers *buffers; @@ -1023,6 +1043,22 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) return buffers->material_index; } +void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) +{ + /* Free empty bmesh node buffers. */ + if (buffers->clear_bmesh_on_flush) { + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->clear_bmesh_on_flush = false; + } + + /* Force flushing to the GPU. */ + if (buffers->vert_buf && buffers->vert_buf->data) { + GPU_vertbuf_use(buffers->vert_buf); + } +} + void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { @@ -1041,7 +1077,3 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) } /** \} */ - -void GPU_pbvh_fix_linking() -{ -} diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 7483be74e01..410e23c9576 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -55,6 +55,12 @@ #include <string.h> #include <stdarg.h> +extern char datatoc_gpu_shader_material_glsl[]; +extern char datatoc_gpu_shader_geometry_glsl[]; + +extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + /* -------------------- GPUPass Cache ------------------ */ /** * Internal shader cache: This prevent the shader recompilation / stall when @@ -778,6 +784,12 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final else if (input->builtin == GPU_OBJECT_MATRIX) { BLI_dynstr_append(ds, "objmat"); } + else if (input->builtin == GPU_OBJECT_INFO) { + BLI_dynstr_append(ds, "ObjectInfo"); + } + else if (input->builtin == GPU_OBJECT_COLOR) { + BLI_dynstr_append(ds, "ObjectColor"); + } else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) { BLI_dynstr_append(ds, "objinv"); } @@ -840,6 +852,10 @@ static char *code_generate_fragment(GPUMaterial *material, codegen_set_unique_ids(nodes); *rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes); + if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) { + BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); + } + if (builtins & GPU_BARYCENTRIC_TEXCO) { BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n"); } @@ -988,7 +1004,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ if (input->attr_type == CD_ORCO) { /* OPTI : orco is computed from local positions, but only if no modifier is present. */ - BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n"); + BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); } else if (input->attr_name[0] == '\0') { @@ -1070,6 +1086,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "\n"); + BLI_dynstr_append(ds, use_geom ? "RESOURCE_ID_VARYING_GEOM\n" : "RESOURCE_ID_VARYING\n"); + BLI_dynstr_append(ds, "#define USE_ATTR\n" "vec3 srgb_to_linear_attr(vec3 c) {\n" @@ -1099,6 +1117,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n"); + BLI_dynstr_append(ds, use_geom ? "\tPASS_RESOURCE_ID_GEOM\n" : "\tPASS_RESOURCE_ID\n"); + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); if (builtins & GPU_BARYCENTRIC_TEXCO) { @@ -1125,8 +1145,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u } else if (input->attr_type == CD_ORCO) { BLI_dynstr_appendf(ds, - "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * " - "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n", + "\tvar%d%s = OrcoTexCoFactors[0].xyz + (ModelMatrixInverse * " + "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1].xyz;\n", input->attr_id, use_geom ? "g" : ""); /* TODO: fix ORCO with modifiers. */ @@ -1181,7 +1201,8 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u } else if (input->attr_type == CD_ORCO) { BLI_dynstr_appendf(ds, - "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", + "\tvar%d%s = OrcoTexCoFactors[0].xyz + position *" + " OrcoTexCoFactors[1].xyz;\n", input->attr_id, use_geom ? "g" : ""); /* See mesh_create_loop_orco() for explanation. */ @@ -1296,6 +1317,8 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons BLI_dynstr_append(ds, "out vec3 worldNormal;\n"); BLI_dynstr_append(ds, "out vec3 viewNormal;\n"); + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); + BLI_dynstr_append(ds, "void main(){\n"); if (builtins & GPU_BARYCENTRIC_DIST) { @@ -1340,9 +1363,13 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code, cons BLI_dynstr_append(ds, "}\n"); } + BLI_dynstr_append(ds, "RESOURCE_ID_VARYING\n"); + /* Generate varying assignments. */ BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n"); + BLI_dynstr_append(ds, "\tPASS_RESOURCE_ID(vert)\n"); + /* XXX HACK: Eevee specific. */ if (geom_code == NULL) { BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n"); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index c9ae6c60293..7fa2eb6424c 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -66,6 +66,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "PIL_time.h" diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c index 166a6236893..518829d1c78 100644 --- a/source/blender/gpu/intern/gpu_element.c +++ b/source/blender/gpu/intern/gpu_element.c @@ -243,7 +243,7 @@ GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uin { GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); BLI_assert(elem_src && !elem_src->is_subrange); - BLI_assert(start + length <= elem_src->index_len); + BLI_assert((length == 0) || (start + length <= elem_src->index_len)); #if GPU_TRACK_INDEX_RANGE elem->index_type = elem_src->index_type; elem->gl_index_type = elem_src->gl_index_type; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 4164db2c469..33f918559f7 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -35,6 +35,7 @@ #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_texture.h" +#include "GPU_platform.h" #include "intern/gpu_private.h" @@ -68,9 +69,6 @@ static struct GPUGlobal { GLint maxubosize; GLint maxubobinds; int samples_color_texture_max; - eGPUDeviceType device; - eGPUOSType os; - eGPUDriverType driver; float line_width_range[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers * calculate dfdy in shader differently when drawing to an offscreen buffer. First @@ -126,13 +124,6 @@ static void gpu_detect_mip_render_workaround(void) GPU_texture_free(tex); } -/* GPU Types */ - -bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) -{ - return (GG.device & device) && (GG.os & os) && (GG.driver & driver); -} - /* GPU Extensions */ int GPU_max_texture_size(void) @@ -266,11 +257,7 @@ void gpu_extensions_init(void) const char *renderer = (const char *)glGetString(GL_RENDERER); const char *version = (const char *)glGetString(GL_VERSION); - if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OFFICIAL; - -#ifdef _WIN32 + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL)) { if (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") || strstr(version, "4.5.13422")) { /* The renderers include: @@ -282,76 +269,15 @@ void gpu_extensions_init(void) GG.unused_fb_slot_workaround = true; } -#endif + } -#if defined(__APPLE__) + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) { if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") || strstr(renderer, "AMD Radeon RX")) { GG.depth_blitting_workaround = true; } -#endif - } - else if (strstr(vendor, "NVIDIA")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OFFICIAL; - } - else if (strstr(vendor, "Intel") || - /* src/mesa/drivers/dri/intel/intel_context.c */ - strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { - GG.device = GPU_DEVICE_INTEL; - GG.driver = GPU_DRIVER_OFFICIAL; - - if (strstr(renderer, "UHD Graphics") || - /* Not UHD but affected by the same bugs. */ - strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { - GG.device |= GPU_DEVICE_INTEL_UHD; - } - } - else if ((strstr(renderer, "Mesa DRI R")) || - (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || - (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || - (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { - GG.device = GPU_DEVICE_ATI; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { - GG.device = GPU_DEVICE_NVIDIA; - GG.driver = GPU_DRIVER_OPENSOURCE; - } - else if (strstr(vendor, "Mesa")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(vendor, "Microsoft")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "Apple Software Renderer")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else if (strstr(renderer, "llvmpipe")) { - GG.device = GPU_DEVICE_SOFTWARE; - GG.driver = GPU_DRIVER_SOFTWARE; - } - else { - printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); - printf("Detected OpenGL configuration:\n"); - printf("Vendor: %s\n", vendor); - printf("Renderer: %s\n", renderer); - GG.device = GPU_DEVICE_ANY; - GG.driver = GPU_DRIVER_ANY; } -#ifdef _WIN32 - GG.os = GPU_OS_WIN; -#elif defined(__APPLE__) - GG.os = GPU_OS_MAC; -#else - GG.os = GPU_OS_UNIX; -#endif - GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; gpu_detect_mip_render_workaround(); @@ -365,18 +291,19 @@ void gpu_extensions_init(void) GG.mip_render_workaround = true; GG.depth_blitting_workaround = true; GG.unused_fb_slot_workaround = true; - GG.context_local_shaders_workaround = true; + GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; } /* df/dy calculation factors, those are dependent on driver */ GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = 1.0; - if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) { + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) && + strstr(version, "3.3.10750")) { GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = -1.0; } - else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN)) { + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { if (strstr(version, "4.0.0 - Build 10.18.10.3308") || strstr(version, "4.0.0 - Build 9.18.10.3186") || strstr(version, "4.0.0 - Build 9.18.10.3165") || @@ -395,6 +322,16 @@ void gpu_extensions_init(void) GG.glew_arb_base_instance_is_supported = false; GG.context_local_shaders_workaround = true; } + + if (strstr(version, "Build 20.19.15.4285")) { + /* Somehow fixes armature display issues (see T69743). */ + GG.context_local_shaders_workaround = true; + } + } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { + /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the + * Mesa driver */ + GG.unused_fb_slot_workaround = true; } GPU_invalid_tex_init(); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 1b68e4c85f7..a531c22365c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -132,9 +132,11 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) const char *err = "unknown"; #define FORMAT_STATUS(X) \ - case GL_FRAMEBUFFER_##X: \ + case GL_FRAMEBUFFER_##X: { \ err = "GL_FRAMEBUFFER_" #X; \ - break; + break; \ + } \ + ((void)0) switch (status) { /* success */ diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 2f84a1cbd27..7b6016e11cb 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -46,7 +46,7 @@ void GPU_init(void) } initialized = true; - + gpu_platform_init(); gpu_extensions_init(); /* must come first */ gpu_codegen_init(); @@ -62,11 +62,13 @@ void GPU_init(void) immInit(); } - GPU_pbvh_fix_linking(); + gpu_pbvh_init(); } void GPU_exit(void) { + gpu_pbvh_exit(); + if (!G.background) { immDestroy(); } @@ -80,7 +82,8 @@ void GPU_exit(void) gpu_framebuffer_module_exit(); gpu_codegen_exit(); - gpu_extensions_exit(); /* must come last */ + gpu_extensions_exit(); + gpu_platform_exit(); /* must come last */ initialized = false; } diff --git a/source/blender/gpu/intern/gpu_platform.c b/source/blender/gpu/intern/gpu_platform.c new file mode 100644 index 00000000000..871052bb070 --- /dev/null +++ b/source/blender/gpu/intern/gpu_platform.c @@ -0,0 +1,229 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Wrap OpenGL features such as textures, shaders and GLSL + * with checks for drivers and GPU support. + */ +#include "GPU_platform.h" +#include "GPU_glew.h" +#include "gpu_private.h" + +#include <string.h> + +#include "BLI_dynstr.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +static struct GPUPlatformGlobal { + bool initialized; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + eGPUSupportLevel support_level; + char *support_key; + char *gpu_name; +} GPG = {false}; + +typedef struct GPUPlatformSupportTest { + eGPUSupportLevel support_level; + eGPUDeviceType device; + eGPUOSType os; + eGPUDriverType driver; + const char *vendor; + const char *renderer; + const char *version; +} GPUPlatformSupportTest; + +eGPUSupportLevel GPU_platform_support_level(void) +{ + return GPG.support_level; +} + +const char *GPU_platform_support_level_key(void) +{ + return GPG.support_key; +} + +const char *GPU_platform_gpu_name(void) +{ + return GPG.gpu_name; +} + +/* GPU Types */ +bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) +{ + return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver); +} + +static char *gpu_platform_create_key(eGPUSupportLevel support_level, + const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, "{"); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, "/"); + BLI_dynstr_append(ds, version); + BLI_dynstr_append(ds, "}"); + BLI_dynstr_append(ds, "="); + if (support_level == GPU_SUPPORT_LEVEL_SUPPORTED) { + BLI_dynstr_append(ds, "SUPPORTED"); + } + else if (support_level == GPU_SUPPORT_LEVEL_LIMITED) { + BLI_dynstr_append(ds, "LIMITED"); + } + else { + BLI_dynstr_append(ds, "UNSUPPORTED"); + } + + char *support_key = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(support_key, '\n', ' '); + BLI_str_replace_char(support_key, '\r', ' '); + return support_key; +} + +static char *gpu_platform_create_gpu_name(const char *vendor, + const char *renderer, + const char *version) +{ + DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, vendor); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, renderer); + BLI_dynstr_append(ds, " "); + BLI_dynstr_append(ds, version); + + char *gpu_name = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + BLI_str_replace_char(gpu_name, '\n', ' '); + BLI_str_replace_char(gpu_name, '\r', ' '); + return gpu_name; +} + +void gpu_platform_init(void) +{ + if (GPG.initialized) { + return; + } + +#ifdef _WIN32 + GPG.os = GPU_OS_WIN; +#elif defined(__APPLE__) + GPG.os = GPU_OS_MAC; +#else + GPG.os = GPU_OS_UNIX; +#endif + + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); + + if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "NVIDIA")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "Intel") || + /* src/mesa/drivers/dri/intel/intel_context.c */ + strstr(renderer, "Mesa DRI Intel") || strstr(renderer, "Mesa DRI Mobile Intel")) { + GPG.device = GPU_DEVICE_INTEL; + GPG.driver = GPU_DRIVER_OFFICIAL; + + if (strstr(renderer, "UHD Graphics") || + /* Not UHD but affected by the same bugs. */ + strstr(renderer, "HD Graphics 530") || strstr(renderer, "Kaby Lake GT2")) { + GPG.device |= GPU_DEVICE_INTEL_UHD; + } + } + else if ((strstr(renderer, "Mesa DRI R")) || + (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) || + (strstr(renderer, "AMD") && strstr(vendor, "X.Org")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) { + GPG.device = GPU_DEVICE_ATI; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) { + GPG.device = GPU_DEVICE_NVIDIA; + GPG.driver = GPU_DRIVER_OPENSOURCE; + } + else if (strstr(vendor, "Mesa")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(vendor, "Microsoft")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "Apple Software Renderer")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) { + GPG.device = GPU_DEVICE_SOFTWARE; + GPG.driver = GPU_DRIVER_SOFTWARE; + } + else { + printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); + printf("Detected OpenGL configuration:\n"); + printf("Vendor: %s\n", vendor); + printf("Renderer: %s\n", renderer); + GPG.device = GPU_DEVICE_ANY; + GPG.driver = GPU_DRIVER_ANY; + } + + /* Detect support level */ + if (!GLEW_VERSION_3_3) { + GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + } + else { + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { + /* Old Intel drivers with known bugs that cause material properties to crash. + * Version Build 10.18.14.5067 is the latest available and appears to be working + * ok with our workarounds, so excluded from this list. */ + if (strstr(version, "Build 7.14") || strstr(version, "Build 7.15") || + strstr(version, "Build 8.15") || strstr(version, "Build 9.17") || + strstr(version, "Build 9.18") || strstr(version, "Build 10.18.10.3") || + strstr(version, "Build 10.18.10.4") || strstr(version, "Build 10.18.10.5") || + strstr(version, "Build 10.18.14.4")) { + GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; + } + } + } + GPG.support_key = gpu_platform_create_key(GPG.support_level, vendor, renderer, version); + GPG.gpu_name = gpu_platform_create_gpu_name(vendor, renderer, version); + GPG.initialized = true; +} + +void gpu_platform_exit(void) +{ + MEM_SAFE_FREE(GPG.support_key); + MEM_SAFE_FREE(GPG.gpu_name); +} diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h index 43b2da13e28..7846bff87f4 100644 --- a/source/blender/gpu/intern/gpu_private.h +++ b/source/blender/gpu/intern/gpu_private.h @@ -22,6 +22,10 @@ #define __GPU_PRIVATE_H__ /* call this before running any of the functions below */ +void gpu_platform_init(void); +void gpu_platform_exit(void); + +/* call this before running any of the functions below */ void gpu_extensions_init(void); void gpu_extensions_exit(void); @@ -33,4 +37,8 @@ void gpu_debug_exit(void); void gpu_framebuffer_module_init(void); void gpu_framebuffer_module_exit(void); +/* gpu_pbvh.c */ +void gpu_pbvh_init(void); +void gpu_pbvh_exit(void); + #endif /* __GPU_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 42c21626c05..5df73d1a0c6 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -36,6 +36,7 @@ #include "DNA_space_types.h" #include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -248,6 +249,9 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) /* a #version 400 feature, but we use #version 330 maximum so use extension */ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); } + if (GLEW_ARB_shader_draw_parameters) { + strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n"); + } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) @@ -255,6 +259,9 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { strcat(defines, "#define GPU_ATI\n"); + if (GPU_crappy_amd_driver()) { + strcat(defines, "#define GPU_DEPRECATED_AMD_DRIVER\n"); + } } else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { strcat(defines, "#define GPU_NVIDIA\n"); diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 083c5bf2b60..983c5dfc27a 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -65,9 +65,8 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_CLIPPLANES] = "WorldClipPlanes", [GPU_UNIFORM_COLOR] = "color", - [GPU_UNIFORM_CALLID] = "callId", - [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo", - [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor", + [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance", + [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk", [GPU_UNIFORM_CUSTOM] = NULL, [GPU_NUM_UNIFORMS] = NULL, diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index a54d90f37f5..497fc13a2c8 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -38,6 +38,7 @@ #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_framebuffer.h" +#include "GPU_platform.h" #include "GPU_texture.h" #include "gpu_context_private.h" diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index fcb1a008226..615af57c1bd 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -39,6 +39,7 @@ #include "GPU_immediate.h" #include "GPU_texture.h" #include "GPU_viewport.h" +#include "GPU_uniformbuffer.h" #include "DRW_engine.h" @@ -619,11 +620,20 @@ void GPU_viewport_free(GPUViewport *viewport) MEM_freeN(viewport->fbl); MEM_freeN(viewport->txl); - if (viewport->vmempool.calls != NULL) { - BLI_memblock_destroy(viewport->vmempool.calls, NULL); + if (viewport->vmempool.commands != NULL) { + BLI_memblock_destroy(viewport->vmempool.commands, NULL); } - if (viewport->vmempool.states != NULL) { - BLI_memblock_destroy(viewport->vmempool.states, NULL); + if (viewport->vmempool.commands_small != NULL) { + BLI_memblock_destroy(viewport->vmempool.commands_small, NULL); + } + if (viewport->vmempool.callbuffers != NULL) { + BLI_memblock_destroy(viewport->vmempool.callbuffers, NULL); + } + if (viewport->vmempool.obmats != NULL) { + BLI_memblock_destroy(viewport->vmempool.obmats, NULL); + } + if (viewport->vmempool.obinfos != NULL) { + BLI_memblock_destroy(viewport->vmempool.obinfos, NULL); } if (viewport->vmempool.cullstates != NULL) { BLI_memblock_destroy(viewport->vmempool.cullstates, NULL); @@ -650,6 +660,13 @@ void GPU_viewport_free(GPUViewport *viewport) BLI_memblock_destroy(viewport->vmempool.images, NULL); } + for (int i = 0; i < viewport->vmempool.ubo_len; i++) { + GPU_uniformbuffer_free(viewport->vmempool.matrices_ubo[i]); + GPU_uniformbuffer_free(viewport->vmempool.obinfos_ubo[i]); + } + MEM_SAFE_FREE(viewport->vmempool.matrices_ubo); + MEM_SAFE_FREE(viewport->vmempool.obinfos_ubo); + DRW_instance_data_list_free(viewport->idatalist); MEM_freeN(viewport->idatalist); diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl new file mode 100644 index 00000000000..aa1d437c307 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl @@ -0,0 +1,19 @@ + +/* Need to be included after common_view_lib.glsl for resource_id. */ +#ifndef GPU_OBINFOS_UBO +#define GPU_OBINFOS_UBO +struct ObjectInfos { + vec4 drw_OrcoTexCoFactors[2]; + vec4 drw_ObjectColor; + vec4 drw_Infos; +}; + +layout(std140) uniform infoBlock +{ + /* DRW_RESOURCE_CHUNK_LEN = 512 */ + ObjectInfos drw_infos[512]; +}; +#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) +#define ObjectInfo (drw_infos[resource_id].drw_Infos) +#define ObjectColor (drw_infos[resource_id].drw_ObjectColor) +#endif diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl index 31b359dbe6d..f32c47bcec3 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl @@ -1,8 +1,5 @@ uniform mat4 ViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif /* ---- Instantiated Attrs ---- */ in float pos; @@ -47,11 +44,12 @@ void main() pPos = vec3(0.0); } - gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0); + vec4 wPos = InstanceModelMatrix * vec4(pPos, 1.0); + gl_Position = ViewProjectionMatrix * wPos; finalColor = vec4(color, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * vec4(pPos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(wPos.xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl index d9a0ffbbdac..5bd29c55e42 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl @@ -18,13 +18,14 @@ void main() { float len = end - start; vec3 sta = vec3(0.0, 0.0, -start); - vec4 pos_4d = vec4(pos * -len + sta, 1.0); - gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d; + vec4 wPos = InstanceModelMatrix * vec4(pos * -len + sta, 1.0); + + gl_Position = ViewProjectionMatrix * wPos; gl_PointSize = size; finalColor = vec4(color, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((InstanceModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(wPos.xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl index 3e52e43beae..10228a1e985 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl @@ -1,6 +1,5 @@ uniform mat4 ViewProjectionMatrix; -uniform mat4 ModelMatrix; /* ---- Instantiated Attrs ---- */ in vec3 pos; @@ -20,10 +19,10 @@ void main() { finalColor = color; - vec4 pos_4d = vec4(pos * size, 1.0); - gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d; + vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0); + gl_Position = ViewProjectionMatrix * wPos; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(wPos.xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl index 130f46e1e33..32db8d17572 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl @@ -1,8 +1,6 @@ uniform mat4 ViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif + uniform int baseId; /* ---- Instantiated Attrs ---- */ @@ -21,11 +19,11 @@ flat out uint finalId; void main() { - vec4 pos_4d = vec4(pos * size, 1.0); - gl_Position = ViewProjectionMatrix * InstanceModelMatrix * pos_4d; + vec4 wPos = InstanceModelMatrix * vec4(pos * size, 1.0); + gl_Position = ViewProjectionMatrix * wPos; finalId = uint(baseId + callId); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * InstanceModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(wPos.xyz); #endif } diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl index eeca6e972fa..b8d31f5540a 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl @@ -9,5 +9,5 @@ in mat4 InstanceModelMatrix; void main() { - gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0)); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl index abe6081489d..e089aec1d92 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl @@ -92,14 +92,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol) void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = min(col1.rgb, col2.rgb * fac); + outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac); outcol.a = col1.a; } void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol.rgb = max(col1.rgb, col2.rgb * fac); + outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac); outcol.a = col1.a; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 140213a9ed9..7af409dd410 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -113,14 +113,14 @@ void node_bsdf_principled(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec + out_refr; result.radiance += out_diff * out_sheen; /* Coarse approx. */ + result.radiance += emission.rgb; + result.radiance *= alpha; closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); mixed_ss_base_color *= alpha * (1.0 - transmission); closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.radiance += emission.rgb; - result.radiance *= alpha; result.transmittance = vec3(1.0 - alpha); } @@ -169,9 +169,11 @@ void node_bsdf_principled_dielectric(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec + out_diff * (diffuse + out_sheen); - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -213,9 +215,11 @@ void node_bsdf_principled_metallic(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -267,9 +271,11 @@ void node_bsdf_principled_clearcoat(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + result.transmittance = vec3(1.0 - alpha); } @@ -333,14 +339,15 @@ void node_bsdf_principled_subsurface(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = out_spec; + result.radiance += out_diff * out_sheen; + result.radiance += emission.rgb; + result.radiance *= alpha; + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); mixed_ss_base_color *= alpha * (1.0 - transmission); closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.radiance += out_diff * out_sheen; - result.radiance += emission.rgb; - result.radiance *= alpha; result.transmittance = vec3(1.0 - alpha); } @@ -402,9 +409,9 @@ void node_bsdf_principled_glass(vec4 base_color, result = CLOSURE_DEFAULT; result.radiance = mix(out_refr, out_spec, fresnel); - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.radiance += emission.rgb; result.radiance *= alpha; + closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); result.transmittance = vec3(1.0 - alpha); } #else diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 7e7e489a6c3..173c8135f96 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -218,15 +218,20 @@ typedef enum IMB_BlendMode { } IMB_BlendMode; void IMB_blend_color_byte(unsigned char dst[4], - unsigned char src1[4], - unsigned char src2[4], + const unsigned char src1[4], + const unsigned char src2[4], IMB_BlendMode mode); -void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode); +void IMB_blend_color_float(float dst[4], + const float src1[4], + const float src2[4], + IMB_BlendMode mode); void IMB_rect_crop(struct ImBuf *ibuf, const struct rcti *crop); +void IMB_rect_size_set(struct ImBuf *ibuf, const uint size[2]); + void IMB_rectclip(struct ImBuf *dbuf, - struct ImBuf *sbuf, + const struct ImBuf *sbuf, int *destx, int *desty, int *srcx, @@ -234,7 +239,7 @@ void IMB_rectclip(struct ImBuf *dbuf, int *width, int *height); void IMB_rectcpy(struct ImBuf *drect, - struct ImBuf *srect, + const struct ImBuf *srect, int destx, int desty, int srcx, @@ -242,11 +247,11 @@ void IMB_rectcpy(struct ImBuf *drect, int width, int height); void IMB_rectblend(struct ImBuf *dbuf, - struct ImBuf *obuf, - struct ImBuf *sbuf, + const struct ImBuf *obuf, + const struct ImBuf *sbuf, unsigned short *dmask, - unsigned short *curvemask, - unsigned short *mmask, + const unsigned short *curvemask, + const unsigned short *mmask, float mask_max, int destx, int desty, @@ -259,11 +264,11 @@ void IMB_rectblend(struct ImBuf *dbuf, IMB_BlendMode mode, bool accumulate); void IMB_rectblend_threaded(struct ImBuf *dbuf, - struct ImBuf *obuf, - struct ImBuf *sbuf, + const struct ImBuf *obuf, + const struct ImBuf *sbuf, unsigned short *dmask, - unsigned short *curvemask, - unsigned short *mmask, + const unsigned short *curvemask, + const unsigned short *mmask, float mask_max, int destx, int desty, @@ -477,7 +482,7 @@ int imb_get_anim_type(const char *name); * * \attention Defined in util.c */ -bool IMB_isfloat(struct ImBuf *ibuf); +bool IMB_isfloat(const struct ImBuf *ibuf); /* Do byte/float and colorspace conversions need to take alpha into account? */ bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf); @@ -695,6 +700,8 @@ void imb_freemipmapImBuf(struct ImBuf *ibuf); bool imb_addtilesImBuf(struct ImBuf *ibuf); void imb_freetilesImBuf(struct ImBuf *ibuf); +void imb_freerectImbuf_all(struct ImBuf *ibuf); + /* threaded processors */ void IMB_processor_apply_threaded( int buffer_lines, diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 065c7e64d07..9ad88f24693 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -89,7 +89,7 @@ struct anim { int ib_flags; int curtype; int curposition; /* index 0 = 1e, 1 = 2e, enz. */ - int duration; + int duration_in_frames; int frs_sec; double frs_sec_base; int x, y; diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 5048414ac65..52db0b80441 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -33,7 +33,7 @@ typedef struct ImFileType { int (*is_a)(const unsigned char *buf); int (*is_a_filepath)(const char *name); - int (*ftype)(const struct ImFileType *type, struct ImBuf *ibuf); + int (*ftype)(const struct ImFileType *type, const struct ImBuf *ibuf); struct ImBuf *(*load)(const unsigned char *mem, size_t size, int flags, diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 75db3fd3c73..381de9de610 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -197,6 +197,17 @@ void IMB_freezbuffloatImBuf(ImBuf *ibuf) ibuf->mall &= ~IB_zbuffloat; } +/** Free all pixel data (assosiated with image size). */ +void imb_freerectImbuf_all(ImBuf *ibuf) +{ + imb_freerectImBuf(ibuf); + imb_freerectfloatImBuf(ibuf); + imb_freetilesImBuf(ibuf); + IMB_freezbufImBuf(ibuf); + IMB_freezbuffloatImBuf(ibuf); + freeencodedbufferImBuf(ibuf); +} + void IMB_freeImBuf(ImBuf *ibuf) { if (ibuf) { @@ -212,12 +223,7 @@ void IMB_freeImBuf(ImBuf *ibuf) BLI_spin_unlock(&refcounter_spin); if (needs_free) { - imb_freerectImBuf(ibuf); - imb_freerectfloatImBuf(ibuf); - imb_freetilesImBuf(ibuf); - IMB_freezbufImBuf(ibuf); - IMB_freezbuffloatImBuf(ibuf); - freeencodedbufferImBuf(ibuf); + imb_freerectImbuf_all(ibuf); IMB_metadata_free(ibuf->metadata); colormanage_cache_free(ibuf); diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 52d8db95054..232a9998ebf 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -199,7 +199,7 @@ static void free_anim_avi(struct anim *anim) } # endif - anim->duration = 0; + anim->duration_in_frames = 0; } #endif /* WITH_AVI */ @@ -408,7 +408,7 @@ static int startavi(struct anim *anim) return -1; } - anim->duration = anim->avi->header->TotalFrames; + anim->duration_in_frames = anim->avi->header->TotalFrames; anim->params = NULL; anim->x = anim->avi->header->Width; @@ -426,7 +426,7 @@ static int startavi(struct anim *anim) anim->y, anim->framesize, anim->interlacing, - anim->duration); + anim->duration_in_frames); # endif return 0; @@ -493,12 +493,13 @@ BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim) static int startffmpeg(struct anim *anim) { - int i, videoStream; + int i, video_stream_index; AVCodec *pCodec; AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx; AVRational frame_rate; + AVStream *video_stream; int frs_num; double frs_den; int streamcount; @@ -528,7 +529,7 @@ static int startffmpeg(struct anim *anim) av_dump_format(pFormatCtx, 0, anim->name, 0); /* Find the video stream */ - videoStream = -1; + video_stream_index = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -536,17 +537,18 @@ static int startffmpeg(struct anim *anim) streamcount--; continue; } - videoStream = i; + video_stream_index = i; break; } } - if (videoStream == -1) { + if (video_stream_index == -1) { avformat_close_input(&pFormatCtx); return -1; } - pCodecCtx = pFormatCtx->streams[videoStream]->codec; + video_stream = pFormatCtx->streams[video_stream_index]; + pCodecCtx = video_stream->codec; /* Find the decoder for the video stream */ pCodec = avcodec_find_decoder(pCodecCtx->codec_id); @@ -567,12 +569,29 @@ static int startffmpeg(struct anim *anim) return -1; } - frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]); - if (pFormatCtx->streams[videoStream]->nb_frames != 0) { - anim->duration = pFormatCtx->streams[videoStream]->nb_frames; + frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL); + anim->duration_in_frames = 0; + + /* Take from the stream if we can. */ + if (video_stream->nb_frames != 0) { + anim->duration_in_frames = video_stream->nb_frames; + + /* Sanity check on the detected duration. This is to work around corruption like reported in + * T68091. */ + if (frame_rate.den != 0 && pFormatCtx->duration > 0) { + double stream_sec = anim->duration_in_frames * av_q2d(frame_rate); + double container_sec = pFormatCtx->duration / (double)AV_TIME_BASE; + if (stream_sec > 4.0 * container_sec) { + /* The stream is significantly longer than the container duration, which is + * suspicious. */ + anim->duration_in_frames = 0; + } + } } - else { - anim->duration = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + 0.5f); + /* Fall back to the container. */ + if (anim->duration_in_frames == 0) { + anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + + 0.5f); } frs_num = frame_rate.num; @@ -596,7 +615,7 @@ static int startffmpeg(struct anim *anim) anim->pFormatCtx = pFormatCtx; anim->pCodecCtx = pCodecCtx; anim->pCodec = pCodec; - anim->videoStream = videoStream; + anim->videoStream = video_stream_index; anim->interlacing = 0; anim->orientation = 0; @@ -1038,7 +1057,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ v_st = anim->pFormatCtx->streams[anim->videoStream]; - frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st)); + frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); st_time = anim->pFormatCtx->start_time; pts_time_base = av_q2d(v_st->time_base); @@ -1222,7 +1241,7 @@ static void free_anim_ffmpeg(struct anim *anim) av_free_packet(&anim->next_packet); } } - anim->duration = 0; + anim->duration_in_frames = 0; } #endif @@ -1259,7 +1278,7 @@ static ImBuf *anim_getnew(struct anim *anim) ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace); if (ibuf) { BLI_strncpy(anim->first, anim->name, sizeof(anim->first)); - anim->duration = 1; + anim->duration_in_frames = 1; } break; case ANIM_MOVIE: @@ -1297,7 +1316,7 @@ struct ImBuf *IMB_anim_previewframe(struct anim *anim) ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE); if (ibuf) { IMB_freeImBuf(ibuf); - position = anim->duration / 2; + position = anim->duration_in_frames / 2; ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE, IMB_PROXY_NONE); } return ibuf; @@ -1333,7 +1352,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, if (position < 0) { return (NULL); } - if (position >= anim->duration) { + if (position >= anim->duration_in_frames) { return (NULL); } } @@ -1398,12 +1417,12 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) { struct anim_index *idx; if (tc == IMB_TC_NONE) { - return anim->duration; + return anim->duration_in_frames; } idx = IMB_anim_open_index(anim, tc); if (!idx) { - return anim->duration; + return anim->duration_in_frames; } return IMB_indexer_get_duration(idx); diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index d1b3bf21e23..c6f8bab325b 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -40,11 +40,11 @@ # include "dds/dds_api.h" #endif -static int imb_ftype_default(const ImFileType *type, ImBuf *ibuf) +static int imb_ftype_default(const ImFileType *type, const ImBuf *ibuf) { return (ibuf->ftype == type->filetype); } -static int imb_ftype_iris(const ImFileType *type, ImBuf *ibuf) +static int imb_ftype_iris(const ImFileType *type, const ImBuf *ibuf) { (void)type; return (ibuf->ftype == IMB_FTYPE_IMAGIC); diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 49e9c4c54d2..ec03a0a07b8 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -401,11 +401,6 @@ typedef struct ScanlineGlobalData { int total_scanlines; } ScanlineGlobalData; -typedef struct ScanlineTask { - int start_scanline; - int num_scanlines; -} ScanlineTask; - static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 66e0a681f8f..97a0cc85301 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -900,7 +900,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, stream_size = avio_size(context->iFormatCtx->pb); - context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream)); + context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL)); context->pts_time_base = av_q2d(context->iStream->time_base); while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) { diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 3bf97cb851f..e361df1304a 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -83,7 +83,7 @@ static OPJ_CODEC_FORMAT format_from_header(const unsigned char mem[JP2_FILEHEADE int imb_is_a_jp2(const unsigned char *buf) { - return check_jp2(buf); + return (check_jp2(buf) || check_j2k(buf)); } /** diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 76918c216f7..7150e41841b 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -39,8 +39,8 @@ #include "MEM_guardedalloc.h" void IMB_blend_color_byte(unsigned char dst[4], - unsigned char src1[4], - unsigned char src2[4], + const unsigned char src1[4], + const unsigned char src2[4], IMB_BlendMode mode) { switch (mode) { @@ -126,7 +126,10 @@ void IMB_blend_color_byte(unsigned char dst[4], } } -void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_BlendMode mode) +void IMB_blend_color_float(float dst[4], + const float src1[4], + const float src2[4], + IMB_BlendMode mode) { switch (mode) { case IMB_BLEND_MIX: @@ -259,7 +262,7 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop) BLI_rcti_size_x(crop) + 1, BLI_rcti_size_y(crop) + 1, }; - BLI_assert(size_dst[0] > 0 && size_dst[0] > 0); + BLI_assert(size_dst[0] > 0 && size_dst[1] > 0); BLI_assert(crop->xmin >= 0 && crop->ymin >= 0); BLI_assert(crop->xmax < ibuf->x && crop->ymax < ibuf->y); @@ -276,10 +279,49 @@ void IMB_rect_crop(ImBuf *ibuf, const rcti *crop) ibuf->y = size_dst[1]; } +/** Re-alloc buffers at a new size */ + +static void rect_realloc_4bytes(void **buf_p, const uint size[2]) +{ + if (*buf_p == NULL) { + return; + } + MEM_freeN(*buf_p); + *buf_p = MEM_mallocN(sizeof(uint) * size[0] * size[1], __func__); +} + +static void rect_realloc_16bytes(void **buf_p, const uint size[2]) +{ + if (*buf_p == NULL) { + return; + } + MEM_freeN(*buf_p); + *buf_p = MEM_mallocN(sizeof(uint[4]) * size[0] * size[1], __func__); +} + +/** + * In-place size setting (caller must fill in buffer contents). + */ +void IMB_rect_size_set(ImBuf *ibuf, const uint size[2]) +{ + BLI_assert(size[0] > 0 && size[1] > 0); + if ((size[0] == ibuf->x) && (size[1] == ibuf->y)) { + return; + } + + rect_realloc_4bytes((void **)&ibuf->rect, size); + rect_realloc_4bytes((void **)&ibuf->zbuf, size); + rect_realloc_4bytes((void **)&ibuf->zbuf_float, size); + rect_realloc_16bytes((void **)&ibuf->rect_float, size); + + ibuf->x = size[0]; + ibuf->y = size[1]; +} + /* clipping */ void IMB_rectclip(ImBuf *dbuf, - ImBuf *sbuf, + const ImBuf *sbuf, int *destx, int *desty, int *srcx, @@ -341,8 +383,8 @@ void IMB_rectclip(ImBuf *dbuf, } static void imb_rectclip3(ImBuf *dbuf, - ImBuf *obuf, - ImBuf *sbuf, + const ImBuf *obuf, + const ImBuf *sbuf, int *destx, int *desty, int *origx, @@ -435,8 +477,14 @@ static void imb_rectclip3(ImBuf *dbuf, /* copy and blend */ -void IMB_rectcpy( - ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height) +void IMB_rectcpy(ImBuf *dbuf, + const ImBuf *sbuf, + int destx, + int desty, + int srcx, + int srcy, + int width, + int height) { IMB_rectblend(dbuf, dbuf, @@ -463,11 +511,11 @@ typedef void (*IMB_blend_func)(unsigned char *dst, typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); void IMB_rectblend(ImBuf *dbuf, - ImBuf *obuf, - ImBuf *sbuf, + const ImBuf *obuf, + const ImBuf *sbuf, unsigned short *dmask, - unsigned short *curvemask, - unsigned short *texmask, + const unsigned short *curvemask, + const unsigned short *texmask, float mask_max, int destx, int desty, @@ -482,9 +530,9 @@ void IMB_rectblend(ImBuf *dbuf, { unsigned int *drect = NULL, *orect = NULL, *srect = NULL, *dr, * or, *sr; float *drectf = NULL, *orectf = NULL, *srectf = NULL, *drf, *orf, *srf; - unsigned short *cmaskrect = curvemask, *cmr; + const unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; - unsigned short *texmaskrect = texmask, *tmr; + const unsigned short *texmaskrect = texmask, *tmr; int do_float, do_char, srcskip, destskip, origskip, x; IMB_blend_func func = NULL; IMB_blend_func_float func_float = NULL; @@ -924,8 +972,10 @@ void IMB_rectblend(ImBuf *dbuf, } typedef struct RectBlendThreadData { - ImBuf *dbuf, *obuf, *sbuf; - unsigned short *dmask, *curvemask, *texmask; + ImBuf *dbuf; + const ImBuf *obuf, *sbuf; + unsigned short *dmask; + const unsigned short *curvemask, *texmask; float mask_max; int destx, desty, origx, origy; int srcx, srcy, width; @@ -956,11 +1006,11 @@ static void rectblend_thread_do(void *data_v, int start_scanline, int num_scanli } void IMB_rectblend_threaded(ImBuf *dbuf, - ImBuf *obuf, - ImBuf *sbuf, + const ImBuf *obuf, + const ImBuf *sbuf, unsigned short *dmask, - unsigned short *curvemask, - unsigned short *texmask, + const unsigned short *curvemask, + const unsigned short *texmask, float mask_max, int destx, int desty, diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index ff7cb87960e..27b566e25a2 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -252,6 +252,8 @@ static int isffmpeg(const char *filename) if (BLI_path_extension_check_n(filename, ".swf", ".jpg", + ".jp2", + ".j2c", ".png", ".dds", ".tga", @@ -389,7 +391,7 @@ bool IMB_isanim(const char *filename) return (type && type != ANIM_SEQUENCE); } -bool IMB_isfloat(ImBuf *ibuf) +bool IMB_isfloat(const ImBuf *ibuf) { const ImFileType *type; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index a1bc71ade62..f303f7720c3 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -477,6 +477,10 @@ enum { /* The datablock structure is a sub-object of a different one. * Direct persistent references are not allowed. */ LIB_PRIVATE_DATA = 1 << 10, + /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT + * tag set. But the current .blend file also has a weak pointer to it that + * we want to restore if possible, and silently drop if it's missing. */ + LIB_INDIRECT_WEAK_LINK = 1 << 11, }; /** @@ -693,6 +697,14 @@ enum { FILTER_ID_LP = (1u << 31), }; +#define FILTER_ID_ALL \ + (FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | \ + FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA | \ + FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | \ + FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | \ + FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \ + FILTER_ID_LP) + /* IMPORTANT: this enum matches the order currently use in set_listbasepointers, * keep them in sync! */ enum { diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index cf4e74dfd41..714c205cda2 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -40,7 +40,7 @@ /* BRUSH SCULPT TOOL SETTINGS */ \ .weight = 1.0f, /* weight of brush 0 - 1.0 */ \ .size = 35, /* radius of the brush in pixels */ \ - .alpha = 0.5f, /* brush strength/intensity probably variable should be renamed? */ \ + .alpha = 1.0f, /* brush strength/intensity probably variable should be renamed? */ \ .autosmooth_factor = 0.0f, \ .topology_rake_factor = 0.0f, \ .crease_pinch_factor = 0.5f, \ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index a503d3b6739..fc8763f1519 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -321,11 +321,12 @@ typedef struct Brush { int curve_preset; int automasking_flags; - char _pad1[4]; - int elastic_deform_type; float elastic_deform_volume_preservation; + /* pose */ + float pose_offset; + /* overlay */ int texture_overlay_alpha; int mask_overlay_alpha; @@ -406,7 +407,7 @@ typedef enum eBrushFlags { BRUSH_SIZE_PRESSURE = (1 << 3), BRUSH_JITTER_PRESSURE = (1 << 4), BRUSH_SPACING_PRESSURE = (1 << 5), - BRUSH_FLAG_UNUSED_6 = (1 << 6), /* cleared */ + BRUSH_ORIGINAL_PLANE = (1 << 6), BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7), BRUSH_ANCHORED = (1 << 8), BRUSH_DIR_IN = (1 << 9), @@ -498,9 +499,11 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_CLAY, \ SCULPT_TOOL_CLAY_STRIPS, \ SCULPT_TOOL_ROTATE, \ + SCULPT_TOOL_SCRAPE, \ SCULPT_TOOL_FLATTEN) -#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK) +#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) \ + ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM) #define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, SCULPT_TOOL_SNAKE_HOOK) diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index bdb3db94c89..759029ad618 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -32,7 +32,6 @@ #define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */ struct AnimData; -struct BoundBox; struct EditFont; struct GHash; struct Ipo; @@ -212,8 +211,6 @@ typedef struct Curve { /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; - struct BoundBox *bb; - /** Actual data, called splines in rna. */ ListBase nurb; @@ -229,14 +226,13 @@ typedef struct Curve { /* texture space, copied as one block in editobject.c */ float loc[3]; float size[3]; - float rot[3]; /** Creation-time type of curve datablock. */ short type; /** Keep a short because of BKE_object_obdata_texspace_get(). */ short texflag; - char _pad0[2]; + char _pad0[6]; short twist_mode; float twist_smooth, smallcaps_scale; @@ -308,6 +304,7 @@ typedef struct Curve { /* Curve.texflag */ enum { CU_AUTOSPACE = 1, + CU_AUTOSPACE_EVALUATED = 2, }; #if 0 /* Moved to overlay options in 2.8 */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 58962dd9469..3241e0e3cdb 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -404,6 +404,8 @@ typedef enum eGPDlayer_Flag { GP_LAYER_USE_MASK = (1 << 13), /* Flag used to display in Paint mode only layers with keyframe */ GP_LAYER_SOLO_MODE = (1 << 4), + /* Ruler Layer */ + GP_LAYER_IS_RULER = (1 << 14), } eGPDlayer_Flag; /* bGPDlayer->onion_flag */ diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h index 8cab90b0a46..7d56baf86a4 100644 --- a/source/blender/makesdna/DNA_gpu_types.h +++ b/source/blender/makesdna/DNA_gpu_types.h @@ -24,6 +24,7 @@ #ifndef __DNA_GPU_TYPES_H__ #define __DNA_GPU_TYPES_H__ +/* Keep for 'Camera' versioning. */ /** Properties for dof effect. */ typedef struct GPUDOFSettings { /** Focal distance for depth of field. */ @@ -37,29 +38,4 @@ typedef struct GPUDOFSettings { int high_quality; } GPUDOFSettings; -/** Properties for SSAO effect. */ -typedef struct GPUSSAOSettings { - float factor; - float color[3]; - float distance_max; - float attenuation; - /** Ray samples, we use presets here for easy control instead of. */ - int samples; - char _pad[4]; -} GPUSSAOSettings; - -typedef struct GPUFXSettings { - GPUDOFSettings *dof; - GPUSSAOSettings *ssao; - /** #eGPUFXFlags. */ - char fx_flag; - char _pad[7]; -} GPUFXSettings; - -/* shaderfx enables */ -typedef enum eGPUFXFlags { - GPU_FX_FLAG_DOF = (1 << 0), - GPU_FX_FLAG_SSAO = (1 << 1), -} eGPUFXFlags; - #endif /* __DNA_GPU_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 3af1da46f80..4de98e0b684 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -118,13 +118,13 @@ enum { BASE_HIDDEN = (1 << 8), /* Object is hidden for editing. */ /* Runtime evaluated flags. */ - BASE_VISIBLE = (1 << 1), /* Object is enabled and visible. */ - BASE_SELECTABLE = (1 << 2), /* Object can be selected. */ - BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */ - /* BASE_DEPRECATED = (1 << 4), */ - BASE_FROM_SET = (1 << 5), /* Object comes from set. */ - BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */ - BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ + BASE_VISIBLE_DEPSGRAPH = (1 << 1), /* Object is enabled and visible for the depsgraph. */ + BASE_SELECTABLE = (1 << 2), /* Object can be selected. */ + BASE_FROM_DUPLI = (1 << 3), /* Object comes from duplicator. */ + BASE_VISIBLE_VIEWLAYER = (1 << 4), /* Object is enabled and visible for the viewlayer. */ + BASE_FROM_SET = (1 << 5), /* Object comes from set. */ + BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */ + BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ /* BASE_DEPRECATED = (1 << 9), */ BASE_HOLDOUT = (1 << 10), /* Object masked out from render */ BASE_INDIRECT_ONLY = (1 << 11), /* Object only contributes indirectly to render */ @@ -142,10 +142,13 @@ enum { LAYER_COLLECTION_HIDE = (1 << 7), }; -/* Layer Collection->runtime_flag */ +/* Layer Collection->runtime_flag + Keep it synced with base->flag based on g_base_collection_flags. */ enum { LAYER_COLLECTION_HAS_OBJECTS = (1 << 0), - LAYER_COLLECTION_VISIBLE = (1 << 1), + LAYER_COLLECTION_VISIBLE_DEPSGRAPH = (1 << 1), + LAYER_COLLECTION_RESTRICT_VIEWPORT = (1 << 2), + LAYER_COLLECTION_VISIBLE_VIEW_LAYER = (1 << 4), }; /* ViewLayer->flag */ diff --git a/source/blender/makesdna/DNA_mesh_defaults.h b/source/blender/makesdna/DNA_mesh_defaults.h index 40b8e2c9247..f605827d120 100644 --- a/source/blender/makesdna/DNA_mesh_defaults.h +++ b/source/blender/makesdna/DNA_mesh_defaults.h @@ -34,6 +34,8 @@ .smoothresh = DEG2RADF(30), \ .texflag = ME_AUTOSPACE, \ .remesh_voxel_size = 0.1f, \ + .remesh_voxel_adaptivity = 0.0f, \ + .flag = ME_REMESH_FIX_POLES | ME_REMESH_REPROJECT_VOLUME, \ } /** \} */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 070180d0a24..fb9e522dfa9 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -116,8 +116,6 @@ typedef struct Mesh { /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; - struct BoundBox *bb; - /** Old animation system, deprecated for 2.5. */ struct Ipo *ipo DNA_DEPRECATED; struct Key *key; @@ -177,7 +175,6 @@ typedef struct Mesh { /* texture space, copied as one block in editobject.c */ float loc[3]; float size[3]; - float rot[3]; short texflag, flag; float smoothresh; @@ -193,6 +190,7 @@ typedef struct Mesh { short totcol; float remesh_voxel_size; + float remesh_voxel_adaptivity; char remesh_mode; char _pad1[3]; /** Deprecated multiresolution modeling data, only keep for loading old files. */ @@ -218,6 +216,7 @@ typedef struct TFace { /* texflag */ enum { ME_AUTOSPACE = 1, + ME_AUTOSPACE_EVALUATED = 2, }; /* me->editflag */ @@ -253,6 +252,8 @@ enum { ME_SCULPT_DYNAMIC_TOPOLOGY = 1 << 10, ME_REMESH_SMOOTH_NORMALS = 1 << 11, ME_REMESH_REPROJECT_PAINT_MASK = 1 << 12, + ME_REMESH_FIX_POLES = 1 << 13, + ME_REMESH_REPROJECT_VOLUME = 1 << 14, }; /* me->cd_flag */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 5d71d33733d..505853dbbeb 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1598,6 +1598,19 @@ enum { MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5), }; +typedef struct CorrectiveSmoothDeltaCache { + /* delta's between the original positions and the smoothed positions */ + float (*deltas)[3]; + unsigned int totverts; + + /* Value of settings when creating the cache. + * These are used to check if the cache should be recomputed. */ + float lambda; + short repeat, flag; + char smooth_type, rest_source; + char _pad[2]; +} CorrectiveSmoothDeltaCache; + typedef struct CorrectiveSmoothModifierData { ModifierData modifier; @@ -1616,11 +1629,8 @@ typedef struct CorrectiveSmoothModifierData { /** MAX_VGROUP_NAME. */ char defgrp_name[64]; - /* runtime-only cache (delta's between), - * delta's between the original positions and the smoothed positions */ - float (*delta_cache)[3]; - unsigned int delta_cache_num; - char _pad2[4]; + /* runtime-only cache */ + CorrectiveSmoothDeltaCache delta_cache; } CorrectiveSmoothModifierData; enum { diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index efda24d6e0e..8de79d9ea2b 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -97,7 +97,7 @@ typedef struct MovieClip { struct MovieTracking tracking; /** * Context of tracking job used to synchronize data - * like framenumber in SpaceClip clip user. + * like frame-number in SpaceClip clip user. */ void *tracking_context; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 0287a1510fe..7eecf23195a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -277,7 +277,9 @@ typedef struct bNode { /** Used at runtime when going through the tree. Initialize before use. */ short tmp_flag; /** Used at runtime to tag derivatives branches. EEVEE only. */ - short branch_tag; + char branch_tag; + /** Used at runtime when iterating over node branches. */ + char iter_flag; /** Runtime during drawing. */ struct uiBlock *block; @@ -433,7 +435,7 @@ typedef struct bNodeTree { int flag; /** Update flags. */ int update; - /** Flag to prevent reentrant update calls. */ + /** Flag to prevent re-entrant update calls. */ short is_updating; /** Generic temporary flag for recursion check (DFS/BFS). */ short done; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index a49da9e3761..8d77e57c959 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -93,7 +93,7 @@ .frs_sec = 24, \ .frs_sec_base = 1, \ \ - /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used, \ + /* OCIO_TODO: for forwards compatibility only, so if no tone-curve are used, \ * images would look in the same way as in current blender \ * \ * perhaps at some point should be completely deprecated? \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 1f70fb7175d..50712db3e04 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -39,7 +39,6 @@ extern "C" { #include "DNA_listBase.h" #include "DNA_ID.h" #include "DNA_freestyle_types.h" -#include "DNA_gpu_types.h" #include "DNA_collection_types.h" #include "DNA_layer_types.h" #include "DNA_material_types.h" @@ -2062,14 +2061,7 @@ extern const char *RE_engine_id_CYCLES; #define MINAFRAME -1048574 #define MINAFRAMEF -1048574.0f -#define BASE_VISIBLE(v3d, base) \ - (((v3d == NULL) || ((v3d)->localvd == NULL) || \ - ((v3d)->local_view_uuid & (base)->local_view_bits)) && \ - ((v3d == NULL) || (((v3d)->flag & V3D_LOCAL_COLLECTIONS) == 0) || \ - ((v3d)->local_collections_uuid & (base)->local_collections_bits)) && \ - ((v3d == NULL) || \ - (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \ - (((base)->flag & BASE_VISIBLE) != 0)) +#define BASE_VISIBLE(v3d, base) BKE_base_is_visible(v3d, base) #define BASE_SELECTABLE(v3d, base) \ (BASE_VISIBLE(v3d, base) && \ ((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_select) == 0)) && \ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 2740d27e1af..8587a2854fe 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -678,11 +678,9 @@ typedef struct FileSelectParams { short sort; /** Display mode flag. */ short display; - short display_previous; /** Details toggles (file size, creation date, etc.) */ char details_flags; - /* The type of file action (opening or saving) */ - char action_type; /* eFileSel_Action */ + char _pad2[3]; /** Filter when (flags & FILE_FILTER) is true. */ int filter; @@ -799,7 +797,8 @@ typedef enum eFileSel_Params_Flag { FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */ FILE_GROUP_INSTANCE = (1 << 10), FILE_SORT_INVERT = (1 << 11), - FILE_HIDE_TOOL_PROPS = (1 << 12) + FILE_HIDE_TOOL_PROPS = (1 << 12), + FILE_CHECK_EXISTING = (1 << 13), } eFileSel_Params_Flag; /* sfile->params->rename_flag */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 6e44c51970d..c726c5e132e 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -345,6 +345,7 @@ typedef struct ThemeSpace { lock_marker[4]; unsigned char bundle_solid[4]; unsigned char path_before[4], path_after[4]; + unsigned char path_keyframe_before[4], path_keyframe_after[4]; unsigned char camera_path[4]; unsigned char _pad1[2]; @@ -393,6 +394,8 @@ typedef struct ThemeSpace { /** NLA - warning color for duplicate instances of tweaking strip. */ unsigned char nla_tweakdupli[4]; + /** NLA "Track" */ + unsigned char nla_track[4]; /** NLA "Transition" strips. */ unsigned char nla_transition[4], nla_transition_sel[4]; /** NLA "Meta" strips. */ @@ -413,7 +416,6 @@ typedef struct ThemeSpace { unsigned char metadatabg[4]; unsigned char metadatatext[4]; - char _pad2[4]; } ThemeSpace; /* set of colors for use as a custom color set for Objects/Bones wire drawing */ @@ -576,6 +578,23 @@ typedef struct UserDef_SpaceData { char _pad0[6]; } UserDef_SpaceData; +/** + * Storage for UI data that to keep it even after the window was closed. (Similar to + * #UserDef_SpaceData.) + */ +typedef struct UserDef_FileSpaceData { + int display_type; /* FileSelectParams.display */ + int thumbnail_size; /* FileSelectParams.thumbnail_size */ + int sort_type; /* FileSelectParams.sort */ + int details_flags; /* FileSelectParams.details_flags */ + int flag; /* FileSelectParams.flag */ + int filter_id; /* FileSelectParams.filter_id */ + + /** Info used when creating the file browser in a temporary window. */ + int temp_win_sizex; + int temp_win_sizey; +} UserDef_FileSpaceData; + typedef struct UserDef { /** UserDef has separate do-version handling, and can be read from other files. */ int versionfile, subversionfile; @@ -587,7 +606,8 @@ typedef struct UserDef { /** #eUserPref_PrefFlag preferences for the preferences. */ char pref_flag; char savetime; - char _pad4[4]; + char mouse_emulate_3_button_modifier; + char _pad4[3]; /** FILE_MAXDIR length. */ char tempdir[768]; char fontdir[768]; @@ -707,11 +727,13 @@ typedef struct UserDef { short curssize; /** #eColorPicker_Types. */ short color_picker_type; + /** Curve smoothing type for newly added F-Curves. */ + char auto_smoothing_new; /** Interpolation mode for newly added F-Curves. */ char ipo_new; /** Handle types for newly added keyframes. */ char keyhandles_new; - char _pad11[3]; + char _pad11[2]; /** #eZoomFrame_Mode. */ char view_frame_type; @@ -814,12 +836,15 @@ typedef struct UserDef { char viewport_aa; - char _pad5[6]; + char render_display_type; /* eUserpref_RenderDisplayType */ + char filebrowser_display_type; /* eUserpref_TempSpaceDisplayType */ + char _pad5[4]; struct WalkNavigation walk_navigation; /** The UI for the user preferences. */ UserDef_SpaceData space_data; + UserDef_FileSpaceData file_space_data; /** Runtime data (keep last). */ UserDef_Runtime runtime; @@ -969,7 +994,11 @@ typedef enum eUserpref_UI_Flag { USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */ USER_SPLASH_DISABLE = (1 << 27), USER_HIDE_RECENT = (1 << 28), - USER_SHOW_THUMBNAILS = (1 << 29), +#ifdef DNA_DEPRECATED + USER_SHOW_THUMBNAILS = + (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if + we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */ +#endif USER_SAVE_PROMPT = (1 << 30), USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31), } eUserpref_UI_Flag; @@ -1202,6 +1231,23 @@ typedef enum eUserpref_FactorDisplay { USER_FACTOR_AS_PERCENTAGE = 1, } eUserpref_FactorDisplay; +typedef enum eUserpref_RenderDisplayType { + USER_RENDER_DISPLAY_NONE = 0, + USER_RENDER_DISPLAY_SCREEN = 1, + USER_RENDER_DISPLAY_AREA = 2, + USER_RENDER_DISPLAY_WINDOW = 3 +} eUserpref_RenderDisplayType; + +typedef enum eUserpref_TempSpaceDisplayType { + USER_TEMP_SPACE_DISPLAY_FULLSCREEN, + USER_TEMP_SPACE_DISPLAY_WINDOW, +} eUserpref_TempSpaceDisplayType; + +typedef enum eUserpref_EmulateMMBMod { + USER_EMU_MMB_MOD_ALT = 0, + USER_EMU_MMB_MOD_OSKEY = 1, +} eUserpref_EmulateMMBMod; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 10c61446d9d..7b832f1b646 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -38,7 +38,6 @@ struct wmTimer; #include "DNA_image_types.h" #include "DNA_object_types.h" #include "DNA_movieclip_types.h" -#include "DNA_gpu_types.h" typedef struct RegionView3D { @@ -301,10 +300,6 @@ typedef struct View3D { /** Actually only used to define the opacity of the grease pencil vertex in edit mode. */ float vertex_opacity; - /* note, 'fx_settings.dof' is currently _not_ allocated, - * instead set (temporarily) from camera */ - struct GPUFXSettings fx_settings; - /* XXX deprecated? */ /** Grease-Pencil Data (annotation layers). */ struct bGPdata *gpd DNA_DEPRECATED; @@ -351,6 +346,7 @@ typedef struct View3D { #define RV3D_CLIPPING (1 << 2) #define RV3D_NAVIGATING (1 << 3) #define RV3D_GPULIGHT_UPDATE (1 << 4) +#define RV3D_PAINTING (1 << 5) /*#define RV3D_IS_GAME_ENGINE (1 << 5) */ /* UNUSED */ /** * Disable zbuffer offset, skip calls to #ED_view3d_polygon_offset. diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 76d076a8638..260f1cd20f6 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -250,6 +250,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = { SDNA_DEFAULT_DECL(UserDef), SDNA_DEFAULT_DECL(bTheme), SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data), + SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data), SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation), /* DNA_view3d_defaults.h */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 0b60d1fa344..5d29ea24d90 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -267,6 +267,7 @@ extern StructRNA RNA_FreestyleLineStyle; extern StructRNA RNA_FreestyleModuleSettings; extern StructRNA RNA_FreestyleSettings; extern StructRNA RNA_Function; +extern StructRNA RNA_GPUFXSettings; extern StructRNA RNA_GPencilFrame; extern StructRNA RNA_GPencilInterpolateSettings; extern StructRNA RNA_GPencilLayer; @@ -400,6 +401,7 @@ extern StructRNA RNA_MeshFloatPropertyLayer; extern StructRNA RNA_MeshIntProperty; extern StructRNA RNA_MeshIntPropertyLayer; extern StructRNA RNA_MeshLoop; +extern StructRNA RNA_MeshLoopColor; extern StructRNA RNA_MeshLoopColorLayer; extern StructRNA RNA_MeshLoopTriangle; extern StructRNA RNA_MeshPolygon; @@ -413,6 +415,7 @@ extern StructRNA RNA_MeshTextureFace; extern StructRNA RNA_MeshTextureFaceLayer; extern StructRNA RNA_MeshTexturePoly; extern StructRNA RNA_MeshTexturePolyLayer; +extern StructRNA RNA_MeshUVLoop; extern StructRNA RNA_MeshVertex; extern StructRNA RNA_MessageSensor; extern StructRNA RNA_MetaBall; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index e72a55b5a9e..458f031ceae 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -90,6 +90,7 @@ extern const EnumPropertyItem rna_enum_color_sets_items[]; extern const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[]; extern const EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[]; +extern const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[]; extern const EnumPropertyItem rna_enum_keyframe_handle_type_items[]; extern const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[]; diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 6e98b5f4727..aeb6d528cdb 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -393,7 +393,7 @@ bool RNA_struct_idprops_check(StructRNA *srna) return (srna && srna->idproperties); } -static IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name) +IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name) { IDProperty *group = RNA_struct_idprops(ptr, 0); @@ -2058,18 +2058,18 @@ int RNA_property_ui_icon(PropertyRNA *prop) return rna_ensure_property(prop)->icon; } -bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop) +bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig) { ID *id = ptr->owner_id; int flag; const char *dummy_info; - prop = rna_ensure_property(prop); + PropertyRNA *prop = rna_ensure_property(prop_orig); flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag; return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 && (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) && - (!id->override_library || RNA_property_overridable_get(ptr, prop))))); + (!id->override_library || RNA_property_overridable_get(ptr, prop_orig))))); } /** @@ -2081,15 +2081,15 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char * ID *id = ptr->owner_id; int flag; - prop = rna_ensure_property(prop); + PropertyRNA *prop_type = rna_ensure_property(prop); *r_info = ""; /* get flag */ - if (prop->editable) { - flag = prop->editable(ptr, r_info); + if (prop_type->editable) { + flag = prop_type->editable(ptr, r_info); } else { - flag = prop->flag; + flag = prop_type->flag; if ((flag & PROP_EDITABLE) == 0 || (flag & PROP_REGISTER)) { *r_info = N_("This property is for internal use only and can't be edited"); } @@ -2097,17 +2097,21 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char * /* property from linked data-block */ if (id) { - if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) { + if (ID_IS_LINKED(id) && (prop_type->flag & PROP_LIB_EXCEPTION) == 0) { if (!(*r_info)[0]) { *r_info = N_("Can't edit this property from a linked data-block"); } return false; } - if (id->override_library != NULL && !RNA_property_overridable_get(ptr, prop)) { - if (!(*r_info)[0]) { - *r_info = N_("Can't edit this property from an override data-block"); + if (id->override_library != NULL) { + /* We need the real data property in case of IDProperty here... */ + PropertyRNA *real_prop = rna_ensure_property_realdata(&prop, ptr); + if (real_prop == NULL || !RNA_property_overridable_get(ptr, real_prop)) { + if (!(*r_info)[0]) { + *r_info = N_("Can't edit this property from an override data-block"); + } + return false; } - return false; } } diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index b0a83ea38c6..18fbe7886e9 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -76,8 +76,8 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) } else { /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */ - return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && - (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY); + IDProperty *idprop = (IDProperty *)prop; + return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0; } } @@ -400,9 +400,39 @@ static bool rna_property_override_operation_store(Main *bmain, return changed; } - BLI_assert(prop_local->override_store == prop_reference->override_store && - (!ptr_storage || prop_local->override_store == prop_storage->override_store) && - prop_local->override_store != NULL); + RNAPropOverrideStore override_store = NULL; + /* Special case for IDProps, we use default callback then. */ + if (prop_local->magic != RNA_MAGIC) { + override_store = rna_property_override_store_default; + if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) { + override_store = NULL; + } + } + else if (prop_reference->magic != RNA_MAGIC) { + override_store = rna_property_override_store_default; + if (prop_local->override_store != override_store) { + override_store = NULL; + } + } + else if (prop_local->override_store == prop_reference->override_store) { + override_store = prop_local->override_store; + } + + if (ptr_storage != NULL && prop_storage->magic == RNA_MAGIC && + prop_storage->override_store != override_store) { + override_store = NULL; + } + + if (override_store == NULL) { +#ifndef NDEBUG + printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n", + op->rna_path, + prop_local->magic == RNA_MAGIC, + prop_reference->magic == RNA_MAGIC); +#endif + BLI_assert(0); + return changed; + } for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { /* Only needed for diff operations. */ @@ -413,17 +443,17 @@ static bool rna_property_override_operation_store(Main *bmain, continue; } - if (prop_local->override_store(bmain, - ptr_local, - ptr_reference, - ptr_storage, - prop_local, - prop_reference, - prop_storage, - len_local, - len_reference, - len_storage, - opop)) { + if (override_store(bmain, + ptr_local, + ptr_reference, + ptr_storage, + prop_local, + prop_reference, + prop_storage, + len_local, + len_reference, + len_storage, + opop)) { changed = true; } } @@ -595,6 +625,21 @@ bool RNA_struct_override_matches(Main *bmain, prop_local = rna_ensure_property_realdata(&prop_local, ptr_local); prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference); + /* IDProps (custom properties) are even more of a PITA here, we cannot use + * `rna_ensure_property_realdata()` to deal with them, we have to use the path generated from + * `prop_local` (which is valid) to access to the actual reference counterpart... */ + if (prop_local != NULL && prop_local->magic != RNA_MAGIC && prop_local == prop_reference) { + /* We could also use (lower in this code, after rna_path has been computed): + * RNA_path_resolve_property(ptr_reference, rna_path, &some_rna_ptr, &prop_reference); + * But that would be much more costly, and would also fail when ptr_reference + * is not an ID pointer itself, so we'd need to rebuild it from its owner_id, then check that + * generated some_rna_ptr and ptr_reference do point to the same data, etc. + * For now, let's try that simple access, it won't cover all cases but should handle fine + * most basic custom properties situations. */ + prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, + ((IDProperty *)prop_local)->name); + } + if (ELEM(NULL, prop_local, prop_reference)) { continue; } diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h index 28ec504e376..c7995746d08 100644 --- a/source/blender/makesrna/intern/rna_access_internal.h +++ b/source/blender/makesrna/intern/rna_access_internal.h @@ -30,5 +30,6 @@ struct IDProperty; PropertyRNA *rna_ensure_property(PropertyRNA *prop); void rna_idproperty_touch(struct IDProperty *idprop); +struct IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name); #endif /* __ACCESS_RNA_INTERNAL_H__ */ diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 24f8d5c4e3d..6eaf303ce2d 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -306,6 +306,11 @@ bool rna_Action_actedit_assign_poll(PointerRNA *ptr, PointerRNA value) return 0; } +static char *rna_DopeSheet_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("dopesheet"); +} + #else static void rna_def_dopesheet(BlenderRNA *brna) @@ -315,6 +320,7 @@ static void rna_def_dopesheet(BlenderRNA *brna) srna = RNA_def_struct(brna, "DopeSheet", NULL); RNA_def_struct_sdna(srna, "bDopeSheet"); + RNA_def_struct_path_func(srna, "rna_DopeSheet_path"); RNA_def_struct_ui_text( srna, "Dope Sheet", "Settings for filtering the channels shown in animation editors"); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 6157ec41f19..e1a24326474 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -668,8 +668,7 @@ static FCurve *rna_Driver_new( return NULL; } - short add_mode = 1; - FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode); + FCurve *fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_KEYFRAMES); BLI_assert(fcu != NULL); DEG_relations_tag_update(bmain); diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 17a58a61fb5..f539da488ce 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -144,7 +144,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "line_thickness"); RNA_def_property_range(prop, 1, 6); - RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path"); + RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for drawing path"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* Settings */ @@ -164,7 +164,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) /* Use custom color */ prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM); - RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path"); + RNA_def_property_ui_text(prop, "Custom Colors", "Use custom color for this motion path"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* Draw lines between keyframes */ diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index 722b7b12271..01d1d1ddddb 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -355,7 +355,7 @@ static void rna_def_boidrule_avoid(BlenderRNA *brna) prop = RNA_def_property(srna, "fear_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text( - prop, "Fear factor", "Avoid object if danger from it is above this threshold"); + prop, "Fear Factor", "Avoid object if danger from it is above this threshold"); RNA_def_property_update(prop, 0, "rna_Boids_reset"); } @@ -379,7 +379,7 @@ static void rna_def_boidrule_avoid_collision(BlenderRNA *brna) prop = RNA_def_property(srna, "look_ahead", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Look ahead", "Time to look ahead in seconds"); + RNA_def_property_ui_text(prop, "Look Ahead", "Time to look ahead in seconds"); RNA_def_property_update(prop, 0, "rna_Boids_reset"); } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 716e8526071..57a3d889437 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -70,6 +70,7 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = { const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""}, + {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""}, {SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""}, {SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""}, {SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""}, @@ -84,16 +85,15 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""}, {0, "", 0, NULL, NULL}, {SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""}, + {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""}, {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""}, {SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""}, + {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""}, {SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""}, {SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""}, {0, "", 0, NULL, NULL}, {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, - {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""}, - {SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""}, - {SCULPT_TOOL_POSE, "POSE", ICON_BRUSH_GRAB, "Pose", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1298,7 +1298,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "active_smooth"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing "); + RNA_def_property_ui_text(prop, "Active Smooth", "Amount of smoothing while drawing"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); @@ -1306,7 +1306,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "era_strength_f"); RNA_def_property_range(prop, 0.0, 100.0); RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1); - RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength "); + RNA_def_property_ui_text(prop, "Affect Stroke Strength", "Amount of erasing for strength"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); @@ -1314,7 +1314,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "era_thickness_f"); RNA_def_property_range(prop, 0.0, 100.0); RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1); - RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness "); + RNA_def_property_ui_text(prop, "Affect Stroke Thickness", "Amount of erasing for thickness"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); @@ -1452,81 +1452,77 @@ static void rna_def_brush(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem prop_blend_items[] = { - {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use mix blending mode while painting"}, + {IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"}, - {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use multiply blending mode while painting"}, + {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"}, + {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"}, {IMB_BLEND_COLORBURN, "COLORBURN", 0, - "Color burn", - "Use color burn blending mode while painting"}, + "Color Burn", + "Use Color Burn blending mode while painting"}, {IMB_BLEND_LINEARBURN, "LINEARBURN", 0, - "Linear burn", - "Use linear burn blending mode while painting"}, + "Linear Burn", + "Use Linear Burn blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use lighten blending mode while painting"}, - {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"}, + {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"}, + {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"}, {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, - "Color dodge", - "Use color dodge blending mode while painting"}, - {IMB_BLEND_ADD, "ADD", 0, "Add", "Use add blending mode while painting"}, + "Color Dodge", + "Use Color Dodge blending mode while painting"}, + {IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"}, + {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"}, {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, - "Soft light", - "Use softlight blending mode while painting"}, + "Soft Light", + "Use Soft Light blending mode while painting"}, {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, - "Hard light", - "Use hard light blending mode while painting"}, + "Hard Light", + "Use Hard Light blending mode while painting"}, {IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, - "Vivid light", - "Use vividlight blending mode while painting"}, + "Vivid Light", + "Use Vivid Light blending mode while painting"}, {IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, - "Linear light", - "Use linearlight blending mode while painting"}, + "Linear Light", + "Use Linear Light blending mode while painting"}, {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, - "Pin light", - "Use pinlight blending mode while painting"}, + "Pin Light", + "Use Pin Light blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", - "Use difference blending mode while painting"}, + "Use Difference blending mode while painting"}, {IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", - "Use exclusion blending mode while painting"}, - {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use subtract blending mode while painting"}, + "Use Exclusion blending mode while painting"}, + {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, - {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"}, + {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"}, {IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", - "Use saturation blending mode while painting"}, - {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"}, - {IMB_BLEND_LUMINOSITY, - "LUMINOSITY", - 0, - "Luminosity", - "Use luminosity blending mode while painting"}, + "Use Saturation blending mode while painting"}, + {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"}, + {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"}, {0, "", ICON_NONE, NULL, NULL}, {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, @@ -1610,15 +1606,11 @@ static void rna_def_brush(BlenderRNA *brna) }; static const EnumPropertyItem brush_elastic_deform_type_items[] = { - {BRUSH_ELASTIC_DEFORM_GRAB, "ELASTIC_DEFORM_GRAB", 0, "Grab", ""}, - {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "ELASTIC_DEFORM_GRAB_BISCALE", 0, "Bi-scale Grab", ""}, - {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE, - "ELASTIC_DEFORM_GRAB_TRISCALE", - 0, - "Tri-scale Grab", - ""}, - {BRUSH_ELASTIC_DEFORM_SCALE, "ELASTIC_DEFORM_SCALE", 0, "Scale", ""}, - {BRUSH_ELASTIC_DEFORM_TWIST, "ELASTIC_DEFORM_TWIST", 0, "Twist", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB, "GRAB", 0, "Grab", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB_BISCALE, "GRAB_BISCALE", 0, "Bi-scale Grab", ""}, + {BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE, "GRAB_TRISCALE", 0, "Tri-scale Grab", ""}, + {BRUSH_ELASTIC_DEFORM_SCALE, "SCALE", 0, "Scale", ""}, + {BRUSH_ELASTIC_DEFORM_TWIST, "TWIST", 0, "Twist", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1630,7 +1622,7 @@ static void rna_def_brush(BlenderRNA *brna) /* enums */ prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_blend_items); - RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode"); + RNA_def_property_ui_text(prop, "Blending Mode", "Brush blending mode"); RNA_def_property_update(prop, 0, "rna_Brush_update"); /** @@ -1718,7 +1710,7 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_funcs(prop, NULL, "rna_Brush_set_unprojected_radius", NULL); RNA_def_property_range(prop, 0.001, FLT_MAX); - RNA_def_property_ui_range(prop, 0.001, 1, 0, -1); + RNA_def_property_ui_range(prop, 0.001, 1, 1, -1); RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units"); RNA_def_property_update(prop, 0, "rna_Brush_size_update"); @@ -1863,6 +1855,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "pose_offset", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "pose_offset"); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_text( + prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor"); RNA_def_property_float_default(prop, 0); @@ -1886,8 +1885,8 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "normal_radius_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "normal_radius_factor"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3); + RNA_def_property_range(prop, 0.0f, 2.0f); + RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.001, 3); RNA_def_property_ui_text(prop, "Normal Radius", "Ratio between the brush radius and the radius that is going to be " @@ -1960,7 +1959,7 @@ static void rna_def_brush(BlenderRNA *brna) /* flag */ /* This is an enum but its unlikely we add other shapes, so expose as a boolean. */ prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", BRUSH_AIRBRUSH); + RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", PAINT_FALLOFF_SHAPE_TUBE); RNA_def_property_ui_text( prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere"); RNA_def_property_update(prop, 0, "rna_Brush_update"); @@ -1978,6 +1977,14 @@ static void rna_def_brush(BlenderRNA *brna) "When locked keep using normal of surface where stroke was initiated"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_original_plane", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_PLANE); + RNA_def_property_ui_text( + prop, + "Original Plane", + "When locked keep using the plane origin of surface where stroke was initiated"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY); RNA_def_property_ui_text(prop, @@ -2404,7 +2411,7 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna) prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space"); + RNA_def_property_ui_text(prop, "Brush Size", "Brush size in screen space"); prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 7732bf531d8..c0211799192 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1045,6 +1045,7 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "targets", NULL); RNA_def_property_struct_type(prop, "ConstraintTargetBone"); RNA_def_property_ui_text(prop, "Targets", "Target Bones"); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); rna_def_constraint_armature_deform_targets(brna, prop); prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index a7dac4100db..6a3ab632fd4 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -291,9 +291,7 @@ static void rna_Curve_texspace_loc_get(PointerRNA *ptr, float *values) { Curve *cu = (Curve *)ptr->data; - if (!cu->bb) { - BKE_curve_texspace_calc(cu); - } + BKE_curve_texspace_ensure(cu); copy_v3_v3(values, cu->loc); } @@ -309,9 +307,7 @@ static void rna_Curve_texspace_size_get(PointerRNA *ptr, float *values) { Curve *cu = (Curve *)ptr->data; - if (!cu->bb) { - BKE_curve_texspace_calc(cu); - } + BKE_curve_texspace_ensure(cu); copy_v3_v3(values, cu->size); } @@ -1761,15 +1757,6 @@ static void rna_def_curve(BlenderRNA *brna) prop, "rna_Curve_texspace_size_get", "rna_Curve_texspace_size_set", NULL); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); - /* not supported yet */ -# if 0 - prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER); - RNA_def_property_float(prop, NULL, "rot"); - RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation"); - RNA_def_property_editable_func(prop, texspace_editable); - RNA_def_property_update(prop, 0, "rna_Curve_update_data"); -# endif - prop = RNA_def_property(srna, "use_uv_as_generated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_UV_ORCO); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 758fbd07f85..fc22e9e6c74 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1688,6 +1688,11 @@ void RNA_def_property_ui_range( DefRNA.error = 1; } + if (step == 0) { + CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier); + DefRNA.error = 1; + } + if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) { CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier); DefRNA.error = 1; diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index ebd9bd8e925..2072b07ecb3 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -261,8 +261,13 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result) outer); } -static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain) +static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain, ReportList *reports) { + if (DEG_is_evaluating(depsgraph)) { + BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation"); + return; + } + # ifdef WITH_PYTHON /* Allow drivers to be evaluated */ BPy_BEGIN_ALLOW_THREADS; @@ -654,7 +659,7 @@ static void rna_def_depsgraph(BlenderRNA *brna) func, "Re-evaluate any modified data-blocks, for example for animation or modifiers. " "This invalidates all references to evaluated data-blocks from this dependency graph."); - RNA_def_function_flag(func, FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); /* Queries for original datablockls (the ones depsgraph is built for). */ diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index 30a68a4919e..d7e34ff139c 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -472,7 +472,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ANTIALIAS); - RNA_def_property_ui_text(prop, "Anti-aliasing", "Use 5x multisampling to smooth paint edges"); + RNA_def_property_ui_text(prop, "Anti-Aliasing", "Use 5x multisampling to smooth paint edges"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaintSurface_reset"); prop = RNA_def_property(srna, "brush_influence_scale", PROP_FLOAT, PROP_FACTOR); @@ -610,7 +610,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_MULALPHA); RNA_def_property_ui_text( - prop, "Premultiply alpha", "Multiply color by alpha (recommended for Blender input)"); + prop, "Premultiply Alpha", "Multiply color by alpha (recommended for Blender input)"); prop = RNA_def_property(srna, "image_output_path", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "image_output_path"); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 254f3bc3710..424bb4a492f 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -76,6 +76,22 @@ const EnumPropertyItem rna_enum_fmodifier_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_fcurve_auto_smoothing_items[] = { + {FCURVE_SMOOTH_NONE, + "NONE", + 0, + "None", + "Automatic handles only take immediately adjacent keys into account"}, + {FCURVE_SMOOTH_CONT_ACCEL, + "CONT_ACCEL", + 0, + "Continuous Acceleration", + "Automatic handles are adjusted to avoid jumps in acceleration, resulting " + "in smoother curves. However, key changes may affect interpolation over a " + "larger stretch of the curve"}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = { {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", @@ -2258,19 +2274,6 @@ static void rna_def_fcurve(BlenderRNA *brna) "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL}, }; - static EnumPropertyItem prop_mode_smoothing_items[] = { - {FCURVE_SMOOTH_NONE, - "NONE", - 0, - "None", - "Auto handles only take adjacent keys into account (legacy mode)"}, - {FCURVE_SMOOTH_CONT_ACCEL, - "CONT_ACCEL", - 0, - "Continuous Acceleration", - "Auto handles are placed to avoid jumps in acceleration"}, - {0, NULL, 0, NULL, NULL}, - }; srna = RNA_def_struct(brna, "FCurve", NULL); RNA_def_struct_ui_text(srna, "F-Curve", "F-Curve defining values of a period of time"); @@ -2350,7 +2353,7 @@ static void rna_def_fcurve(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); prop = RNA_def_property(srna, "auto_smoothing", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, prop_mode_smoothing_items); + RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items); RNA_def_property_ui_text( prop, "Auto Handle Smoothing", "Algorithm used to compute automatic handles"); RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_FCurve_update_data"); diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 5d21e718934..2f09b90a81e 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -447,7 +447,7 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( prop, - "Remove air bubbles", + "Remove Air Bubbles", "Removes the air gap between fluid surface and obstacles - WARNING: Can result " "in a dissolving surface in other areas"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 3ad18fcc7a3..2601600c6ee 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1457,6 +1457,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop, "Solo Mode", "In Paint mode display only layers with keyframe in current frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Layer is used as Ruler. */ + prop = RNA_def_property(srna, "is_ruler", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_IS_RULER); + RNA_def_property_ui_text(prop, "Ruler", "This is a special ruler layer"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* exposed as layers.active */ # if 0 prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 4a0cf4d7ce2..4e7be7c9429 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -1387,7 +1387,7 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP); RNA_def_property_ui_text( prop, - "Keep On Top", + "Keep on Top", "Keep the original stroke in front of new instances (only affect by layer)"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } @@ -1763,7 +1763,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna) prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP); - RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_ui_text(prop, "Inverse Vertex Group", "Inverse filter"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE); @@ -1799,7 +1799,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna) prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "curfalloff"); - RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Light Falloff Curve"); + RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index bab7375f01b..40c6229f9b1 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -123,18 +123,13 @@ static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create) static bool rna_LayerCollection_visible_get(LayerCollection *layer_collection, bContext *C) { View3D *v3d = CTX_wm_view3d(C); - const bool runtime_visible = (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE) != 0; - if (v3d == NULL) { - return runtime_visible; - } - - if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) { - return runtime_visible; + if ((v3d == NULL) || ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0)) { + return (layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) != 0; } if (v3d->local_collections_uuid & layer_collection->local_collections_bits) { - return true; + return (layer_collection->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) == 0; } return false; @@ -192,15 +187,24 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip); } -static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain) +static void rna_ViewLayer_update_tagged(ID *id_ptr, + ViewLayer *view_layer, + Main *bmain, + ReportList *reports) { + Scene *scene = (Scene *)id_ptr; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); + + if (DEG_is_evaluating(depsgraph)) { + BKE_report(reports, RPT_ERROR, "Dependency graph update requested during evaluation"); + return; + } + # ifdef WITH_PYTHON /* Allow drivers to be evaluated */ BPy_BEGIN_ALLOW_THREADS; # endif - Scene *scene = (Scene *)id_ptr; - Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); /* NOTE: This is similar to CTX_data_depsgraph_pointer(). Ideally such access would be * de-duplicated across all possible cases, but for now this is safest and easiest way to go. * @@ -415,12 +419,12 @@ static void rna_def_layer_collection(BlenderRNA *brna) /* Run-time flags. */ prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE); + RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE_VIEW_LAYER); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, - "Visible", - "Whether this collection is visible, take into account the collection parent"); + RNA_def_property_ui_text(prop, + "Visible", + "Whether this collection is visible for the viewlayer, take into " + "account the collection parent"); func = RNA_def_function(srna, "has_objects", "rna_LayerCollection_has_objects"); RNA_def_function_ui_description(func, ""); @@ -573,7 +577,7 @@ void RNA_def_view_layer(BlenderRNA *brna) /* debug update routine */ func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); RNA_def_function_ui_description( func, "Update data tagged to be updated from previous access to data or operators"); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index f6cfc33c82e..f5730885193 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -2179,7 +2179,7 @@ static void rna_def_linestyle(BlenderRNA *brna) prop = RNA_def_property(srna, "texture_spacing", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "texstep"); RNA_def_property_range(prop, 0.01f, 100.0f); - RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length"); + RNA_def_property_ui_text(prop, "Texture Spacing", "Spacing for textures along stroke length"); RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update"); /* anim */ diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index fec991e16da..2c42dba9131 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -461,8 +461,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, "Cannot read '%s': %s", filepath, errno ? strerror(errno) : TIP_("unsupported font format")); - - id_us_min((ID *)font); } return font; } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index dd26b91de7f..efae4785a69 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -43,7 +43,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { {0, "", ICON_NONE, NULL, NULL}, {MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""}, {MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""}, - {MA_RAMP_DODGE, "DODGE", 0, "Dodge", ""}, + {MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""}, {MA_RAMP_ADD, "ADD", 0, "Add", ""}, {0, "", ICON_NONE, NULL, NULL}, {MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""}, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 21df0510941..72cba6f19ea 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -503,9 +503,7 @@ static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float values[3]) { Mesh *me = (Mesh *)ptr->data; - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } + BKE_mesh_texspace_ensure(me); copy_v3_v3(values, me->size); } @@ -514,9 +512,7 @@ static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float values[3]) { Mesh *me = (Mesh *)ptr->data; - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } + BKE_mesh_texspace_ensure(me); copy_v3_v3(values, me->loc); } @@ -547,7 +543,7 @@ static void rna_MeshVertex_undeformed_co_get(PointerRNA *ptr, float values[3]) /* orco is normalized to 0..1, we do inverse to match mvert->co */ float loc[3], size[3]; - BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size); + BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size); madd_v3_v3v3v3(values, loc, orco[(mvert - me->mvert)], size); } else { @@ -2211,15 +2207,6 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable) RNA_def_property_editable_func(prop, texspace_editable); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); - /* not supported yet */ -# if 0 - prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER); - RNA_def_property_float(prop, NULL, "rot"); - RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation"); - RNA_def_property_editable_func(prop, texspace_editable); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); -# endif - /* materials */ prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); @@ -2245,13 +2232,13 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_sdna(srna, "Mesh"); RNA_def_struct_ui_text(srna, "Mesh Vertices", "Collection of mesh vertices"); - func = RNA_def_function(srna, "add", "ED_mesh_vertices_add"); + func = RNA_def_function(srna, "add", "ED_mesh_verts_add"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int( func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add", 0, INT_MAX); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); # if 0 /* BMESH_TODO Remove until BMesh merge */ - func = RNA_def_function(srna, "remove", "ED_mesh_vertices_remove"); + func = RNA_def_function(srna, "remove", "ED_mesh_verts_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to remove", 0, INT_MAX); # endif @@ -2427,7 +2414,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_pointer_funcs( prop, "rna_Mesh_uv_layer_active_get", "rna_Mesh_uv_layer_active_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); - RNA_def_property_ui_text(prop, "Active UV loop layer", "Active UV loop layer"); + RNA_def_property_ui_text(prop, "Active UV Loop Layer", "Active UV loop layer"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); @@ -2435,7 +2422,7 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop) "rna_Mesh_uv_layer_active_index_get", "rna_Mesh_uv_layer_active_index_set", "rna_Mesh_uv_layer_index_range"); - RNA_def_property_ui_text(prop, "Active UV loop layer Index", "Active UV loop layer index"); + RNA_def_property_ui_text(prop, "Active UV Loop Layer Index", "Active UV loop layer index"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); } @@ -2815,28 +2802,28 @@ static void rna_def_mesh(BlenderRNA *brna) prop, "rna_Mesh_uv_layer_clone_get", "rna_Mesh_uv_layer_clone_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text( - prop, "Clone UV loop layer", "UV loop layer to be used as cloning source"); + prop, "Clone UV Loop Layer", "UV loop layer to be used as cloning source"); prop = RNA_def_property(srna, "uv_layer_clone_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_Mesh_uv_layer_clone_index_get", "rna_Mesh_uv_layer_clone_index_set", "rna_Mesh_uv_layer_index_range"); - RNA_def_property_ui_text(prop, "Clone UV loop layer Index", "Clone UV loop layer index"); + RNA_def_property_ui_text(prop, "Clone UV Loop Layer Index", "Clone UV loop layer index"); prop = RNA_def_property(srna, "uv_layer_stencil", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MeshUVLoopLayer"); RNA_def_property_pointer_funcs( prop, "rna_Mesh_uv_layer_stencil_get", "rna_Mesh_uv_layer_stencil_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Mask UV loop layer", "UV loop layer to mask the painted area"); + RNA_def_property_ui_text(prop, "Mask UV Loop Layer", "UV loop layer to mask the painted area"); prop = RNA_def_property(srna, "uv_layer_stencil_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_Mesh_uv_layer_stencil_index_get", "rna_Mesh_uv_layer_stencil_index_set", "rna_Mesh_uv_layer_index_range"); - RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index"); + RNA_def_property_ui_text(prop, "Mask UV Loop Layer Index", "Mask UV loop layer index"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); /* Vertex colors */ @@ -3008,11 +2995,35 @@ static void rna_def_mesh(BlenderRNA *brna) "values preserve finer details"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_voxel_adaptivity", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_adaptivity"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 4); + RNA_def_property_ui_text( + prop, + "Adaptivity", + "Reduces the final face count by simplifying geometry where detail is not needed, " + "generating triangles. A value greater than 0 disables Fix Poles"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS); RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES); + RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + + prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME); + RNA_def_property_ui_text( + prop, + "Preserve Volume", + "Projects the mesh to preserve the volume and details of the original mesh"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); + prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_PAINT_MASK); RNA_def_property_boolean_default(prop, false); @@ -3084,15 +3095,6 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); # endif - /* not supported yet */ -# if 0 - prop = RNA_def_property(srna, "texspace_rot", PROP_FLOAT, PROP_EULER); - RNA_def_property_float(prop, NULL, "rot"); - RNA_def_property_ui_text(prop, "Texture Space Rotation", "Texture space rotation"); - RNA_def_property_editable_func(prop, texspace_editable); - RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); -# endif - /* editflag */ prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 18cf57c5624..7a3ca7e9dd8 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -929,7 +929,7 @@ static void rna_MultiresModifier_type_set(PointerRNA *ptr, int value) Object *ob = (Object *)ptr->owner_id; MultiresModifierData *mmd = (MultiresModifierData *)ptr->data; - multires_force_update(ob); + multires_force_sculpt_rebuild(ob); mmd->simple = value; } @@ -1401,7 +1401,7 @@ static void rna_CorrectiveSmoothModifier_update(Main *bmain, Scene *scene, Point { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)ptr->data; - MEM_SAFE_FREE(csmd->delta_cache); + MEM_SAFE_FREE(csmd->delta_cache.deltas); rna_Modifier_update(bmain, scene, ptr); } @@ -3100,7 +3100,7 @@ static void rna_def_modifier_cast(BlenderRNA *brna) prop = RNA_def_property(srna, "use_transform", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_CAST_USE_OB_TRANSFORM); RNA_def_property_ui_text( - prop, "Use transform", "Use object transform to control projection shape"); + prop, "Use Transform", "Use object transform to control projection shape"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); @@ -5922,7 +5922,7 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 2.0f, 16.0f); RNA_def_property_ui_text( - prop, "Interpolation falloff", "Controls how much nearby polygons influence deformation"); + prop, "Interpolation Falloff", "Controls how much nearby polygons influence deformation"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE); @@ -6217,7 +6217,7 @@ void RNA_def_modifier(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline); RNA_def_property_ui_text( prop, - "Apply on spline", + "Apply on Spline", "Apply this and all preceding deformation modifiers on splines' points rather than " "on filled curve/surface"); RNA_def_property_ui_icon(prop, ICON_SURFACE_DATA, 0); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 913324e4997..287c7502c41 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1482,7 +1482,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int node->typeinfo->ext.call(NULL, &ptr, func, &list); RNA_parameter_get_lookup(&list, "label", &ret); - rlabel = *(char **)ret; + rlabel = (char *)ret; BLI_strncpy(label, rlabel != NULL ? rlabel : "", maxlen); RNA_parameter_list_free(&list); @@ -3986,7 +3986,7 @@ static void def_mix_rgb(StructRNA *srna) prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); - RNA_def_property_ui_text(prop, "Blend Type", ""); + RNA_def_property_ui_text(prop, "Blending Mode", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); @@ -4431,7 +4431,7 @@ static void def_sh_tex_voronoi(StructRNA *srna) "DISTANCE_TO_EDGE", 0, "Distance To Edge", - "Computes the distance to the edge of the vornoi cell"}, + "Computes the distance to the edge of the voronoi cell"}, {SHD_VORONOI_N_SPHERE_RADIUS, "N_SPHERE_RADIUS", 0, @@ -5719,7 +5719,7 @@ static void def_cmp_dilate_erode(StructRNA *srna) prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "custom2"); RNA_def_property_range(prop, -5000, 5000); - RNA_def_property_ui_range(prop, -100, 100, 0, -1); + RNA_def_property_ui_range(prop, -100, 100, 1, -1); RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -6955,7 +6955,7 @@ static void def_cmp_boxmask(StructRNA *srna) prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_masktype_items); - RNA_def_property_ui_text(prop, "Mask type", ""); + RNA_def_property_ui_text(prop, "Mask Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeBoxMask", "storage"); @@ -7002,7 +7002,7 @@ static void def_cmp_ellipsemask(StructRNA *srna) prop = RNA_def_property(srna, "mask_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, node_masktype_items); - RNA_def_property_ui_text(prop, "Mask type", ""); + RNA_def_property_ui_text(prop, "Mask Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeEllipseMask", "storage"); @@ -7117,7 +7117,7 @@ static void def_cmp_bokehimage(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "lensshift"); RNA_def_property_float_default(prop, 0.0f); RNA_def_property_range(prop, -1.0f, 1.0f); - RNA_def_property_ui_text(prop, "Lens shift", "Shift of the lens components"); + RNA_def_property_ui_text(prop, "Lens Shift", "Shift of the lens components"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3054e32d558..68859aaf1de 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2764,7 +2764,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "parentinv"); RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); RNA_def_property_ui_text( - prop, "Matrix", "Inverse of object's parent matrix at time of parenting"); + prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); /* modifiers */ diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 56d25f5bebf..babf388bfc7 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -70,6 +70,7 @@ static const EnumPropertyItem space_items[] = { # include "BKE_customdata.h" # include "BKE_font.h" # include "BKE_global.h" +# include "BKE_layer.h" # include "BKE_main.h" # include "BKE_mesh.h" # include "BKE_mball.h" @@ -283,6 +284,11 @@ static void rna_Object_local_view_set(Object *ob, } } +static bool rna_Object_visible_in_viewport_get(Object *ob, View3D *v3d) +{ + return BKE_object_is_visible_in_viewport(v3d, ob); +} + /* Convert a given matrix from a space to another (using the object and/or a bone as * reference). */ static void rna_Object_mat_convert_space(Object *ob, @@ -825,6 +831,15 @@ void RNA_api_object(StructRNA *srna) parm = RNA_def_boolean(func, "state", 0, "", "Local view state to define"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* Viewport */ + func = RNA_def_function(srna, "visible_in_viewport_get", "rna_Object_visible_in_viewport_get"); + RNA_def_function_ui_description( + func, "Check for local view and local collections for this viewport and object"); + parm = RNA_def_pointer(func, "viewport", "SpaceView3D", "", "Viewport in local collections"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "", "Object viewport visibility"); + RNA_def_function_return(func, parm); + /* Matrix space conversion */ func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space"); RNA_def_function_ui_description( diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 430059c7a18..87b14b56504 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1943,7 +1943,7 @@ static void rna_def_softbody(BlenderRNA *brna) prop = RNA_def_property(srna, "use_estimate_matrix", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "solverflags", SBSO_ESTIMATEIPO); - RNA_def_property_ui_text(prop, "Estimate matrix", "Estimate matrix... split to COM, ROT, SCALE"); + RNA_def_property_ui_text(prop, "Estimate Matrix", "Estimate matrix... split to COM, ROT, SCALE"); /***********************************************************************************/ /* these are not exactly settings, but reading calculated results*/ @@ -1952,7 +1952,7 @@ static void rna_def_softbody(BlenderRNA *brna) /* translation */ prop = RNA_def_property(srna, "location_mass_center", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "lcom"); - RNA_def_property_ui_text(prop, "Center of mass", "Location of Center of mass"); + RNA_def_property_ui_text(prop, "Center of Mass", "Location of center of mass"); RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); /* matrix */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 98ecb053641..211d9e19ab4 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1891,7 +1891,7 @@ static void rna_def_fluid_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "viscosity_beta"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3); - RNA_def_property_ui_text(prop, "Stiff viscosity", "Creates viscosity for expanding fluid"); + RNA_def_property_ui_text(prop, "Stiff Viscosity", "Creates viscosity for expanding fluid"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); /* Double density relaxation */ @@ -2398,7 +2398,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_DIE_ON_COL); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( - prop, "Die on hit", "Particles die when they collide with a deflector object"); + prop, "Die on Hit", "Particles die when they collide with a deflector object"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "use_size_deflect", PROP_BOOLEAN, PROP_NONE); @@ -3297,7 +3297,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "keyed_loops"); RNA_def_property_range(prop, 1.0f, 10000.0f); RNA_def_property_ui_range(prop, 1.0f, 100.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Loop count", "Number of times the keys are looped"); + RNA_def_property_ui_text(prop, "Loop Count", "Number of times the keys are looped"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* modified dm support */ @@ -3594,7 +3594,7 @@ static void rna_def_particle_system(BlenderRNA *brna) prop = RNA_def_property(srna, "use_keyed_timing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_KEYED_TIMING); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Keyed timing", "Use key times"); + RNA_def_property_ui_text(prop, "Keyed Timing", "Use key times"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index e514fd82aca..8c4b7dd52d9 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -648,7 +648,7 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), /* Remember that insertion operations are defined and stored in correct order, which means that * even if we insert several items in a row, we always insert first one, then second one, etc. - * So we should always find 'anchor' constraint in both _src *and* _dst> */ + * So we should always find 'anchor' constraint in both _src *and* _dst */ bConstraint *con_anchor = NULL; if (opop->subitem_local_name && opop->subitem_local_name[0]) { con_anchor = BLI_findstring( @@ -669,7 +669,11 @@ bool rna_PoseChannel_constraints_override_apply(Main *UNUSED(bmain), } con_src = con_src ? con_src->next : pchan_src->constraints.first; - BLI_assert(con_src != NULL); + if (con_src == NULL) { + printf("%s: Could not find constraint to insert, doing nothing...\n", __func__); + BLI_assert(0); + return false; + } bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true); @@ -1299,7 +1303,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Custom Object", "Object that defines custom draw type for this bone"); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); - RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); + RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update"); prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "custom_scale"); @@ -1457,7 +1461,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna) prop = RNA_def_property(srna, "step_count", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "numstep"); RNA_def_property_range(prop, 1.f, 50.f); - RNA_def_property_ui_text(prop, "Num steps", "Divide the frame interval into this many steps"); + RNA_def_property_ui_text(prop, "Num Steps", "Divide the frame interval into this many steps"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); @@ -1478,7 +1482,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna) prop = RNA_def_property(srna, "use_auto_step", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ITASC_AUTO_STEP); RNA_def_property_ui_text(prop, - "Auto step", + "Auto Step", "Automatically determine the optimal number of steps for best " "performance/accuracy trade off"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); @@ -1487,14 +1491,14 @@ static void rna_def_pose_itasc(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "minstep"); RNA_def_property_range(prop, 0.0f, 0.1f); RNA_def_property_ui_text( - prop, "Min step", "Lower bound for timestep in second in case of automatic substeps"); + prop, "Min Step", "Lower bound for timestep in second in case of automatic substeps"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "step_max", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "maxstep"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( - prop, "Max step", "Higher bound for timestep in second in case of automatic substeps"); + prop, "Max Step", "Higher bound for timestep in second in case of automatic substeps"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "feedback", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 6e21d02c0b3..4db702b215f 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -613,7 +613,10 @@ static bool rna_Property_overridable_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0; + IDProperty *idprop = rna_idproperty_check(&prop, ptr); + + return idprop != NULL ? (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0 : + (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY) != 0; } static bool rna_Property_use_output_get(PointerRNA *ptr) @@ -1154,20 +1157,21 @@ static bool rna_property_override_diff_propptr_validate_diffing(PointerRNA *prop *r_is_id = *r_is_null = *r_is_type_diff = false; /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */ - if (propptr_a->type == NULL) { - if (propptr_b == NULL || propptr_b->type == NULL) { + if (ELEM(NULL, propptr_a->type, propptr_a->data)) { + if (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)) { *r_is_null = true; } else { *r_is_id = RNA_struct_is_ID(propptr_b->type); *r_is_null = true; - *r_is_type_diff = true; + *r_is_type_diff = propptr_a->type != propptr_b->type; } is_valid_for_diffing = false; } else { *r_is_id = RNA_struct_is_ID(propptr_a->type); - *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type)); + *r_is_null = (ELEM(NULL, propptr_b, propptr_b->type, propptr_b->data)); + *r_is_type_diff = (propptr_b == NULL || propptr_b->type != propptr_a->type); is_valid_for_diffing = !(*r_is_id || *r_is_null); } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 193383637d0..5841d90f3ce 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3422,7 +3422,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna) prop, NULL, "rna_UnifiedPaintSettings_unprojected_radius_set", NULL); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_range(prop, 0.001, FLT_MAX); - RNA_def_property_ui_range(prop, 0.001, 1, 0, -1); + RNA_def_property_ui_range(prop, 0.001, 1, 1, -1); RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units"); RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_radius_update"); @@ -4861,66 +4861,6 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } -static void rna_def_gpu_ssao_fx(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "GPUSSAOSettings", NULL); - RNA_def_struct_ui_text( - srna, "GPU SSAO", "Settings for GPU based screen space ambient occlusion"); - - prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "Strength", "Strength of the SSAO effect"); - RNA_def_property_range(prop, 0.0f, 250.0f); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "distance_max", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text( - prop, "Distance", "Distance of object that contribute to the SSAO effect"); - RNA_def_property_range(prop, 0.0f, 100000.0f); - RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "attenuation", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant"); - RNA_def_property_range(prop, 1.0f, 100000.0f); - RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); - RNA_def_property_ui_text(prop, "Samples", "Number of samples"); - RNA_def_property_range(prop, 1, 500); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_ui_text(prop, "Color", "Color for screen space ambient occlusion effect"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -} - -static void rna_def_gpu_fx(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - rna_def_gpu_ssao_fx(brna); - - srna = RNA_def_struct(brna, "GPUFXSettings", NULL); - RNA_def_struct_ui_text(srna, "GPU FX Settings", "Settings for GPU based compositing"); - - prop = RNA_def_property(srna, "ssao", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_struct_type(prop, "GPUSSAOSettings"); - RNA_def_property_ui_text(prop, "Screen Space Ambient Occlusion settings", ""); - - prop = RNA_def_property(srna, "use_ssao", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_SSAO); - RNA_def_property_ui_text( - prop, "SSAO", "Use screen space ambient occlusion of field on viewport"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -} - static void rna_def_view_layers(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -5456,7 +5396,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_range(prop, 0, 500); RNA_def_property_int_default(prop, 25); RNA_def_property_ui_text(prop, - "Keyframe interval", + "Keyframe Interval", "Distance between key frames, also known as GOP size; " "influences file size and seekability"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); @@ -5467,14 +5407,14 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_range(prop, 0, 16); RNA_def_property_ui_text( prop, - "Max B-frames", + "Max B-Frames", "Maximum number of B-frames between non-B-frames; influences file size and seekability"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_max_b_frames", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FFMPEG_USE_MAX_B_FRAMES); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Use max B-frames", "Set a maximum number of B-frames"); + RNA_def_property_ui_text(prop, "Use Max B-Frames", "Set a maximum number of B-frames"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "buffersize", PROP_INT, PROP_NONE); @@ -5498,7 +5438,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_enum_default(prop, FFM_CRF_MEDIUM); RNA_def_property_ui_text( prop, - "Output quality", + "Output Quality", "Constant Rate Factor (CRF); tradeoff between video quality and file size"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); @@ -5508,7 +5448,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, ffmpeg_preset_items); RNA_def_property_enum_default(prop, FFM_PRESET_GOOD); RNA_def_property_ui_text( - prop, "Encoding speed", "Tradeoff between encoding speed and compression ratio"); + prop, "Encoding Speed", "Tradeoff between encoding speed and compression ratio"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_autosplit", PROP_BOOLEAN, PROP_NONE); @@ -5568,22 +5508,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem display_mode_items[] = { - {R_OUTPUT_SCREEN, - "SCREEN", - 0, - "Full Screen", - "Images are rendered in a maximized Image Editor"}, - {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"}, - {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"}, - {R_OUTPUT_NONE, - "NONE", - 0, - "Keep User Interface", - "Images are rendered without changing the user interface"}, - {0, NULL, 0, NULL, NULL}, - }; - /* Bake */ static const EnumPropertyItem bake_mode_items[] = { //{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"}, @@ -5758,7 +5682,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "frs_sec_base"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 1e-5f, 1e6f); - RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1); + /* Important to show at least 3 decimal points because multiple presets set this to 1.001. */ + RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, 3); RNA_def_property_ui_text(prop, "FPS Base", "Framerate base"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); @@ -5980,13 +5905,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "(this solves anti-aliasing issues with compositing)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "displaymode"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_enum_items(prop, display_mode_items); - RNA_def_property_ui_text(prop, "Display", "Select where rendered images will be displayed"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "use_lock_interface", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_lock_interface", 1); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -6068,7 +5986,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_bake_user_scale", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_USERSCALE); - RNA_def_property_ui_text(prop, "User scale", "Use a user scale for the derivative map"); + RNA_def_property_ui_text(prop, "User Scale", "Use a user scale for the derivative map"); prop = RNA_def_property(srna, "bake_user_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bake_user_scale"); @@ -7930,7 +7848,6 @@ void RNA_def_scene(BlenderRNA *brna) RNA_define_animate_sdna(true); /* *** Animated *** */ rna_def_scene_render_data(brna); - rna_def_gpu_fx(brna); rna_def_scene_render_view(brna); /* Scene API */ diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 2b1b23a40f4..8a06d594c1f 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -88,7 +88,11 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf BPy_END_ALLOW_THREADS; # endif - BKE_scene_camera_switch_update(scene); + if (BKE_scene_camera_switch_update(scene)) { + for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { + BKE_screen_view3d_scene_sync(sc, scene); + } + } /* don't do notifier when we're rendering, avoid some viewport crashes * redrawing while the data is being modified for render */ diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 728ef3fb706..1637f8cfed5 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -272,7 +272,7 @@ static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr) sa->butspacetype_subtype = 0; } -static void rna_View2D_region_to_view(struct View2D *v2d, int x, int y, float result[2]) +static void rna_View2D_region_to_view(struct View2D *v2d, float x, float y, float result[2]) { UI_view2d_region_to_view(v2d, x, y, &result[0], &result[1]); } @@ -406,9 +406,9 @@ static void rna_def_view2d_api(StructRNA *srna) func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view"); RNA_def_function_ui_description(func, "Transform region coordinates to 2D view"); - parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000); + parm = RNA_def_float(func, "x", 0, -FLT_MAX, FLT_MAX, "x", "Region x coordinate", -10000, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000); + parm = RNA_def_float(func, "y", 0, -FLT_MAX, FLT_MAX, "y", "Region y coordinate", -10000, 10000); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_array(func, "result", diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index ef550a079ad..1457bbfd3c3 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -204,10 +204,11 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr) static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr)) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); if (!edit) { return; @@ -259,8 +260,9 @@ static const EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); # if 0 + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); ParticleSystem *psys = edit ? edit->psys : NULL; # else /* use this rather than PE_get_current() - because the editing cache is @@ -285,14 +287,14 @@ static bool rna_ParticleEdit_editable_get(PointerRNA *ptr) { ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data; - return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object)); + return (pset->object && pset->scene && PE_get_current(NULL, pset->scene, pset->object)); } static bool rna_ParticleEdit_hair_get(PointerRNA *ptr) { ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data; if (pset->scene) { - PTCacheEdit *edit = PE_get_current(pset->scene, pset->object); + PTCacheEdit *edit = PE_get_current(NULL, pset->scene, pset->object); return (edit && edit->psys); } @@ -646,7 +648,7 @@ static void rna_def_paint(BlenderRNA *brna) prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "num_input_samples"); - RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 0, -1); + RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 1, -1); RNA_def_property_ui_text( prop, "Input Samples", "Average multiple input samples together to smooth the brush stroke"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); @@ -1021,7 +1023,7 @@ static void rna_def_image_paint(BlenderRNA *brna) /* integers */ prop = RNA_def_property(srna, "seam_bleed", PROP_INT, PROP_PIXEL); - RNA_def_property_ui_range(prop, 0, 8, 0, -1); + RNA_def_property_ui_range(prop, 0, 8, 1, -1); RNA_def_property_ui_text( prop, "Bleed", "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 31bc9927026..31ead989f25 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1462,7 +1462,7 @@ static const EnumPropertyItem blend_mode_items[] = { {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, - {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, @@ -1723,7 +1723,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "blend_mode"); RNA_def_property_enum_items(prop, blend_mode_items); RNA_def_property_ui_text( - prop, "Blend Mode", "Method for controlling how the strip combines with other strips"); + prop, "Blending Mode", "Method for controlling how the strip combines with other strips"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); @@ -1740,7 +1740,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_float_sdna(prop, NULL, "effect_fader"); - RNA_def_property_ui_text(prop, "Effect fader position", "Custom fade value"); + RNA_def_property_ui_text(prop, "Effect Fader Position", "Custom fade value"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); @@ -1758,7 +1758,7 @@ static void rna_def_sequence(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "speed_fader"); RNA_def_property_ui_text( prop, - "Speed factor", + "Speed Factor", "Multiply the current speed of the sequence with this number or remap current frame " "to this frame"); RNA_def_property_update( @@ -1944,7 +1944,7 @@ static void rna_def_editor(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1); RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost"); RNA_def_property_ui_text( - prop, "Recycle Up To Cost", "Only frames with cost lower than this value will be recycled"); + prop, "Recycle Up to Cost", "Only frames with cost lower than this value will be recycled"); } static void rna_def_filter_video(StructRNA *srna) @@ -2225,7 +2225,7 @@ static void rna_def_scene(BlenderRNA *brna) RNA_def_struct_sdna(srna, "Sequence"); prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_ui_text(prop, "Scene", "Scene that this sequence uses"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); @@ -2639,8 +2639,7 @@ static void rna_def_solid_color(StructRNA *srna) prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "col"); RNA_def_property_ui_text(prop, "Color", "Effect Strip color"); - RNA_def_property_update( - prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); } static void rna_def_speed_control(StructRNA *srna) @@ -2661,14 +2660,14 @@ static void rna_def_speed_control(StructRNA *srna) prop = RNA_def_property(srna, "use_as_speed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_INTEGRATE); RNA_def_property_ui_text( - prop, "Use as speed", "Interpret the value as speed instead of a frame number"); + prop, "Use as Speed", "Interpret the value as speed instead of a frame number"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); prop = RNA_def_property(srna, "use_scale_to_length", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y); RNA_def_property_ui_text( - prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length"); + prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); } @@ -2786,27 +2785,31 @@ static void rna_def_text(StructRNA *srna) static void rna_def_color_mix(StructRNA *srna) { static EnumPropertyItem blend_color_items[] = { - {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, - {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, + {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""}, + {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, + {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""}, - {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""}, {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""}, + {SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""}, + {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""}, - {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""}, - {SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""}, - {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""}, {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""}, {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""}, - {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, - {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""}, - {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, + {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, + {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""}, + {0, "", ICON_NONE, NULL, NULL}, + {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, + {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""}, + {0, "", ICON_NONE, NULL, NULL}, {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""}, {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""}, + {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""}, {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""}, - {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, - {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2818,7 +2821,7 @@ static void rna_def_color_mix(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "blend_effect"); RNA_def_property_enum_items(prop, blend_color_items); RNA_def_property_ui_text( - prop, "Blend Effect", "Method for controlling how the strip combines with other strips"); + prop, "Blending Mode", "Method for controlling how the strip combines with other strips"); RNA_def_property_update( prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update"); @@ -3015,7 +3018,7 @@ static void rna_def_whitebalance_modifier(BlenderRNA *brna) prop = RNA_def_property(srna, "white_value", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "white_value"); - RNA_def_property_ui_text(prop, "White value", "This color defines white in the strip"); + RNA_def_property_ui_text(prop, "White Value", "This color defines white in the strip"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update"); } diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index acf525e1788..cd4e027ce7c 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -260,14 +260,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "low_color"); RNA_def_property_array(prop, 4); - RNA_def_property_ui_text(prop, "Low color", "First color used for effect"); + RNA_def_property_ui_text(prop, "Low Color", "First color used for effect"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "high_color"); RNA_def_property_array(prop, 4); - RNA_def_property_ui_text(prop, "Height color", "Second color used for effect"); + RNA_def_property_ui_text(prop, "High Color", "Second color used for effect"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index fa0297ac306..c00cc789eff 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -588,7 +588,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES); - RNA_def_property_ui_text(prop, "High res", "Enable high resolution (using amplification)"); + RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); @@ -668,7 +668,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG); - RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x "); + RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x "); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); @@ -1204,7 +1204,7 @@ static void rna_def_smoke_coll_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, smoke_coll_type_items); - RNA_def_property_ui_text(prop, "Collision type", "Collision type"); + RNA_def_property_ui_text(prop, "Collision Type", "Collision type"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index bbddf1b8310..e4a81e20942 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -587,7 +587,7 @@ static void rna_Space_bool_from_region_flag_set_by_type(PointerRNA *ptr, { ScrArea *sa = rna_area_from_space(ptr); ARegion *ar = BKE_area_find_region_type(sa, region_type); - if (ar) { + if (ar && (ar->alignment != RGN_ALIGN_NONE)) { SET_FLAG_FROM_TEST(ar->flag, value, region_flag); } ED_region_tag_redraw(ar); @@ -785,13 +785,18 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { + bool changed = false; /* need set all caches as dirty to recalculate onion skinning */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { if (ob->type == OB_GPENCIL) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + bGPdata *gpd = (bGPdata *)ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + changed = true; } } - WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); + if (changed) { + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); + } } /* Space 3D View */ @@ -1103,7 +1108,7 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS } else { /* Solid mode, or lookdev mode for workbench engine. */ - r_free = false; + *r_free = false; return rna_enum_shading_color_type_items; } } @@ -1272,6 +1277,11 @@ static char *rna_View3DOverlay_path(PointerRNA *UNUSED(ptr)) /* Space Image Editor */ +static char *rna_SpaceUVEditor_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("uv_editor"); +} + static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_SpaceUVEditor, ptr->data); @@ -2192,6 +2202,11 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain), /* File browser. */ +static char *rna_FileSelectParams_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("params"); +} + int rna_FileSelectParams_filename_editable(struct PointerRNA *ptr, const char **r_info) { FileSelectParams *params = ptr->data; @@ -2706,6 +2721,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) srna = RNA_def_struct(brna, "SpaceUVEditor", NULL); RNA_def_struct_sdna(srna, "SpaceImage"); RNA_def_struct_nested(brna, srna, "SpaceImageEditor"); + RNA_def_struct_path_func(srna, "rna_SpaceUVEditor_path"); RNA_def_struct_ui_text(srna, "Space UV Editor", "UV editor data for the image editor space"); /* selection */ @@ -3970,10 +3986,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop, "Show 3D Marker Names", "Show names for reconstructed tracks objects"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "fx_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "use_local_collections", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_LOCAL_COLLECTIONS); RNA_def_property_ui_text( @@ -4292,7 +4304,7 @@ static void rna_def_space_image(BlenderRNA *brna) prop = RNA_def_property(srna, "sample_histogram", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "sample_line_hist"); RNA_def_property_struct_type(prop, "Histogram"); - RNA_def_property_ui_text(prop, "Line sample", "Sampled colors along line"); + RNA_def_property_ui_text(prop, "Line Sample", "Sampled colors along line"); prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE); RNA_def_property_array(prop, 2); @@ -4729,7 +4741,7 @@ static void rna_def_space_text(BlenderRNA *brna) prop = RNA_def_property(srna, "use_match_case", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_MATCH_CASE); RNA_def_property_ui_text( - prop, "Match case", "Search string is sensitive to uppercase and lowercase letters"); + prop, "Match Case", "Search string is sensitive to uppercase and lowercase letters"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); prop = RNA_def_property(srna, "find_text", PROP_STRING, PROP_NONE); @@ -5293,7 +5305,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna) {FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text data-blocks"}, {FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font data-blocks"}, {FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World data-blocks"}, - {FILTER_ID_WS, "WORK_SPACE", ICON_NONE, "Workspaces", "Show/hide workspace data-blocks"}, + {FILTER_ID_WS, + "WORK_SPACE", + ICON_WORKSPACE, + "Workspaces", + "Show/hide workspace data-blocks"}, {0, NULL, 0, NULL, NULL}, }; @@ -5335,6 +5351,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) }; srna = RNA_def_struct(brna, "FileSelectParams", NULL); + RNA_def_struct_path_func(srna, "rna_FileSelectParams_path"); RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters"); prop = RNA_def_property(srna, "title", PROP_STRING, PROP_NONE); @@ -5424,7 +5441,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) prop = RNA_def_property(srna, "use_filter_backup", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_BLENDER_BACKUP); RNA_def_property_ui_text( - prop, "Filter BlenderBackup files", "Show .blend1, .blend2, etc. files"); + prop, "Filter Blender Backup Files", "Show .blend1, .blend2, etc. files"); RNA_def_property_ui_icon(prop, ICON_FILE_BACKUP, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -5476,7 +5493,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_enum_items(prop, file_filter_idtypes_items); RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_ui_text( - prop, "Filter ID types", "Which ID types to show/hide, when browsing a library"); + prop, "Filter ID Types", "Which ID types to show/hide, when browsing a library"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "filter_id_category", PROP_ENUM, PROP_NONE); @@ -5484,7 +5501,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_enum_items(prop, file_filter_idcategories_items); RNA_def_property_flag(prop, PROP_ENUM_FLAG); RNA_def_property_ui_text( - prop, "Filter ID categories", "Which ID categories to show/hide, when browsing a library"); + prop, "Filter ID Categories", "Which ID categories to show/hide, when browsing a library"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "filter_glob", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index 64a23dfa985..778e817c73e 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -87,8 +87,60 @@ static int rna_Text_current_line_index_get(PointerRNA *ptr) static void rna_Text_current_line_index_set(PointerRNA *ptr, int value) { - Text *text = (Text *)ptr->data; - txt_move_toline(text, value, 0); + Text *text = ptr->data; + TextLine *line = BLI_findlink(&text->lines, value); + if (line == NULL) { + line = text->lines.last; + } + text->curl = line; + text->curc = 0; +} + +static int rna_Text_select_end_line_index_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_findindex(&text->lines, text->sell); +} + +static void rna_Text_select_end_line_index_set(PointerRNA *ptr, int value) +{ + Text *text = ptr->data; + TextLine *line = BLI_findlink(&text->lines, value); + if (line == NULL) { + line = text->lines.last; + } + text->sell = line; + text->selc = 0; +} + +static int rna_Text_current_character_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_str_utf8_offset_to_index(text->curl->line, text->curc); +} + +static void rna_Text_current_character_set(PointerRNA *ptr, int index) +{ + Text *text = ptr->data; + TextLine *line = text->curl; + const int len_utf8 = BLI_strlen_utf8(line->line); + CLAMP_MAX(index, len_utf8); + text->curc = BLI_str_utf8_offset_from_index(line->line, index); +} + +static int rna_Text_select_end_character_get(PointerRNA *ptr) +{ + Text *text = ptr->data; + return BLI_str_utf8_offset_to_index(text->sell->line, text->selc); +} + +static void rna_Text_select_end_character_set(PointerRNA *ptr, int index) +{ + Text *text = ptr->data; + TextLine *line = text->sell; + const int len_utf8 = BLI_strlen_utf8(line->line); + CLAMP_MAX(index, len_utf8); + text->selc = BLI_str_utf8_offset_from_index(line->line, index); } static void rna_TextLine_body_get(PointerRNA *ptr, char *value) @@ -209,12 +261,14 @@ static void rna_def_text(BlenderRNA *brna) prop, "Current Line", "Current line, and start line of selection if one exists"); prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "curc"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Current Character", "Index of current character in current line, and also start index of " "character in selection if one exists"); + RNA_def_property_int_funcs( + prop, "rna_Text_current_character_get", "rna_Text_current_character_set", NULL); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); prop = RNA_def_property(srna, "current_line_index", PROP_INT, PROP_NONE); RNA_def_property_int_funcs( @@ -230,12 +284,20 @@ static void rna_def_text(BlenderRNA *brna) RNA_def_property_struct_type(prop, "TextLine"); RNA_def_property_ui_text(prop, "Selection End Line", "End line of selection"); + prop = RNA_def_property(srna, "select_end_line_index", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs( + prop, "rna_Text_select_end_line_index_get", "rna_Text_select_end_line_index_set", NULL); + RNA_def_property_ui_text(prop, "Select End Line Index", "Index of last TextLine in selection"); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); + prop = RNA_def_property(srna, "select_end_character", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "selc"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Selection End Character", "Index of character after end of selection in the selection end line"); + RNA_def_property_int_funcs( + prop, "rna_Text_select_end_character_get", "rna_Text_select_end_character_set", NULL); + RNA_def_property_update(prop, NC_TEXT | ND_CURSOR, NULL); RNA_api_text(srna); } diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c index 524dcfa9ad7..000076eccec 100644 --- a/source/blender/makesrna/intern/rna_text_api.c +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -46,6 +46,18 @@ static void rna_Text_write(Text *text, const char *str) WM_main_add_notifier(NC_TEXT | NA_EDITED, text); } +static void rna_Text_select_set(Text *text, int startl, int startc, int endl, int endc) +{ + txt_sel_set(text, startl, startc, endl, endc); + WM_main_add_notifier(NC_TEXT | NA_EDITED, text); +} + +static void rna_Text_cursor_set(Text *text, int line, int ch, bool select) +{ + txt_move_to(text, line, ch, select); + WM_main_add_notifier(NC_TEXT | NA_EDITED, text); +} + #else void RNA_api_text(StructRNA *srna) @@ -69,6 +81,25 @@ void RNA_api_text(StructRNA *srna) RNA_def_function_ui_description(func, "Returns True if the editor supports syntax highlighting " "for the current text datablock"); + + func = RNA_def_function(srna, "select_set", "rna_Text_select_set"); + RNA_def_function_ui_description(func, "Set selection range by line and character index"); + parm = RNA_def_int(func, "line_start", 0, INT_MIN, INT_MAX, "Start Line", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int( + func, "char_start", 0, INT_MIN, INT_MAX, "Start Character", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "line_end", 0, INT_MIN, INT_MAX, "End Line", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "char_end", 0, INT_MIN, INT_MAX, "End Character", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "cursor_set", "rna_Text_cursor_set"); + RNA_def_function_ui_description(func, "Set cursor by line and (optionally) character index"); + parm = RNA_def_int(func, "line", 0, 0, INT_MAX, "Line", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "character", 0, 0, INT_MAX, "Character", "", 0, INT_MAX); + RNA_def_boolean(func, "select", false, "", "Select when moving the cursor"); } #endif diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 0a824b3c67a..4b232251770 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1037,7 +1037,7 @@ static void rna_def_trackingSettings(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, tracker_motion_model); - RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking"); + RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking"); /* default_use_brute */ prop = RNA_def_property(srna, "use_default_brute", PROP_BOOLEAN, PROP_NONE); @@ -1470,7 +1470,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, tracker_motion_model); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Motion model", "Default motion model to use for tracking"); + RNA_def_property_ui_text(prop, "Motion Model", "Default motion model to use for tracking"); /* minimum correlation */ prop = RNA_def_property(srna, "correlation_min", PROP_FLOAT, PROP_NONE); @@ -1849,7 +1849,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna) prop = RNA_def_property(srna, "use_2d_stabilization", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_2D_STABILIZATION); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Use 2D stabilization", "Use 2D stabilization for footage"); + RNA_def_property_ui_text(prop, "Use 2D Stabilization", "Use 2D stabilization for footage"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate"); /* use_stabilize_rotation */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 548111500ad..07ce07710b1 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -424,6 +424,17 @@ static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value) } } +static int rna_UserDef_mouse_emulate_3_button_modifier_get(PointerRNA *ptr) +{ +# if !defined(WIN32) + UserDef *userdef = ptr->data; + return userdef->mouse_emulate_3_button_modifier; +# else + UNUSED_VARS(ptr); + return USER_EMU_MMB_MOD_ALT; +# endif +} + static PointerRNA rna_UserDef_view_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_PreferencesView, ptr->data); @@ -3190,6 +3201,18 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna) RNA_def_property_ui_text(prop, "View Sliders", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "dopesheet_channel", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "ds_channel"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Channel", "Nonlinear Animation Channel"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "nla_track", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "nla_track"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Track", "Nonlinear Animation Track"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "active_action", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "anim_active"); RNA_def_property_array(prop, 4); @@ -3397,6 +3420,16 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame"); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "path_keyframe_before", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Path Before", "Color of path before current frame"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "path_keyframe_after", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "cframe"); RNA_def_property_array(prop, 3); @@ -4044,6 +4077,43 @@ static void rna_def_userdef_view(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem render_display_types[] = { + {USER_RENDER_DISPLAY_NONE, + "NONE", + 0, + "Keep User Interface", + "Images are rendered without changing the user interface"}, + {USER_RENDER_DISPLAY_SCREEN, + "SCREEN", + 0, + "Full Screen", + "Images are rendered in a maximized Image Editor"}, + {USER_RENDER_DISPLAY_AREA, + "AREA", + 0, + "Image Editor", + "Images are rendered in an Image Editor"}, + {USER_RENDER_DISPLAY_WINDOW, + "WINDOW", + 0, + "New Window", + "Images are rendered in a new window"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem temp_space_display_types[] = { + {USER_TEMP_SPACE_DISPLAY_FULLSCREEN, + "SCREEN", /* Could be FULLSCREEN, but keeping it consistent with render_display_types */ + 0, + "Full Screen", + "Open the temporary editor in a maximized screen"}, + {USER_TEMP_SPACE_DISPLAY_WINDOW, + "WINDOW", + 0, + "New Window", + "Open the temporary editor in a new window"}, + {0, NULL, 0, NULL, NULL}, + }; + PropertyRNA *prop; StructRNA *srna; @@ -4172,7 +4242,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO); RNA_def_property_ui_text( prop, - "Open On Mouse Over", + "Open on Mouse Over", "Open menu buttons and pulldowns automatically when the mouse is hovering"); prop = RNA_def_property(srna, "open_toplevel_delay", PROP_INT, PROP_NONE); @@ -4268,6 +4338,17 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Header Position", "Default header position for new space-types"); RNA_def_property_update(prop, 0, "rna_userdef_screen_update_header_default"); + prop = RNA_def_property(srna, "render_display_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, render_display_types); + RNA_def_property_ui_text( + prop, "Render Display Type", "Default location where rendered images will be displayed in"); + + prop = RNA_def_property(srna, "filebrowser_display_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, temp_space_display_types); + RNA_def_property_ui_text(prop, + "File Browser Display Type", + "Default location where the File Editor will be displayed in"); + static const EnumPropertyItem text_hinting_items[] = { {0, "AUTO", 0, "Auto", ""}, {USER_TEXT_HINTING_NONE, "NONE", 0, "None", ""}, @@ -4360,7 +4441,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_enum_items(prop, zoom_frame_modes); RNA_def_property_enum_sdna(prop, NULL, "view_frame_type"); RNA_def_property_ui_text( - prop, "Zoom To Frame Type", "How zooming to frame focuses around current frame"); + prop, "Zoom to Frame Type", "How zooming to frame focuses around current frame"); prop = RNA_def_property(srna, "view_frame_keyframes", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 1, 500); @@ -4576,6 +4657,13 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Color for newly added transformation F-Curves (Location, Rotation, Scale) " "and also Color is based on the transform axis"); + prop = RNA_def_property(srna, "fcurve_new_auto_smoothing", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_fcurve_auto_smoothing_items); + RNA_def_property_enum_sdna(prop, NULL, "auto_smoothing_new"); + RNA_def_property_ui_text(prop, + "New Curve Smoothing Mode", + "Auto Handle Smoothing mode used for newly added F-Curves"); + prop = RNA_def_property(srna, "keyframe_new_interpolation_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_mode_items); RNA_def_property_enum_sdna(prop, NULL, "ipo_new"); @@ -5204,7 +5292,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop = RNA_def_property(srna, "use_zoom_to_mouse", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZOOM_TO_MOUSEPOS); RNA_def_property_ui_text(prop, - "Zoom To Mouse Position", + "Zoom to Mouse Position", "Zoom in towards the mouse pointer's position in the 3D view, " "rather than the 2D window center"); @@ -5429,6 +5517,21 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update"); + static const EnumPropertyItem mouse_emulate_3_button_modifier[] = { + {USER_EMU_MMB_MOD_ALT, "ALT", 0, "Alt", ""}, + {USER_EMU_MMB_MOD_OSKEY, "OSKEY", 0, "OS-Key", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + prop = RNA_def_property(srna, "mouse_emulate_3_button_modifier", PROP_ENUM, PROP_NONE); + /* Only needed because of WIN32 inability to support the option. */ + RNA_def_property_enum_funcs(prop, "rna_UserDef_mouse_emulate_3_button_modifier_get", NULL, NULL); + RNA_def_property_enum_items(prop, mouse_emulate_3_button_modifier); + RNA_def_property_ui_text( + prop, "Emulate 3 Button Modifier", "Hold this modifier to emulate the middle mouse button"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update"); + prop = RNA_def_property(srna, "use_emulate_numpad", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_NONUMPAD); RNA_def_property_ui_text( @@ -5515,11 +5618,6 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Hide System Bookmarks", "Hide system bookmarks in the file selector"); - prop = RNA_def_property(srna, "show_thumbnails", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_THUMBNAILS); - RNA_def_property_ui_text( - prop, "Show Thumbnails", "Open in thumbnail view for images and movies"); - prop = RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index b705f98a3de..886258ee45f 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -41,24 +41,27 @@ #include "rna_internal.h" /* own include */ -/* confusingm 2 enums mixed up here */ +/* confusing 2 enums mixed up here */ const EnumPropertyItem rna_enum_window_cursor_items[] = { - {CURSOR_STD, "DEFAULT", 0, "Default", ""}, - {CURSOR_NONE, "NONE", 0, "None", ""}, - {CURSOR_WAIT, "WAIT", 0, "Wait", ""}, - {CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""}, - {CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""}, - {CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""}, + {WM_CURSOR_DEFAULT, "DEFAULT", 0, "Default", ""}, + {WM_CURSOR_NONE, "NONE", 0, "None", ""}, + {WM_CURSOR_WAIT, "WAIT", 0, "Wait", ""}, + {WM_CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""}, + {WM_CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""}, + {WM_CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""}, /* new */ - {BC_KNIFECURSOR, "KNIFE", 0, "Knife", ""}, - {BC_TEXTEDITCURSOR, "TEXT", 0, "Text", ""}, - {BC_PAINTBRUSHCURSOR, "PAINT_BRUSH", 0, "Paint Brush", ""}, - {BC_HANDCURSOR, "HAND", 0, "Hand", ""}, - {BC_EW_SCROLLCURSOR, "SCROLL_X", 0, "Scroll-X", ""}, - {BC_NS_SCROLLCURSOR, "SCROLL_Y", 0, "Scroll-Y", ""}, - {BC_NSEW_SCROLLCURSOR, "SCROLL_XY", 0, "Scroll-XY", ""}, - {BC_EYEDROPPER_CURSOR, "EYEDROPPER", 0, "Eyedropper", ""}, + {WM_CURSOR_KNIFE, "KNIFE", 0, "Knife", ""}, + {WM_CURSOR_TEXT_EDIT, "TEXT", 0, "Text", ""}, + {WM_CURSOR_PAINT_BRUSH, "PAINT_BRUSH", 0, "Paint Brush", ""}, + {WM_CURSOR_PAINT, "PAINT_CROSS", 0, "Paint Cross", ""}, + {WM_CURSOR_DOT, "DOT", 0, "Dot Cursor", ""}, + {WM_CURSOR_ERASER, "ERASER", 0, "Eraser", ""}, + {WM_CURSOR_HAND, "HAND", 0, "Hand", ""}, + {WM_CURSOR_EW_SCROLL, "SCROLL_X", 0, "Scroll-X", ""}, + {WM_CURSOR_NS_SCROLL, "SCROLL_Y", 0, "Scroll-Y", ""}, + {WM_CURSOR_NSEW_SCROLL, "SCROLL_XY", 0, "Scroll-XY", ""}, + {WM_CURSOR_EYEDROPPER, "EYEDROPPER", 0, "Eyedropper", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c index b8c6a25ace8..f22c86b3ff2 100644 --- a/source/blender/makesrna/intern/rna_workspace_api.c +++ b/source/blender/makesrna/intern/rna_workspace_api.c @@ -110,7 +110,7 @@ void RNA_api_workspace(StructRNA *srna) FunctionRNA *func; PropertyRNA *parm; - func = RNA_def_function(srna, "status_text_set", "ED_workspace_status_text"); + func = RNA_def_function(srna, "status_text_set_internal", "ED_workspace_status_text"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); RNA_def_function_ui_description( func, "Set the status bar text, typically key shortcuts for modal operators"); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 3c3aae8fda6..644ac3a10e8 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -269,8 +269,8 @@ static void dm_mvert_map_doubles(int *doubles_map, static void mesh_merge_transform(Mesh *result, Mesh *cap_mesh, const float cap_offset[4][4], - unsigned int cap_verts_index, - unsigned int cap_edges_index, + uint cap_verts_index, + uint cap_edges_index, int cap_loops_index, int cap_polys_index, int cap_nverts, diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index a05b7023392..0c00bb572be 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -212,7 +212,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes spread, mesh->smoothresh); - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); /* Make sure we never alloc'd these. */ BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index e55eeddbfa5..9868395c0e8 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -316,7 +316,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes MEM_freeN(looptris); } - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index 3d43c6de88e..56e84423db4 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -118,7 +118,7 @@ static void deformVerts(ModifierData *md, if (mesh_src) { float current_time = 0; - unsigned int mvert_num = 0; + uint mvert_num = 0; BKE_mesh_vert_coords_apply(mesh_src, vertexCos); BKE_mesh_calc_normals(mesh_src); diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index a234f468e45..ff241550bdc 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -70,7 +70,7 @@ static void initData(ModifierData *md) csmd->defgrp_name[0] = '\0'; - csmd->delta_cache = NULL; + csmd->delta_cache.deltas = NULL; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) @@ -84,14 +84,14 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords); } - tcsmd->delta_cache = NULL; - tcsmd->delta_cache_num = 0; + tcsmd->delta_cache.deltas = NULL; + tcsmd->delta_cache.totverts = 0; } static void freeBind(CorrectiveSmoothModifierData *csmd) { MEM_SAFE_FREE(csmd->bind_coords); - MEM_SAFE_FREE(csmd->delta_cache); + MEM_SAFE_FREE(csmd->delta_cache.deltas); csmd->bind_coords_num = 0; } @@ -117,11 +117,11 @@ static void requiredDataMask(Object *UNUSED(ob), /* check individual weights for changes and cache values */ static void mesh_get_weights(MDeformVert *dvert, const int defgrp_index, - const unsigned int numVerts, + const uint numVerts, const bool use_invert_vgroup, float *smooth_weights) { - unsigned int i; + uint i; for (i = 0; i < numVerts; i++, dvert++) { const float w = defvert_find_weight(dvert, defgrp_index); @@ -140,11 +140,11 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights) const MPoly *mpoly = mesh->mpoly; const MLoop *mloop = mesh->mloop; const MEdge *medge = mesh->medge; - unsigned int mpoly_num, medge_num, i; - unsigned short *boundaries; + uint mpoly_num, medge_num, i; + ushort *boundaries; - mpoly_num = (unsigned int)mesh->totpoly; - medge_num = (unsigned int)mesh->totedge; + mpoly_num = (uint)mesh->totpoly; + medge_num = (uint)mesh->totedge; boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__); @@ -176,14 +176,14 @@ static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights) static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float (*vertexCos)[3], - unsigned int numVerts, + uint numVerts, const float *smooth_weights, - unsigned int iterations) + uint iterations) { const float lambda = csmd->lambda; - unsigned int i; + uint i; - const unsigned int numEdges = (unsigned int)mesh->totedge; + const uint numEdges = (uint)mesh->totedge; const MEdge *edges = mesh->medge; float *vertex_edge_count_div; @@ -252,18 +252,18 @@ static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float (*vertexCos)[3], - unsigned int numVerts, + uint numVerts, const float *smooth_weights, - unsigned int iterations) + uint iterations) { const float eps = FLT_EPSILON * 10.0f; - const unsigned int numEdges = (unsigned int)mesh->totedge; + const uint numEdges = (uint)mesh->totedge; /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, * and 2.0 rarely spikes, double the value for consistent behavior. */ const float lambda = csmd->lambda * 2.0f; const MEdge *edges = mesh->medge; float *vertex_edge_count; - unsigned int i; + uint i; struct SmoothingData_Weighted { float delta[3]; @@ -346,9 +346,9 @@ static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float (*vertexCos)[3], - unsigned int numVerts, + uint numVerts, const float *smooth_weights, - unsigned int iterations) + uint iterations) { switch (csmd->smooth_type) { case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT: @@ -367,7 +367,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd, MDeformVert *dvert, const int defgrp_index, float (*vertexCos)[3], - unsigned int numVerts) + uint numVerts) { float *smooth_weights = NULL; @@ -391,7 +391,7 @@ static void smooth_verts(CorrectiveSmoothModifierData *csmd, } } - smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat); + smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)csmd->repeat); if (smooth_weights) { MEM_freeN(smooth_weights); @@ -454,13 +454,13 @@ static void calc_tangent_loop_accum(const float v_dir_prev[3], static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3]) { - const unsigned int mpoly_num = (unsigned int)mesh->totpoly; + const uint mpoly_num = (uint)mesh->totpoly; #ifndef USE_TANGENT_CALC_INLINE - const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm); + const uint mvert_num = (uint)dm->getNumVerts(dm); #endif const MPoly *mpoly = mesh->mpoly; const MLoop *mloop = mesh->mloop; - unsigned int i; + uint i; for (i = 0; i < mpoly_num; i++) { const MPoly *mp = &mpoly[i]; @@ -502,6 +502,23 @@ static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tan #endif } +static void store_cache_settings(CorrectiveSmoothModifierData *csmd) +{ + csmd->delta_cache.lambda = csmd->lambda; + csmd->delta_cache.repeat = csmd->repeat; + csmd->delta_cache.flag = csmd->flag; + csmd->delta_cache.smooth_type = csmd->smooth_type; + csmd->delta_cache.rest_source = csmd->rest_source; +} + +static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd) +{ + return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat && + csmd->delta_cache.flag == csmd->flag && + csmd->delta_cache.smooth_type == csmd->smooth_type && + csmd->delta_cache.rest_source == csmd->rest_source); +} + /** * This calculates #CorrectiveSmoothModifierData.delta_cache * It's not run on every update (during animation for example). @@ -511,22 +528,22 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd, MDeformVert *dvert, const int defgrp_index, const float (*rest_coords)[3], - unsigned int numVerts) + uint numVerts) { float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords); float(*tangent_spaces)[3][3]; - unsigned int i; + uint i; tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__); - if (csmd->delta_cache_num != numVerts) { - MEM_SAFE_FREE(csmd->delta_cache); + if (csmd->delta_cache.totverts != numVerts) { + MEM_SAFE_FREE(csmd->delta_cache.deltas); } /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */ - if (!csmd->delta_cache) { - csmd->delta_cache_num = numVerts; - csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); + if (!csmd->delta_cache.deltas) { + csmd->delta_cache.totverts = numVerts; + csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__); } smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts); @@ -544,7 +561,7 @@ static void calc_deltas(CorrectiveSmoothModifierData *csmd, if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) { transpose_m3_m3(imat, tangent_spaces[i]); } - mul_v3_m3v3(csmd->delta_cache[i], imat, delta); + mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta); } MEM_freeN(tangent_spaces); @@ -556,13 +573,14 @@ static void correctivesmooth_modifier_do(ModifierData *md, Object *ob, Mesh *mesh, float (*vertexCos)[3], - unsigned int numVerts, + uint numVerts, struct BMEditMesh *em) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; const bool force_delta_cache_update = /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */ + !cache_settings_equal(csmd) || ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) && (((ID *)ob->data)->recalc & ID_RECALC_ALL)); @@ -575,7 +593,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, /* if rest bind_coords not are defined, set them (only run during bind) */ if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && /* signal to recalculate, whoever sets MUST also free bind coords */ - (csmd->bind_coords_num == (unsigned int)-1)) { + (csmd->bind_coords_num == (uint)-1)) { if (DEG_is_active(depsgraph)) { BLI_assert(csmd->bind_coords == NULL); csmd->bind_coords = MEM_dupallocN(vertexCos); @@ -617,8 +635,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, goto error; } else { - unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : - ((Mesh *)ob->data)->totvert); + uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert); if (me_numVerts != numVerts) { modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts); @@ -628,10 +645,13 @@ static void correctivesmooth_modifier_do(ModifierData *md, } /* check to see if our deltas are still valid */ - if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) { + if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) || + force_delta_cache_update) { const float(*rest_coords)[3]; bool is_rest_coords_alloc = false; + store_cache_settings(csmd); + if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* caller needs to do sanity check here */ csmd->bind_coords_num = numVerts; @@ -642,7 +662,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) : BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts); - BLI_assert((unsigned int)me_numVerts == numVerts); + BLI_assert((uint)me_numVerts == numVerts); is_rest_coords_alloc = true; } @@ -662,7 +682,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) { /* this could be a check, but at this point it _must_ be valid */ - BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache); + BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache.deltas); } #ifdef DEBUG_TIME @@ -673,7 +693,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts); { - unsigned int i; + uint i; float(*tangent_spaces)[3][3]; @@ -689,7 +709,7 @@ static void correctivesmooth_modifier_do(ModifierData *md, calc_tangent_ortho(tangent_spaces[i]); #endif - mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]); + mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]); add_v3_v3(vertexCos[i], delta); } @@ -704,8 +724,8 @@ static void correctivesmooth_modifier_do(ModifierData *md, /* when the modifier fails to execute */ error: - MEM_SAFE_FREE(csmd->delta_cache); - csmd->delta_cache_num = 0; + MEM_SAFE_FREE(csmd->delta_cache.deltas); + csmd->delta_cache.totverts = 0; } static void deformVerts(ModifierData *md, @@ -717,7 +737,7 @@ static void deformVerts(ModifierData *md, Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); correctivesmooth_modifier_do( - md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL); + md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL); if (mesh_src != mesh) { BKE_id_free(NULL, mesh_src); @@ -735,7 +755,7 @@ static void deformVertsEM(ModifierData *md, ctx->object, editData, mesh, NULL, numVerts, false, false); correctivesmooth_modifier_do( - md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData); + md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData); if (mesh_src != mesh) { BKE_id_free(NULL, mesh_src); diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index cff700e8d45..c113a2767a0 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -140,8 +140,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index); if (dvert) { - const unsigned int vert_tot = mesh->totvert; - unsigned int i; + const uint vert_tot = mesh->totvert; + uint i; vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__); @@ -199,7 +199,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes updateFaceCount(ctx, dmd, bm->totface); - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); /* make sure we never alloc'd these */ BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL); BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL); diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index ac0d72214c8..9cb694be88b 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -294,6 +294,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd, mvert = mesh->mvert; MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index); + if (defgrp_index >= 0 && dvert == NULL) { + /* There is a vertex group, but it has no vertices. */ + return; + } + Tex *tex_target = dmd->texture; if (tex_target != NULL) { tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co), "displaceModifier_do tex_co"); diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 904d600164a..a4686e07daf 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -97,7 +97,7 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd) /* BM_mesh_validate(bm); */ /* for troubleshooting */ - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 4ed787810a8..5f0bbc8ecf1 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -201,7 +201,7 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p BLI_rng_free(rng); } -static int edgecut_get(EdgeHash *edgehash, unsigned int v1, unsigned int v2) +static int edgecut_get(EdgeHash *edgehash, uint v1, uint v2) { return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2)); } @@ -649,7 +649,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh) int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ int numlayer; - unsigned int ed_v1, ed_v2; + uint ed_v1, ed_v2; edgehash = BLI_edgehash_new(__func__); @@ -906,7 +906,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; - unsigned int ed_v1, ed_v2, mindex = 0; + uint ed_v1, ed_v2, mindex = 0; MTFace *mtface = NULL, *mtf; totface = mesh->totface; @@ -938,10 +938,13 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, continue; } } + else { + pa = NULL; + } /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ - if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) { + if (pa == NULL || cfra < pa->time) { mindex = totvert + totpart; } else { @@ -1022,6 +1025,9 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, mul_m4_v3(imat, vertco); } + else { + pa = NULL; + } } BLI_edgehashIterator_free(ehi); @@ -1043,13 +1049,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, continue; } } + else { + pa = NULL; + } source = mesh->mface[i]; mf = &explode->mface[u]; orig_v4 = source.v4; - if (facepa[i] != totpart && cfra < pa->time) { + /* Same as above in the first loop over mesh's faces. */ + if (pa == NULL || cfra < pa->time) { mindex = totvert + totpart; } else { @@ -1069,7 +1079,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd, /* override uv channel for particle age */ if (mtface) { - float age = (cfra - pa->time) / pa->lifetime; + float age = (pa != NULL) ? (cfra - pa->time) / pa->lifetime : 0.0f; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c index 587aa108fd1..748bf4db4e2 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c @@ -513,6 +513,12 @@ static Mesh *fluidsim_read_cache( return NULL; } + BKE_mesh_copy_settings(newmesh, orgmesh); + + /* Fluid simulation has a texture space that based on the bounds of the fluid mesh. + * This does not seem particularly useful, but it's backwards compatible. */ + BKE_mesh_texspace_calc(newmesh); + /* load vertex velocities, if they exist... * TODO? use generate flag as loading flag as well? * warning, needs original .bobj.gz mesh loading filename */ diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 2f902db9340..1a62010abe7 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -136,8 +136,8 @@ struct HookData_cb { float falloff_sq; float fac_orig; - unsigned int use_falloff : 1; - unsigned int use_uniform : 1; + uint use_falloff : 1; + uint use_uniform : 1; float cent[3]; diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index c9e0171c9f2..0fc2e0971da 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -66,7 +66,7 @@ typedef struct LaplacianSystem { float (*co)[3]; /* Original vertex coordinates */ float (*no)[3]; /* Original vertex normal */ float (*delta)[3]; /* Differential Coordinates */ - unsigned int (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */ + uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */ int *index_anchors; /* Static vertex index list */ int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */ int *ringf_indices; /* Indices of faces per vertex */ @@ -153,7 +153,7 @@ static void createFaceRingMap(const int mvert_tot, for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { for (j = 0; j < 3; j++) { - const unsigned int v_index = mloop[mlt->tri[j]].v; + const uint v_index = mloop[mlt->tri[j]].v; map[v_index].count++; totalr++; } @@ -167,7 +167,7 @@ static void createFaceRingMap(const int mvert_tot, } for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) { for (j = 0; j < 3; j++) { - const unsigned int v_index = mloop[mlt->tri[j]].v; + const uint v_index = mloop[mlt->tri[j]].v; map[v_index].indices[map[v_index].count] = i; map[v_index].count++; } @@ -253,7 +253,7 @@ static void initLaplacianMatrix(LaplacianSystem *sys) int idv[3]; for (ti = 0; ti < sys->total_tris; ti++) { - const unsigned int *vidt = sys->tris[ti]; + const uint *vidt = sys->tris[ti]; const float *co[3]; co[0] = sys->co[vidt[0]]; @@ -352,7 +352,7 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys) zero_v3(ni); num_fni = sys->ringf_map[i].count; for (fi = 0; fi < num_fni; fi++) { - const unsigned int *vin; + const uint *vin; fidn = sys->ringf_map[i].indices; vin = sys->tris[fidn[fi]]; for (j = 0; j < 3; j++) { diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 4a86c26cdeb..86d4124e5db 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -199,7 +199,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys) float w1, w2, w3; float areaf; int i; - unsigned int idv1, idv2; + uint idv1, idv2; for (i = 0; i < sys->numEdges; i++) { idv1 = sys->medges[i].v1; @@ -233,7 +233,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys) const float *v_prev = sys->vertexCos[l_prev->v]; const float *v_curr = sys->vertexCos[l_curr->v]; const float *v_next = sys->vertexCos[l_next->v]; - const unsigned int l_curr_index = l_curr - sys->mloop; + const uint l_curr_index = l_curr - sys->mloop; sys->numNeFa[l_curr->v] += 1; @@ -274,7 +274,7 @@ static void init_laplacian_matrix(LaplacianSystem *sys) static void fill_laplacian_matrix(LaplacianSystem *sys) { int i; - unsigned int idv1, idv2; + uint idv1, idv2; for (i = 0; i < sys->numPolys; i++) { const MPoly *mp = &sys->mpoly[i]; @@ -284,7 +284,7 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) const MLoop *l_curr = l_term - 1; for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) { - const unsigned int l_curr_index = l_curr - sys->mloop; + const uint l_curr_index = l_curr - sys->mloop; /* Is ring if number of faces == number of edges around vertice*/ if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) { diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index df8f68862e6..cf7d227e898 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -160,7 +160,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes * (including selected matches only): * key = oldindex, value = newindex */ - vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts); + vertHash = BLI_ghash_int_new_ex("mask vert gh", (uint)maxVerts); /* add vertices which exist in vertexgroups into vertHash for filtering * - dv = for each vertex, what vertexgroups does it belong to @@ -204,7 +204,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ - vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts); + vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (uint)maxVerts); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { @@ -220,8 +220,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ - edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges); - polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys); + edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (uint)maxEdges); + polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (uint)maxPolys); mvert_src = mesh->mvert; medge_src = mesh->medge; diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c index 16a118522c5..a3ab0120ff9 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c +++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c @@ -168,7 +168,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp, if (factor >= 1.0f) { #if 1 float *vco = *vertexCos; - unsigned int i; + uint i; for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) { fread(vco, sizeof(float) * 3, 1, fp); @@ -192,7 +192,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp, else { const float ifactor = 1.0f - factor; float *vco = *vertexCos; - unsigned int i; + uint i; for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) { float tvec[3]; fread(tvec, sizeof(float) * 3, 1, fp); diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index 97a8635ac9e..7b8ad0bd705 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -153,7 +153,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp, if (factor >= 1.0f) { float *vco = *vertexCos; - unsigned int i; + uint i; for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) { fread(vco, sizeof(float) * 3, 1, fp); @@ -167,7 +167,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp, else { const float ifactor = 1.0f - factor; float *vco = *vertexCos; - unsigned int i; + uint i; for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) { float tvec[3]; fread(tvec, sizeof(float) * 3, 1, fp); diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 21ec3505dc9..47f8528ee94 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -30,6 +30,7 @@ #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_mesh.h" +#include "BKE_mirror.h" #include "BKE_modifier.h" #include "BKE_deform.h" @@ -68,377 +69,6 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } } -static Mesh *doBiscetOnMirrorPlane(MirrorModifierData *mmd, - const Mesh *mesh, - int axis, - const float plane_co[3], - float plane_no[3]) -{ - bool do_bisect_flip_axis = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) || - (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) || - (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z)); - - const float bisect_distance = 0.001f; - - Mesh *result; - BMesh *bm; - BMIter viter; - BMVert *v, *v_next; - - bm = BKE_mesh_to_bmesh_ex(mesh, - &(struct BMeshCreateParams){0}, - &(struct BMeshFromMeshParams){ - .calc_face_normal = true, - .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, - .emask = CD_MASK_ORIGINDEX, - .pmask = CD_MASK_ORIGINDEX}, - }); - - /* Define bisecting plane (aka mirror plane). */ - float plane[4]; - if (!do_bisect_flip_axis) { - /* That reversed condition is a tad weird, but for some reason that's how you keep - * the part of the mesh which is on the non-mirrored side when flip option is disabled, - * think that that is the expected behavior. */ - negate_v3(plane_no); - } - plane_from_point_normal_v3(plane, plane_co, plane_no); - - BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance); - - /* Plane definitions for vert killing. */ - float plane_offset[4]; - copy_v3_v3(plane_offset, plane); - plane_offset[3] = plane[3] - bisect_distance; - - /* Delete verts across the mirror plane. */ - BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { - if (plane_point_side_v3(plane_offset, v->co) > 0.0f) { - BM_vert_kill(bm, v); - } - } - - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); - - return result; -} - -static Mesh *doMirrorOnAxis(MirrorModifierData *mmd, - const ModifierEvalContext *UNUSED(ctx), - Object *ob, - const Mesh *mesh, - int axis) -{ - const float tolerance_sq = mmd->tolerance * mmd->tolerance; - const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0; - int tot_vtargetmap = 0; /* total merge vertices */ - - const bool do_bisect = ((axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) || - (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) || - (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z)); - - Mesh *result; - MVert *mv, *mv_prev; - MEdge *me; - MLoop *ml; - MPoly *mp; - float mtx[4][4]; - float plane_co[3], plane_no[3]; - int i; - int a, totshape; - int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL; - - /* mtx is the mirror transformation */ - unit_m4(mtx); - mtx[axis][axis] = -1.0f; - - Object *mirror_ob = mmd->mirror_ob; - if (mirror_ob != NULL) { - float tmp[4][4]; - float itmp[4][4]; - - /* tmp is a transform from coords relative to the object's own origin, - * to coords relative to the mirror object origin */ - invert_m4_m4(tmp, mirror_ob->obmat); - mul_m4_m4m4(tmp, tmp, ob->obmat); - - /* itmp is the reverse transform back to origin-relative coordinates */ - invert_m4_m4(itmp, tmp); - - /* combine matrices to get a single matrix that translates coordinates into - * mirror-object-relative space, does the mirror, and translates back to - * origin-relative space */ - mul_m4_series(mtx, itmp, mtx, tmp); - - if (do_bisect) { - copy_v3_v3(plane_co, itmp[3]); - copy_v3_v3(plane_no, itmp[axis]); - } - } - else if (do_bisect) { - copy_v3_v3(plane_co, mtx[3]); - /* Need to negate here, since that axis is inverted (for mirror transform). */ - negate_v3_v3(plane_no, mtx[axis]); - } - - Mesh *mesh_bisect = NULL; - if (do_bisect) { - mesh_bisect = doBiscetOnMirrorPlane(mmd, mesh, axis, plane_co, plane_no); - mesh = mesh_bisect; - } - - const int maxVerts = mesh->totvert; - const int maxEdges = mesh->totedge; - const int maxLoops = mesh->totloop; - const int maxPolys = mesh->totpoly; - - result = BKE_mesh_new_nomain_from_template( - mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2); - - /*copy customdata to original geometry*/ - CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts); - CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges); - CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops); - CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys); - - /* Subsurf for eg won't have mesh data in the custom data arrays. - * now add mvert/medge/mpoly layers. */ - if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) { - memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert); - } - if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) { - memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge); - } - if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) { - memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop); - memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly); - } - - /* copy customdata to new geometry, - * copy from its self because this data may have been created in the checks above */ - CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts); - CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges); - /* loops are copied later */ - CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys); - - if (do_vtargetmap) { - /* second half is filled with -1 */ - vtargetmap = MEM_malloc_arrayN(maxVerts, 2 * sizeof(int), "MOD_mirror tarmap"); - - vtmap_a = vtargetmap; - vtmap_b = vtargetmap + maxVerts; - } - - /* mirror vertex coordinates */ - mv_prev = result->mvert; - mv = mv_prev + maxVerts; - for (i = 0; i < maxVerts; i++, mv++, mv_prev++) { - mul_m4_v3(mtx, mv->co); - - if (do_vtargetmap) { - /* compare location of the original and mirrored vertex, to see if they - * should be mapped for merging */ - if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) { - *vtmap_a = maxVerts + i; - tot_vtargetmap++; - - /* average location */ - mid_v3_v3v3(mv->co, mv_prev->co, mv->co); - copy_v3_v3(mv_prev->co, mv->co); - } - else { - *vtmap_a = -1; - } - - *vtmap_b = -1; /* fill here to avoid 2x loops */ - - vtmap_a++; - vtmap_b++; - } - } - - /* handle shape keys */ - totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY); - for (a = 0; a < totshape; a++) { - float(*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a); - for (i = maxVerts; i < result->totvert; i++) { - mul_m4_v3(mtx, cos[i]); - } - } - - /* adjust mirrored edge vertex indices */ - me = result->medge + maxEdges; - for (i = 0; i < maxEdges; i++, me++) { - me->v1 += maxVerts; - me->v2 += maxVerts; - } - - /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */ - mp = result->mpoly + maxPolys; - ml = result->mloop; - for (i = 0; i < maxPolys; i++, mp++) { - MLoop *ml2; - int j, e; - - /* reverse the loop, but we keep the first vertex in the face the same, - * to ensure that quads are split the same way as on the other side */ - CustomData_copy_data( - &result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1); - - for (j = 1; j < mp->totloop; j++) { - CustomData_copy_data(&result->ldata, - &result->ldata, - mp->loopstart + j, - mp->loopstart + maxLoops + mp->totloop - j, - 1); - } - - ml2 = ml + mp->loopstart + maxLoops; - e = ml2[0].e; - for (j = 0; j < mp->totloop - 1; j++) { - ml2[j].e = ml2[j + 1].e; - } - ml2[mp->totloop - 1].e = e; - - mp->loopstart += maxLoops; - } - - /* adjust mirrored loop vertex and edge indices */ - ml = result->mloop + maxLoops; - for (i = 0; i < maxLoops; i++, ml++) { - ml->v += maxVerts; - ml->e += maxEdges; - } - - /* handle uvs, - * let tessface recalc handle updating the MTFace data */ - if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) || - (is_zero_v2(mmd->uv_offset_copy) == false)) { - const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0; - const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0; - - const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV); - - for (a = 0; a < totuv; a++) { - MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a); - int j = maxLoops; - dmloopuv += j; /* second set of loops only */ - for (; j-- > 0; dmloopuv++) { - if (do_mirr_u) { - dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0]; - } - if (do_mirr_v) { - dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1]; - } - dmloopuv->uv[0] += mmd->uv_offset_copy[0]; - dmloopuv->uv[1] += mmd->uv_offset_copy[1]; - } - } - } - - /* handle custom split normals */ - if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && - CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL)) { - const int totloop = result->totloop; - const int totpoly = result->totpoly; - float(*loop_normals)[3] = MEM_calloc_arrayN((size_t)totloop, sizeof(*loop_normals), __func__); - CustomData *ldata = &result->ldata; - short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); - MLoopNorSpaceArray lnors_spacearr = {NULL}; - float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__); - - /* calculate custom normals into loop_normals, then mirror first half into second half */ - - BKE_mesh_calc_normals_poly(result->mvert, - NULL, - result->totvert, - result->mloop, - result->mpoly, - totloop, - totpoly, - poly_normals, - false); - - BKE_mesh_normals_loop_split(result->mvert, - result->totvert, - result->medge, - result->totedge, - result->mloop, - loop_normals, - totloop, - result->mpoly, - poly_normals, - totpoly, - true, - mesh->smoothresh, - &lnors_spacearr, - clnors, - NULL); - - /* mirroring has to account for loops being reversed in polys in second half */ - mp = result->mpoly; - for (i = 0; i < maxPolys; i++, mp++) { - MPoly *mpmirror = result->mpoly + maxPolys + i; - int j; - - for (j = mp->loopstart; j < mp->loopstart + mp->totloop; j++) { - int mirrorj = mpmirror->loopstart; - if (j > mp->loopstart) { - mirrorj += mpmirror->totloop - (j - mp->loopstart); - } - copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); - loop_normals[mirrorj][axis] = -loop_normals[j][axis]; - BKE_lnor_space_custom_normal_to_data( - lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]); - } - } - - MEM_freeN(poly_normals); - MEM_freeN(loop_normals); - BKE_lnor_spacearr_free(&lnors_spacearr); - } - - /* handle vgroup stuff */ - if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) { - MDeformVert *dvert = (MDeformVert *)CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) + - maxVerts; - int *flip_map = NULL, flip_map_len = 0; - - flip_map = defgroup_flip_map(ob, &flip_map_len, false); - - if (flip_map) { - for (i = 0; i < maxVerts; dvert++, i++) { - /* merged vertices get both groups, others get flipped */ - if (do_vtargetmap && (vtargetmap[i] != -1)) { - defvert_flip_merged(dvert, flip_map, flip_map_len); - } - else { - defvert_flip(dvert, flip_map, flip_map_len); - } - } - - MEM_freeN(flip_map); - } - } - - if (do_vtargetmap) { - /* slow - so only call if one or more merge verts are found, - * users may leave this on and not realize there is nothing to merge - campbell */ - if (tot_vtargetmap) { - result = BKE_mesh_merge_verts( - result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED); - } - MEM_freeN(vtargetmap); - } - - if (mesh_bisect != NULL) { - BKE_id_free(NULL, mesh_bisect); - } - - return result; -} - static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, const ModifierEvalContext *ctx, Object *ob, @@ -448,11 +78,11 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, /* check which axes have been toggled and mirror accordingly */ if (mmd->flag & MOD_MIR_AXIS_X) { - result = doMirrorOnAxis(mmd, ctx, ob, result, 0); + result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 0); } if (mmd->flag & MOD_MIR_AXIS_Y) { Mesh *tmp = result; - result = doMirrorOnAxis(mmd, ctx, ob, result, 1); + result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 1); if (tmp != mesh) { /* free intermediate results */ BKE_id_free(NULL, tmp); @@ -460,7 +90,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd, } if (mmd->flag & MOD_MIR_AXIS_Z) { Mesh *tmp = result; - result = doMirrorOnAxis(mmd, ctx, ob, result, 2); + result = BKE_mirror_apply_mirror_on_axis(mmd, ctx, ob, result, 2); if (tmp != mesh) { /* free intermediate results */ BKE_id_free(NULL, tmp); diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index dd7c001931c..883c17aa1e1 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -38,6 +38,7 @@ #include "BKE_paint.h" #include "BKE_subdiv.h" #include "BKE_subdiv_ccg.h" +#include "BKE_subdiv_deform.h" #include "BKE_subdiv_mesh.h" #include "BKE_subsurf.h" @@ -227,6 +228,42 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes return result; } +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh, + float (*vertex_cos)[3], + float (*deform_matrices)[3][3], + int num_verts) + +{ +#if !defined(WITH_OPENSUBDIV) + modifier_setError(md, "Disabled, built without OpenSubdiv"); + return; +#endif + + /* Subsurf does not require extra space mapping, keep matrices as is. */ + (void)deform_matrices; + + MultiresModifierData *mmd = (MultiresModifierData *)md; + SubdivSettings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); + if (subdiv_settings.level == 0) { + return; + } + BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); + MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd); + Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh); + if (subdiv == NULL) { + /* Happens on bad topology, ut also on empty input mesh. */ + return; + } + BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd); + BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts); + if (subdiv != runtime_data->subdiv) { + BKE_subdiv_free(subdiv); + } +} + ModifierTypeInfo modifierType_Multires = { /* name */ "Multires", /* structName */ "MultiresModifierData", @@ -238,7 +275,7 @@ ModifierTypeInfo modifierType_Multires = { /* copyData */ copyData, /* deformVerts */ NULL, - /* deformMatrices */ NULL, + /* deformMatrices */ deformMatrices, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index aff5b8b071b..97be42367d4 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -268,7 +268,7 @@ static void generate_ocean_geometry_uvs(void *__restrict userdata, } } -static Mesh *generate_ocean_geometry(OceanModifierData *omd) +static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig) { Mesh *result; @@ -296,6 +296,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd) gogd.sy /= gogd.ry; result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys); + BKE_mesh_copy_settings(result, mesh_orig); gogd.mverts = result->mvert; gogd.mpolys = result->mpoly; @@ -377,7 +378,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes } if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { - result = generate_ocean_geometry(omd); + result = generate_ocean_geometry(omd, mesh); BKE_mesh_ensure_normals(result); } else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index a7c7c207cd6..67a64921bbc 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -168,7 +168,7 @@ static void deformVerts(ModifierData *md, if (em) { /* In edit mode get directly from the edit mesh. */ - psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); + psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh); } else { /* Otherwise get regular mesh. */ diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index 631401d9d9e..df84f3db55c 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -185,6 +185,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c } } + BKE_mesh_copy_settings(result, mesh); BKE_mesh_calc_edges(result, true, false); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; return result; diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index ac47422fe2f..773cbf72d5b 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -46,18 +46,18 @@ /* used for gathering edge connectivity */ typedef struct ScrewVertConnect { - float dist; /* distance from the center axis */ - float co[3]; /* location relative to the transformed axis */ - float no[3]; /* calc normal of the vertex */ - unsigned int v[2]; /* 2 verts on either side of this one */ - MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */ + float dist; /* distance from the center axis */ + float co[3]; /* location relative to the transformed axis */ + float no[3]; /* calc normal of the vertex */ + uint v[2]; /* 2 verts on either side of this one */ + MEdge *e[2]; /* edges on either side, a bit of a waste since each edge ref's 2 edges */ char flag; } ScrewVertConnect; typedef struct ScrewVertIter { ScrewVertConnect *v_array; ScrewVertConnect *v_poin; - unsigned int v, v_other; + uint v, v_other; MEdge *e; } ScrewVertIter; @@ -67,8 +67,8 @@ typedef struct ScrewVertIter { static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, - unsigned int v_init, - unsigned int dir) + uint v_init, + uint dir) { iter->v_array = array; iter->v = v_init; @@ -187,10 +187,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes int *origindex; int mpoly_index = 0; - unsigned int step; - unsigned int i, j; - unsigned int i1, i2; - unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; + uint step; + uint i, j; + uint i1, i2; + uint step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0; const int quad_ord[4] = { @@ -206,17 +206,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes 3, }; - unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; - const unsigned int totvert = (unsigned int)mesh->totvert; - const unsigned int totedge = (unsigned int)mesh->totedge; - const unsigned int totpoly = (unsigned int)mesh->totpoly; + uint maxVerts = 0, maxEdges = 0, maxPolys = 0; + const uint totvert = (uint)mesh->totvert; + const uint totedge = (uint)mesh->totedge; + const uint totpoly = (uint)mesh->totpoly; - unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ - unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ + uint *edge_poly_map = NULL; /* orig edge to orig poly */ + uint *vert_loop_map = NULL; /* orig vert to orig loop */ /* UV Coords */ - const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata, - CD_MLOOPUV); + const uint mloopuv_layers_tot = (uint)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); float uv_u_scale; float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; @@ -235,11 +234,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; - unsigned int vc_tot_linked = 0; + uint vc_tot_linked = 0; short other_axis_1, other_axis_2; const float *tmpf1, *tmpf2; - unsigned int edge_offset; + uint edge_offset; MPoly *mpoly_orig, *mpoly_new, *mp_new; MLoop *mloop_orig, *mloop_new, *ml_new; @@ -409,7 +408,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (mloopuv_layers_tot) { - unsigned int uv_lay; + uint uv_lay; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay); } @@ -460,18 +459,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { - unsigned int loopstart = (unsigned int)mp_orig->loopstart; - unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; + uint loopstart = (uint)mp_orig->loopstart; + uint loopend = loopstart + (uint)mp_orig->totloop; MLoop *ml_orig = &mloop_orig[loopstart]; - unsigned int k; + uint k; for (k = loopstart; k < loopend; k++, ml_orig++) { edge_poly_map[ml_orig->e] = i; vert_loop_map[ml_orig->v] = k; /* also order edges based on faces */ if (medge_new[ml_orig->e].v1 != ml_orig->v) { - SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); + SWAP(uint, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); } } } @@ -596,7 +595,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes * so resulting faces are flipped the right way */ vc_tot_linked = 0; /* count the number of linked verts for this loop */ if (vc->flag == 0) { - unsigned int v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */ + uint v_best = SV_UNUSED, ed_loop_closed = 0; /* vert and vert new */ ScrewVertIter lt_iter; float fl = -1.0f; @@ -731,7 +730,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (lt_iter.v == lt_iter.e->v1) { if (ed_loop_flip == 0) { /*printf("\t\t\tFlipping 0\n");*/ - SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); + SWAP(uint, lt_iter.e->v1, lt_iter.e->v2); } #if 0 else { @@ -742,7 +741,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes else if (lt_iter.v == lt_iter.e->v2) { if (ed_loop_flip == 1) { /*printf("\t\t\tFlipping 1\n");*/ - SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2); + SWAP(uint, lt_iter.e->v1, lt_iter.e->v2); } #if 0 else { @@ -851,7 +850,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes /* Add Faces */ for (step = 1; step < step_tot; step++) { - const unsigned int varray_stride = totvert * step; + const uint varray_stride = totvert * step; float step_angle; float nor_tx[3]; float mat[4][4]; @@ -921,7 +920,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (close) { /* last loop of edges, previous loop doesn't account for the last set of edges */ - const unsigned int varray_stride = (step_tot - 1) * totvert; + const uint varray_stride = (step_tot - 1) * totvert; for (i = 0; i < totvert; i++) { med_new->v1 = i; @@ -942,12 +941,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes edge_offset = totedge + (totvert * (step_tot - (close ? 0 : 1))); for (i = 0; i < totedge; i++, med_new_firstloop++) { - const unsigned int step_last = step_tot - (close ? 1 : 2); - const unsigned int mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; + const uint step_last = step_tot - (close ? 1 : 2); + const uint mpoly_index_orig = totpoly ? edge_poly_map[i] : UINT_MAX; const bool has_mpoly_orig = (mpoly_index_orig != UINT_MAX); float uv_v_offset_a, uv_v_offset_b; - const unsigned int mloop_index_orig[2] = { + const uint mloop_index_orig[2] = { vert_loop_map ? vert_loop_map[medge_new[i].v1] : UINT_MAX, vert_loop_map ? vert_loop_map[medge_new[i].v2] : UINT_MAX, }; @@ -1006,7 +1005,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes &mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1); if (mloopuv_layers_tot) { - unsigned int uv_lay; + uint uv_lay; const float uv_u_offset_a = (float)(step)*uv_u_scale; const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { @@ -1023,7 +1022,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (mloopuv_layers_tot) { int l_index = (int)(ml_new - mloop_new); - unsigned int uv_lay; + uint uv_lay; const float uv_u_offset_a = (float)(step)*uv_u_scale; const float uv_u_offset_b = (float)(step + 1) * uv_u_scale; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { @@ -1094,7 +1093,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes unsigned i = 0; printf("\n"); for (; i < maxPolys * 4; i += 4) { - unsigned int ii; + uint ii; ml_new = mloop_new + i; ii = findEd(medge_new, maxEdges, ml_new[0].v, ml_new[1].v); printf("%d %d -- ", ii, ml_new[0].e); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index f11e4e4d77a..6e7a0b0dbae 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -103,7 +103,7 @@ typedef struct Frame { int corner; /* checked to avoid chaining. * (merging when we're already been referenced), see T39775 */ - unsigned int is_target : 1; + uint is_target : 1; } merge[4]; /* For hull frames, whether each vertex is detached or not */ @@ -1871,7 +1871,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd) return NULL; } - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh); BM_mesh_free(bm); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index 59d5b2ccbd2..c8bc3aaa484 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -54,16 +54,15 @@ static bool isDisabled(const struct Scene *UNUSED(scene), bool UNUSED(useRenderParams)) { SmoothModifierData *smd = (SmoothModifierData *)md; - short flag; - flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z); + const short flag = smd->flag & (MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z); /* disable if modifier is off for X, Y and Z or if factor is 0 */ - if ((smd->fac == 0.0f) || flag == 0) { - return 1; + if (smd->fac == 0.0f || flag == 0) { + return true; } - return 0; + return false; } static void requiredDataMask(Object *UNUSED(ob), @@ -81,134 +80,105 @@ static void requiredDataMask(Object *UNUSED(ob), static void smoothModifier_do( SmoothModifierData *smd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts) { - MDeformVert *dvert = NULL; - MEdge *medges = NULL; - - int i, j, numDMEdges, defgrp_index; - unsigned char *uctmp; - float *ftmp, fac, facm; + if (mesh == NULL) { + return; + } - ftmp = (float *)MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "smoothmodifier_f"); - if (!ftmp) { + float(*accumulated_vecs)[3] = MEM_calloc_arrayN( + (size_t)numVerts, sizeof(*accumulated_vecs), __func__); + if (!accumulated_vecs) { return; } - uctmp = (unsigned char *)MEM_calloc_arrayN(numVerts, sizeof(unsigned char), "smoothmodifier_uc"); - if (!uctmp) { - if (ftmp) { - MEM_freeN(ftmp); + + uint *num_accumulated_vecs = MEM_calloc_arrayN( + (size_t)numVerts, sizeof(*num_accumulated_vecs), __func__); + if (!num_accumulated_vecs) { + if (accumulated_vecs) { + MEM_freeN(accumulated_vecs); } return; } - fac = smd->fac; - facm = 1 - fac; + const float fac_new = smd->fac; + const float fac_orig = 1.0f - fac_new; - if (mesh != NULL) { - medges = mesh->medge; - numDMEdges = mesh->totedge; - } - else { - medges = NULL; - numDMEdges = 0; - } + MEdge *medges = mesh->medge; + const int num_edges = mesh->totedge; + MDeformVert *dvert; + int defgrp_index; MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index); - /* NOTICE: this can be optimized a little bit by moving the - * if (dvert) out of the loop, if needed */ - for (j = 0; j < smd->repeat; j++) { - for (i = 0; i < numDMEdges; i++) { - float fvec[3]; - float *v1, *v2; - unsigned int idx1, idx2; - - idx1 = medges[i].v1; - idx2 = medges[i].v2; + for (int j = 0; j < smd->repeat; j++) { + if (j != 0) { + memset(accumulated_vecs, 0, sizeof(*accumulated_vecs) * (size_t)numVerts); + memset(num_accumulated_vecs, 0, sizeof(*num_accumulated_vecs) * (size_t)numVerts); + } - v1 = vertexCos[idx1]; - v2 = vertexCos[idx2]; + for (int i = 0; i < num_edges; i++) { + float fvec[3]; + const uint idx1 = medges[i].v1; + const uint idx2 = medges[i].v2; - mid_v3_v3v3(fvec, v1, v2); + mid_v3_v3v3(fvec, vertexCos[idx1], vertexCos[idx2]); - v1 = &ftmp[idx1 * 3]; - v2 = &ftmp[idx2 * 3]; + num_accumulated_vecs[idx1]++; + add_v3_v3(accumulated_vecs[idx1], fvec); - if (uctmp[idx1] < 255) { - uctmp[idx1]++; - add_v3_v3(v1, fvec); - } - if (uctmp[idx2] < 255) { - uctmp[idx2]++; - add_v3_v3(v2, fvec); - } + num_accumulated_vecs[idx2]++; + add_v3_v3(accumulated_vecs[idx2], fvec); } + const short flag = smd->flag; if (dvert) { MDeformVert *dv = dvert; - for (i = 0; i < numVerts; i++, dv++) { - float f, fm, facw, *fp, *v; - short flag = smd->flag; - - v = vertexCos[i]; - fp = &ftmp[i * 3]; - - f = defvert_find_weight(dv, defgrp_index); - if (f <= 0.0f) { - continue; + for (int i = 0; i < numVerts; i++, dv++) { + float *vco_orig = vertexCos[i]; + if (num_accumulated_vecs[0] > 0) { + mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]); } + float *vco_new = accumulated_vecs[i]; - f *= fac; - fm = 1.0f - f; - - /* fp is the sum of uctmp[i] verts, so must be averaged */ - facw = 0.0f; - if (uctmp[i]) { - facw = f / (float)uctmp[i]; + const float f_new = defvert_find_weight(dv, defgrp_index) * fac_new; + if (f_new <= 0.0f) { + continue; } + const float f_orig = 1.0f - f_new; if (flag & MOD_SMOOTH_X) { - v[0] = fm * v[0] + facw * fp[0]; + vco_orig[0] = f_orig * vco_orig[0] + f_new * vco_new[0]; } if (flag & MOD_SMOOTH_Y) { - v[1] = fm * v[1] + facw * fp[1]; + vco_orig[1] = f_orig * vco_orig[1] + f_new * vco_new[1]; } if (flag & MOD_SMOOTH_Z) { - v[2] = fm * v[2] + facw * fp[2]; + vco_orig[2] = f_orig * vco_orig[2] + f_new * vco_new[2]; } } } else { /* no vertex group */ - for (i = 0; i < numVerts; i++) { - float facw, *fp, *v; - short flag = smd->flag; - - v = vertexCos[i]; - fp = &ftmp[i * 3]; - - /* fp is the sum of uctmp[i] verts, so must be averaged */ - facw = 0.0f; - if (uctmp[i]) { - facw = fac / (float)uctmp[i]; + for (int i = 0; i < numVerts; i++) { + float *vco_orig = vertexCos[i]; + if (num_accumulated_vecs[0] > 0) { + mul_v3_fl(accumulated_vecs[i], 1.0f / (float)num_accumulated_vecs[i]); } + float *vco_new = accumulated_vecs[i]; if (flag & MOD_SMOOTH_X) { - v[0] = facm * v[0] + facw * fp[0]; + vco_orig[0] = fac_orig * vco_orig[0] + fac_new * vco_new[0]; } if (flag & MOD_SMOOTH_Y) { - v[1] = facm * v[1] + facw * fp[1]; + vco_orig[1] = fac_orig * vco_orig[1] + fac_new * vco_new[1]; } if (flag & MOD_SMOOTH_Z) { - v[2] = facm * v[2] + facw * fp[2]; + vco_orig[2] = fac_orig * vco_orig[2] + fac_new * vco_new[2]; } } } - - memset(ftmp, 0, 3 * sizeof(float) * numVerts); - memset(uctmp, 0, sizeof(unsigned char) * numVerts); } - MEM_freeN(ftmp); - MEM_freeN(uctmp); + MEM_freeN(accumulated_vecs); + MEM_freeN(num_accumulated_vecs); } static void deformVerts(ModifierData *md, diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 05bcc7f695d..292e659fe03 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -198,11 +198,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes MEdge *ed, *medge, *orig_medge; MLoop *ml, *mloop, *orig_mloop; MPoly *mp, *mpoly, *orig_mpoly; - const unsigned int numVerts = (unsigned int)mesh->totvert; - const unsigned int numEdges = (unsigned int)mesh->totedge; - const unsigned int numPolys = (unsigned int)mesh->totpoly; - const unsigned int numLoops = (unsigned int)mesh->totloop; - unsigned int newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; + const uint numVerts = (uint)mesh->totvert; + const uint numEdges = (uint)mesh->totedge; + const uint numPolys = (uint)mesh->totpoly; + const uint numLoops = (uint)mesh->totloop; + uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0; /* only use material offsets if we have 2 or more materials */ const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0; @@ -211,16 +211,16 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes /* use for edges */ /* over-alloc new_vert_arr, old_vert_arr */ - unsigned int *new_vert_arr = NULL; + uint *new_vert_arr = NULL; STACK_DECLARE(new_vert_arr); - unsigned int *new_edge_arr = NULL; + uint *new_edge_arr = NULL; STACK_DECLARE(new_edge_arr); - unsigned int *old_vert_arr = MEM_calloc_arrayN( + uint *old_vert_arr = MEM_calloc_arrayN( numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); - unsigned int *edge_users = NULL; + uint *edge_users = NULL; char *edge_order = NULL; float(*vert_nors)[3] = NULL; @@ -244,7 +244,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes int defgrp_index; /* array size is doubled in case of using a shell */ - const unsigned int stride = do_shell ? 2 : 1; + const uint stride = do_shell ? 2 : 1; MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); @@ -272,11 +272,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (smd->flag & MOD_SOLIDIFY_RIM) { BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); - unsigned int eidx; - unsigned int i; + uint eidx; + uint i; -#define INVALID_UNUSED ((unsigned int)-1) -#define INVALID_PAIR ((unsigned int)-2) +#define INVALID_UNUSED ((uint)-1) +#define INVALID_PAIR ((uint)-2) new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__); new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__); @@ -442,13 +442,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes /* flip normals */ if (do_shell) { - unsigned int i; + uint i; mp = mpoly + numPolys; for (i = 0; i < mesh->totpoly; i++, mp++) { const int loop_end = mp->totloop - 1; MLoop *ml2; - unsigned int e; + uint e; int j; /* reverses the loop direction (MLoop.v as well as custom-data) @@ -512,7 +512,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes const float offset_sq = offset * offset; if (do_clamp) { - unsigned int i; + uint i; vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens"); copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX); @@ -524,7 +524,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (ofs_new != 0.0f) { - unsigned int i_orig, i_end; + uint i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; @@ -532,7 +532,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) { @@ -559,7 +559,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (ofs_orig != 0.0f) { - unsigned int i_orig, i_end; + uint i_orig, i_end; bool do_shell_align; scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; @@ -568,7 +568,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (dvert) { MDeformVert *dv = &dvert[i]; if (defgrp_invert) { @@ -606,8 +606,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes float *vert_angles = MEM_calloc_arrayN( numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; - unsigned int vidx; - unsigned int i; + uint vidx; + uint i; if (vert_nors == NULL) { vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno"); @@ -707,13 +707,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (ofs_new != 0.0f) { - unsigned int i_orig, i_end; + uint i_orig, i_end; bool do_shell_align; INIT_VERT_ARRAY_OFFSETS(false); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; + const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl( mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other])); @@ -722,14 +722,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (ofs_orig != 0.0f) { - unsigned int i_orig, i_end; + uint i_orig, i_end; bool do_shell_align; /* same as above but swapped, intentional use of 'ofs_new' */ INIT_VERT_ARRAY_OFFSETS(true); for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { - const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; + const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i_other]) { /* zero if unselected */ madd_v3_v3fl( mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other])); @@ -749,7 +749,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } else if (do_shell) { - unsigned int i; + uint i; /* flip vertex normals for copied verts */ mv = mvert + numVerts; for (i = 0; i < numVerts; i++, mv++) { @@ -758,7 +758,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes } if (smd->flag & MOD_SOLIDIFY_RIM) { - unsigned int i; + uint i; /* bugger, need to re-calculate the normals for the new edge faces. * This could be done in many ways, but probably the quickest way @@ -781,13 +781,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes NULL; float nor[3]; #endif - const unsigned char crease_rim = smd->crease_rim * 255.0f; - const unsigned char crease_outer = smd->crease_outer * 255.0f; - const unsigned char crease_inner = smd->crease_inner * 255.0f; + const uchar crease_rim = smd->crease_rim * 255.0f; + const uchar crease_outer = smd->crease_outer * 255.0f; + const uchar crease_inner = smd->crease_inner * 255.0f; int *origindex_edge; int *orig_ed; - unsigned int j; + uint j; if (crease_rim || crease_outer || crease_inner) { result->cd_flag |= ME_CDFLAG_EDGE_CREASE; @@ -817,8 +817,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes ml = mloop + (numLoops * stride); j = 0; for (i = 0; i < newPolys; i++, mp++) { - unsigned int eidx = new_edge_arr[i]; - unsigned int pidx = edge_users[eidx]; + uint eidx = new_edge_arr[i]; + uint pidx = edge_users[eidx]; int k1, k2; bool flip; diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 08a884fa879..4a5887c3122 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -35,6 +35,7 @@ #include "BKE_scene.h" #include "BKE_subdiv.h" #include "BKE_subdiv_ccg.h" +#include "BKE_subdiv_deform.h" #include "BKE_subdiv_mesh.h" #include "BKE_subsurf.h" @@ -240,6 +241,40 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes return result; } +static void deformMatrices(ModifierData *md, + const ModifierEvalContext *UNUSED(ctx), + Mesh *mesh, + float (*vertex_cos)[3], + float (*deform_matrices)[3][3], + int num_verts) +{ +#if !defined(WITH_OPENSUBDIV) + modifier_setError(md, "Disabled, built without OpenSubdiv"); + return; +#endif + + /* Subsurf does not require extra space mapping, keep matrices as is. */ + (void)deform_matrices; + + SubsurfModifierData *smd = (SubsurfModifierData *)md; + SubdivSettings subdiv_settings; + subdiv_settings_init(&subdiv_settings, smd); + if (subdiv_settings.level == 0) { + return; + } + BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh); + SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd); + Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh); + if (subdiv == NULL) { + /* Happens on bad topology, but also on empty input mesh. */ + return; + } + BKE_subdiv_deform_coarse_vertices(subdiv, mesh, vertex_cos, num_verts); + if (subdiv != runtime_data->subdiv) { + BKE_subdiv_free(subdiv); + } +} + ModifierTypeInfo modifierType_Subsurf = { /* name */ "Subdivision", /* structName */ "SubsurfModifierData", @@ -252,7 +287,7 @@ ModifierTypeInfo modifierType_Subsurf = { /* copyData */ copyData, /* deformVerts */ NULL, - /* deformMatrices */ NULL, + /* deformMatrices */ deformMatrices, /* deformVertsEM */ NULL, /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index 840914aa313..97e6bb9e804 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -125,7 +125,7 @@ static void deformVerts(ModifierData *md, } if (surmd->mesh) { - unsigned int numverts = 0, i = 0; + uint numverts = 0, i = 0; int init = 0; float *vec; MVert *x, *v; diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index b34688d27d6..de32b90a5e3 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -45,16 +45,16 @@ typedef struct SDefAdjacency { struct SDefAdjacency *next; - unsigned int index; + uint index; } SDefAdjacency; typedef struct SDefAdjacencyArray { SDefAdjacency *first; - unsigned int num; /* Careful, this is twice the number of polygons (avoids an extra loop) */ + uint num; /* Careful, this is twice the number of polygons (avoids an extra loop) */ } SDefAdjacencyArray; typedef struct SDefEdgePolys { - unsigned int polys[2], num; + uint polys[2], num; } SDefEdgePolys; typedef struct SDefBindCalcData { @@ -90,20 +90,20 @@ typedef struct SDefBindPoly { float point_edgemid_angles[2]; float corner_edgemid_angles[2]; float dominant_angle_weight; - unsigned int index; - unsigned int numverts; - unsigned int loopstart; - unsigned int edge_inds[2]; - unsigned int edge_vert_inds[2]; - unsigned int corner_ind; - unsigned int dominant_edge; + uint index; + uint numverts; + uint loopstart; + uint edge_inds[2]; + uint edge_vert_inds[2]; + uint corner_ind; + uint dominant_edge; bool inside; } SDefBindPoly; typedef struct SDefBindWeightData { SDefBindPoly *bind_polys; - unsigned int numpoly; - unsigned int numbinds; + uint numpoly; + uint numbinds; } SDefBindWeightData; typedef struct SDefDeformData { @@ -217,8 +217,8 @@ static void freeAdjacencyMap(SDefAdjacencyArray *const vert_edges, static int buildAdjacencyMap(const MPoly *poly, const MEdge *edge, const MLoop *const mloop, - const unsigned int numpoly, - const unsigned int numedges, + const uint numpoly, + const uint numedges, SDefAdjacencyArray *const vert_edges, SDefAdjacency *adj, SDefEdgePolys *const edge_polys) @@ -263,10 +263,10 @@ static int buildAdjacencyMap(const MPoly *poly, return MOD_SDEF_BIND_RESULT_SUCCESS; } -BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, +BLI_INLINE void sortPolyVertsEdge(uint *indices, const MLoop *const mloop, - const unsigned int edge, - const unsigned int num) + const uint edge, + const uint num) { bool found = false; @@ -287,10 +287,10 @@ BLI_INLINE void sortPolyVertsEdge(unsigned int *indices, } } -BLI_INLINE void sortPolyVertsTri(unsigned int *indices, +BLI_INLINE void sortPolyVertsTri(uint *indices, const MLoop *const mloop, - const unsigned int loopstart, - const unsigned int num) + const uint loopstart, + const uint num) { for (int i = loopstart; i < num; i++) { *indices = mloop[i].v; @@ -303,7 +303,7 @@ BLI_INLINE void sortPolyVertsTri(unsigned int *indices, } } -BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float point_co[3]) +BLI_INLINE uint nearestVert(SDefBindCalcData *const data, const float point_co[3]) { BVHTreeNearest nearest = { .dist_sq = FLT_MAX, @@ -315,7 +315,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po float t_point[3]; float max_dist = FLT_MAX; float dist; - unsigned int index = 0; + uint index = 0; mul_v3_m4v3(t_point, data->imat, point_co); @@ -346,7 +346,7 @@ BLI_INLINE unsigned int nearestVert(SDefBindCalcData *const data, const float po } } -BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr) +BLI_INLINE int isPolyValid(const float coords[][2], const uint nr) { float prev_co[2]; float curr_vec[2], prev_vec[2]; @@ -408,7 +408,7 @@ BLI_INLINE float computeAngularWeight(const float point_angle, const float edgem BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data, const float point_co[3]) { - const unsigned int nearest = nearestVert(data, point_co); + const uint nearest = nearestVert(data, point_co); const SDefAdjacency *const vert_edges = data->vert_edges[nearest].first; const SDefEdgePolys *const edge_polys = data->edge_polys; @@ -444,7 +444,7 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data, /* Loop over all adjacent edges, * and build the SDefBindPoly data for each poly adjacent to those. */ for (vedge = vert_edges; vedge; vedge = vedge->next) { - unsigned int edge_ind = vedge->index; + uint edge_ind = vedge->index; for (int i = 0; i < edge_polys[edge_ind].num; i++) { { @@ -603,8 +603,8 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data, SDefBindPoly *bpolys[2]; const SDefEdgePolys *epolys; float ang_weights[2]; - unsigned int edge_ind = vedge->index; - unsigned int edge_on_poly[2]; + uint edge_ind = vedge->index; + uint edge_on_poly[2]; epolys = &edge_polys[edge_ind]; @@ -981,9 +981,9 @@ static void bindVert(void *__restrict userdata, static bool surfacedeformBind(SurfaceDeformModifierData *smd, float (*vertexCos)[3], - unsigned int numverts, - unsigned int tnumpoly, - unsigned int tnumverts, + uint numverts, + uint tnumpoly, + uint tnumverts, Mesh *target) { BVHTreeFromMesh treeData = {NULL}; @@ -991,7 +991,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd, const MPoly *mpoly = target->mpoly; const MEdge *medge = target->medge; const MLoop *mloop = target->mloop; - unsigned int tnumedges = target->totedge; + uint tnumedges = target->totedge; int adj_result; SDefAdjacencyArray *vert_edges; SDefAdjacency *adj_array; @@ -1173,12 +1173,12 @@ static void deformVert(void *__restrict userdata, static void surfacedeformModifier_do(ModifierData *md, const ModifierEvalContext *ctx, float (*vertexCos)[3], - unsigned int numverts, + uint numverts, Object *ob) { SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md; Mesh *target; - unsigned int tnumverts, tnumpoly; + uint tnumverts, tnumpoly; /* Exit function if bind flag is not set (free bind data if any). */ if (!(smd->flags & MOD_SDEF_BIND)) { diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 1582c27960e..7fba7e864ae 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -65,7 +65,7 @@ static Mesh *triangulate_mesh(Mesh *mesh, BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL); - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks, mesh); BM_mesh_free(bm); if (keep_clnors) { diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 84ab8afa18a..31df8185dc1 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -109,11 +109,11 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd, /* verts are given the UV from the first face that uses them */ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) { - unsigned int fidx = mp->totloop - 1; + uint fidx = mp->totloop - 1; do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; + uint lidx = mp->loopstart + fidx; + uint vidx = mloop[lidx].v; if (!BLI_BITMAP_TEST(done, vidx)) { /* remap UVs from [0, 1] to [-1, 1] */ @@ -182,7 +182,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob, } else if (ob->type == OB_MESH) { if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL); + mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data); } else { /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index b31e0832123..9698e150850 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -225,19 +225,19 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, for (i = 0, mp = mpoly; i < numPolys; i++, mp++) { if (num_projectors == 1) { if (projectors[0].uci) { - unsigned int fidx = mp->totloop - 1; + uint fidx = mp->totloop - 1; do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; + uint lidx = mp->loopstart + fidx; + uint vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci); } while (fidx--); } else { /* apply transformed coords as UVs */ - unsigned int fidx = mp->totloop - 1; + uint fidx = mp->totloop - 1; do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; + uint lidx = mp->loopstart + fidx; + uint vidx = mloop[lidx].v; copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]); } while (fidx--); } @@ -268,18 +268,18 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, } if (best_projector->uci) { - unsigned int fidx = mp->totloop - 1; + uint fidx = mp->totloop - 1; do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; + uint lidx = mp->loopstart + fidx; + uint vidx = mloop[lidx].v; BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci); } while (fidx--); } else { - unsigned int fidx = mp->totloop - 1; + uint fidx = mp->totloop - 1; do { - unsigned int lidx = mp->loopstart + fidx; - unsigned int vidx = mloop[lidx].v; + uint lidx = mp->loopstart + fidx; + uint vidx = mloop[lidx].v; mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]); } while (fidx--); } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 95b15b4a924..7e23289433f 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -215,7 +215,7 @@ static void get_vert2ob_distance( { /* Vertex and ref object coordinates. */ float v_wco[3]; - unsigned int i = numVerts; + uint i = numVerts; while (i-- > 0) { /* Get world-coordinates of the vertex (constraints and anim included). */ @@ -241,7 +241,7 @@ static void do_map( Object *ob, float *weights, const int nidx, const float min_d, const float max_d, short mode) { const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */ - unsigned int i = nidx; + uint i = nidx; if (max_d == min_d) { while (i-- > 0) { weights[i] = (weights[i] >= max_d) ? 1.0f : 0.0f; /* "Step" behavior... */ diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 7af9ef6f5b6..3dd6e00c3a5 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -91,7 +91,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh * MAX2(ob->totcol - 1, 0), false); - result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 57a4ace997c..f618f964b22 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -206,9 +206,9 @@ set(SRC shader/nodes/node_shader_valToRgb.c shader/nodes/node_shader_value.c shader/nodes/node_shader_vectTransform.c - shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_vector_math.c + shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_info.c shader/nodes/node_shader_volume_principled.c diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 9caa76377fd..4bcd77496c1 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -32,6 +32,7 @@ #include "DNA_linestyle_types.h" #include "DNA_workspace_types.h" +#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -212,115 +213,6 @@ void register_node_tree_type_sh(void) /* GPU material from shader nodes */ -static void ntree_shader_link_builtin_normal(bNodeTree *ntree, - bNode *node_from, - bNodeSocket *socket_from, - bNode *displacement_node, - bNodeSocket *displacement_socket); - -static bNodeSocket *ntree_shader_node_find_input(bNode *node, const char *identifier); - -static bNode *ntree_group_output_node(bNodeTree *ntree); - -static bNode *ntree_shader_relink_output_from_group(bNodeTree *ntree, - bNode *group_node, - bNode *sh_output_node, - int target) -{ - int i; - bNodeTree *group_ntree = (bNodeTree *)group_node->id; - - int sock_len = BLI_listbase_count(&sh_output_node->inputs); - bNodeSocket **group_surface_sockets = BLI_array_alloca(group_surface_sockets, sock_len); - - /* Create output sockets to plug output connection to. */ - i = 0; - for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, i++) { - group_surface_sockets[i] = ntreeAddSocketInterface( - group_ntree, SOCK_OUT, sock->typeinfo->idname, sock->name); - } - - bNode *group_output_node = ntree_group_output_node(group_ntree); - - /* If no group output node is present, we need to create one. */ - if (group_output_node == NULL) { - group_output_node = nodeAddStaticNode(NULL, group_ntree, NODE_GROUP_OUTPUT); - } - - /* Need to update tree so all node instances nodes gets proper sockets. */ - node_group_update(ntree, group_node); - node_group_output_update(group_ntree, group_output_node); - ntreeUpdateTree(G.main, group_ntree); - - /* Remove other shader output nodes so that only the new one can be selected as active. */ - for (bNode *node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) { - ntreeFreeLocalNode(ntree, node); - } - } - - /* Create new shader output node outside the group. */ - bNode *new_output_node = nodeAddStaticNode(NULL, ntree, sh_output_node->type); - new_output_node->custom1 = target; - - i = 0; - for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, i++) { - if (sock->link != NULL) { - /* Link the shader output node incoming link to the group output sockets */ - bNodeSocket *group_output_node_surface_input_sock = nodeFindSocket( - group_output_node, SOCK_IN, group_surface_sockets[i]->identifier); - nodeAddLink(group_ntree, - sock->link->fromnode, - sock->link->fromsock, - group_output_node, - group_output_node_surface_input_sock); - - /* Link the group output sockets to the new shader output node. */ - bNodeSocket *group_node_surface_output = nodeFindSocket( - group_node, SOCK_OUT, group_surface_sockets[i]->identifier); - bNodeSocket *output_node_surface_input = ntree_shader_node_find_input(new_output_node, - sock->name); - - nodeAddLink(ntree, - group_node, - group_node_surface_output, - new_output_node, - output_node_surface_input); - } - } - - ntreeUpdateTree(G.main, group_ntree); - ntreeUpdateTree(G.main, ntree); - - return new_output_node; -} - -static bNode *ntree_shader_output_node_from_group(bNodeTree *ntree, int target) -{ - bNode *output_node = NULL; - - /* Search if node groups do not contain valid output nodes (recursively). */ - for (bNode *node = ntree->nodes.first; node; node = node->next) { - if (!ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - continue; - } - if (node->id != NULL) { - output_node = ntree_shader_output_node_from_group((bNodeTree *)node->id, target); - - if (output_node == NULL) { - output_node = ntreeShaderOutputNode((bNodeTree *)node->id, target); - } - - if (output_node != NULL) { - /* Output is inside this group node. Create relink to make the output outside the group. */ - output_node = ntree_shader_relink_output_from_group(ntree, node, output_node, target); - break; - } - } - } - return output_node; -} - /* Find an output node of the shader tree. * * NOTE: it will only return output which is NOT in the group, which isn't how @@ -368,28 +260,6 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) return output_node; } -/* Find the active output node of a group nodetree. - * - * Does not return the shading output node but the group output node. - */ -static bNode *ntree_group_output_node(bNodeTree *ntree) -{ - /* Make sure we only have single node tagged as output. */ - ntreeSetOutput(ntree); - - /* Find output node that matches type and target. If there are - * multiple, we prefer exact target match and active nodes. */ - bNode *output_node = NULL; - - for (bNode *node = ntree->nodes.first; node; node = node->next) { - if ((node->type == NODE_GROUP_OUTPUT) && (node->flag & NODE_DO_OUTPUT)) { - output_node = node; - } - } - - return output_node; -} - /* Find socket with a specified identifier. */ static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier) { @@ -520,6 +390,109 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree) } } +static void flatten_group_do(bNodeTree *ntree, bNode *gnode) +{ + bNodeLink *link, *linkn, *tlink; + bNode *node, *nextnode; + bNodeTree *ngroup; + LinkNode *group_interface_nodes = NULL; + + ngroup = (bNodeTree *)gnode->id; + + /* Add the nodes into the ntree */ + for (node = ngroup->nodes.first; node; node = nextnode) { + nextnode = node->next; + /* Remove interface nodes. + * This also removes remaining links to and from interface nodes. + * We must delay removal since sockets will reference this node. see: T52092 */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + BLI_linklist_prepend(&group_interface_nodes, node); + } + /* migrate node */ + BLI_remlink(&ngroup->nodes, node); + BLI_addtail(&ntree->nodes, node); + /* ensure unique node name in the node tree */ + /* This is very slow and it has no use for GPU nodetree. (see T70609) */ + // nodeUniqueName(ntree, node); + } + + /* Save first and last link to iterate over flattened group links. */ + bNodeLink *glinks_first = ntree->links.last; + + /* Add internal links to the ntree */ + for (link = ngroup->links.first; link; link = linkn) { + linkn = link->next; + BLI_remlink(&ngroup->links, link); + BLI_addtail(&ntree->links, link); + } + + bNodeLink *glinks_last = ntree->links.last; + + /* restore external links to and from the gnode */ + if (glinks_first != NULL) { + /* input links */ + for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + if (link->fromnode->type == NODE_GROUP_INPUT) { + const char *identifier = link->fromsock->identifier; + /* find external links to this input */ + for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); + } + } + } + } + /* Also iterate over the new links to cover passthrough links. */ + glinks_last = ntree->links.last; + /* output links */ + for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + if (tlink->fromnode == gnode) { + const char *identifier = tlink->fromsock->identifier; + /* find internal links to this output */ + for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + /* only use active output node */ + if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) { + if (STREQ(link->tosock->identifier, identifier)) { + nodeAddLink(ntree, link->fromnode, link->fromsock, tlink->tonode, tlink->tosock); + } + } + } + } + } + } + + while (group_interface_nodes) { + node = BLI_linklist_pop(&group_interface_nodes); + ntreeFreeLocalNode(ntree, node); + } + + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; +} + +/* Flatten group to only have a simple single tree */ +static void ntree_shader_groups_flatten(bNodeTree *localtree) +{ + /* This is effectively recursive as the flattened groups will add + * nodes at the end of the list, which will also get evaluated. */ + for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) { + if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) { + flatten_group_do(localtree, node); + /* Continue even on new flattened nodes. */ + node_next = node->next; + /* delete the group instance and its localtree. */ + bNodeTree *ngroup = (bNodeTree *)node->id; + ntreeFreeLocalNode(localtree, node); + ntreeFreeTree(ngroup); + MEM_freeN(ngroup); + } + else { + node_next = node->next; + } + } + + ntreeUpdateTree(G.main, localtree); +} + /* Check whether shader has a displacement. * * Will also return a node and it's socket which is connected to a displacement @@ -576,53 +549,10 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree, } } -static void ntree_shader_link_builtin_group_normal(bNodeTree *ntree, - bNode *group_node, - bNode *node_from, - bNodeSocket *socket_from, - bNode *displacement_node, - bNodeSocket *displacement_socket) -{ - bNodeTree *group_ntree = (bNodeTree *)group_node->id; - /* Create input socket to plug displacement connection to. */ - bNodeSocket *group_normal_socket = ntreeAddSocketInterface( - group_ntree, SOCK_IN, "NodeSocketVector", "Normal"); - /* Need to update tree so all node instances nodes gets proper sockets. */ - bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); - node_group_update(ntree, group_node); - if (group_input_node) { - node_group_input_update(group_ntree, group_input_node); - } - ntreeUpdateTree(G.main, group_ntree); - /* Assumes sockets are always added at the end. */ - bNodeSocket *group_node_normal_socket = group_node->inputs.last; - if (displacement_node == group_node) { - /* This should never happen as all displacement nodes are duplicated and tagged. */ - BLI_assert(0); - } - else if (group_input_node) { - /* Connect group node normal input. */ - nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket); - BLI_assert(group_input_node != NULL); - bNodeSocket *group_input_node_normal_socket = nodeFindSocket( - group_input_node, SOCK_OUT, group_normal_socket->identifier); - BLI_assert(group_input_node_normal_socket != NULL); - /* Relink normals inside of the instanced tree. */ - ntree_shader_link_builtin_normal(group_ntree, - group_input_node, - group_input_node_normal_socket, - displacement_node, - displacement_socket); - ntreeUpdateTree(G.main, group_ntree); - } -} - /* Use specified node and socket as an input for unconnected normal sockets. */ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, bNode *node_from, - bNodeSocket *socket_from, - bNode *displacement_node, - bNodeSocket *displacement_socket) + bNodeSocket *socket_from) { for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) { if (node == node_from) { @@ -633,16 +563,6 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, /* This node is used inside the displacement tree. Skip to avoid cycles. */ continue; } - if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) { - /* Special re-linking for group nodes. */ - ntree_shader_link_builtin_group_normal( - ntree, node, node_from, socket_from, displacement_node, displacement_socket); - continue; - } - if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { - /* Group inputs and outputs needs nothing special. */ - continue; - } ntree_shader_relink_node_normal(ntree, node, node_from, socket_from); } } @@ -670,36 +590,17 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree) { /* Bypass bump links inside copied nodes */ - bNodeLink *link, *link_next; - for (link = ntree->links.first; link; link = link_next) { - /* link might be freed by ntree_shader_bypass_bump_link. */ - link_next = link->next; + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { bNode *node = link->fromnode; /* If node is a copy. */ if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) { ntree_shader_bypass_bump_link(ntree, node, link); } } - /* Do the same inside nodegroups. */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - /* If node is a copy. */ - if (node->tmp_flag == -2 && ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) { - bNodeTree *group_ntree = (bNodeTree *)node->id; - /* Tag all nodes inside this group as copies. */ - LISTBASE_FOREACH (bNode *, group_node, &group_ntree->nodes) { - group_node->tmp_flag = -2; - } - /* Recursive. */ - ntree_shader_bypass_tagged_bump_nodes(group_ntree); - } - } ntreeUpdateTree(G.main, ntree); } -static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, - bNode *tonode, - void *userdata, - const bool UNUSED(reversed)) +static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata) { int *node_count = (int *)userdata; if (fromnode->tmp_flag == -1) { @@ -728,7 +629,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, /* Count and tag all nodes inside the displacement branch of the tree. */ start_node->tmp_flag = 0; int node_count = 1; - nodeChainIter(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, true); + nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1); /* Make a full copy of the branch */ bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -736,9 +637,6 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, int id = node->tmp_flag; nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT); nodes_copy[id]->tmp_flag = -2; /* Copy */ - if (ELEM(nodes_copy[id]->type, NODE_GROUP, NODE_CUSTOM_GROUP) && nodes_copy[id]->id) { - nodes_copy[id]->id = (ID *)ntreeLocalize((bNodeTree *)nodes_copy[id]->id); - } /* Make sure to clear all sockets links as they are invalid. */ LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) { sock->link = NULL; @@ -850,8 +748,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod ntreeUpdateTree(G.main, ntree); /* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */ - ntree_shader_link_builtin_normal( - ntree, bump_node, bump_output_socket, displacement_node, displacement_socket); + ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket); /* We modified the tree, it needs to be updated now. */ ntreeUpdateTree(G.main, ntree); } @@ -866,16 +763,13 @@ static void node_tag_branch_as_derivative(bNode *node, int dx) } } -static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), - bNode *tonode, - void *userdata, - const bool UNUSED(reversed)) +static bool ntree_shader_bump_branches(bNode *fromnode, bNode *UNUSED(tonode), void *userdata) { bNodeTree *ntree = (bNodeTree *)userdata; - if (tonode->type == SH_NODE_BUMP) { + if (fromnode->type == SH_NODE_BUMP) { bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket; - bNode *bump = tonode; + bNode *bump = fromnode; bump_socket = ntree_shader_node_find_input(bump, "Height"); bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx"); bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy"); @@ -897,27 +791,9 @@ static bool ntree_shader_bump_branches(bNode *UNUSED(fromnode), return true; } -static bool ntree_tag_bsdf_cb(bNode *fromnode, - bNode *UNUSED(tonode), - void *userdata, - const bool UNUSED(reversed)) +static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata) { - /* Don't evaluate nodes more than once. */ - if (fromnode->tmp_flag) { - return true; - } - fromnode->tmp_flag = 1; - switch (fromnode->type) { - case NODE_GROUP: - case NODE_CUSTOM_GROUP: - /* Recursive */ - if (fromnode->id != NULL) { - bNodeTree *ntree = (bNodeTree *)fromnode->id; - bNode *group_output = ntree_group_output_node(ntree); - ntree_shader_tag_nodes(ntree, group_output, (nTreeTags *)userdata); - } - break; case SH_NODE_BSDF_ANISOTROPIC: case SH_NODE_EEVEE_SPECULAR: case SH_NODE_BSDF_GLOSSY: @@ -956,12 +832,7 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag /* Make sure sockets links pointers are correct. */ ntreeUpdateTree(G.main, ntree); - /* Reset visit flag. */ - for (bNode *node = ntree->nodes.first; node; node = node->next) { - node->tmp_flag = 0; - } - - nodeChainIter(ntree, output_node, ntree_tag_bsdf_cb, tags, true); + nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0); } /* This one needs to work on a local tree. */ @@ -972,13 +843,17 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, { bNodeTreeExec *exec; - /* Extract output nodes from inside nodegroups. */ - ntree_shader_output_node_from_group(localtree, SHD_OUTPUT_EEVEE); - bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); ntree_shader_groups_expand_inputs(localtree); + ntree_shader_groups_flatten(localtree); + + if (output == NULL) { + /* Search again, now including flattened nodes. */ + output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + } + /* Perform all needed modifications on the tree in order to support * displacement/bump mapping. */ @@ -986,7 +861,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, /* Duplicate bump height branches for manual derivatives. */ - nodeChainIter(localtree, output, ntree_shader_bump_branches, localtree, true); + nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0); /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */ nTreeTags tags = { diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c index c92ae28f2e6..ecb8c53c312 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.c +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c @@ -67,7 +67,14 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, } else { GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name); - return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); + GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr); + + /* for each output. */ + for (int i = 0; sh_node_attribute_out[i].type != -1; i++) { + node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + } + + return 1; } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index 595ddf27d0a..3340054396d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -120,6 +120,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[20].link); } +#if 0 /* Not used at the moment. */ /* Tangents */ if (!in[21].link) { GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); @@ -131,6 +132,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, GPU_builtin(GPU_OBJECT_MATRIX), &in[21].link); } +#endif bool use_diffuse = socket_not_one(4) && socket_not_one(15); bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0; diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c index df9a8ac8318..3798cfbbfac 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c @@ -41,21 +41,38 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, { /* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will * trigger the use of geometry shader (and the performance penalty it implies). */ - float val[2] = {0.0f, 0.0f}; + float val[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) : GPU_builtin(GPU_BARYCENTRIC_TEXCO); + /* Opti: don't request orco if not needed. */ + GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) : GPU_attribute(CD_ORCO, ""); - return GPU_stack_link(mat, - node, - "node_geometry", - in, - out, - GPU_builtin(GPU_VIEW_POSITION), - GPU_builtin(GPU_WORLD_NORMAL), - GPU_attribute(CD_ORCO, ""), - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - bary_link); + const bool success = GPU_stack_link(mat, + node, + "node_geometry", + in, + out, + GPU_builtin(GPU_VIEW_POSITION), + GPU_builtin(GPU_WORLD_NORMAL), + orco_link, + GPU_builtin(GPU_OBJECT_MATRIX), + GPU_builtin(GPU_INVERSE_VIEW_MATRIX), + bary_link); + + /* for each output */ + for (int i = 0; sh_node_geometry_out[i].type != -1; i++) { + node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + /* Normalize some vectors after dFdx/dFdy offsets. + * This is the case for interpolated, non linear functions. + * The resulting vector can still be a bit wrong but not as much. + * (see T70644) */ + if (node->branch_tag != 0 && ELEM(i, 1, 2, 4)) { + GPU_link( + mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL); + } + } + + return success; } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c index 9a0a132b311..9f93dfd837b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c @@ -61,8 +61,6 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[5].link); } - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS); - if (node->sss_id > 0) { bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2); bNodeSocketValueRGBA *socket_data = socket->default_value; @@ -71,6 +69,10 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, /* For some reason it seems that the socket value is in ARGB format. */ GPU_material_sss_profile_create( mat, &socket_data->value[1], &node->original->custom1, &socket_data_sharp->value); + + /* sss_id is 0 only the node is not connected to any output. + * In this case flagging the material would trigger a bug (see T68736). */ + GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS); } return GPU_stack_link( diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index 637aeb3c182..8bb17acc4d3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -45,14 +45,17 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) : GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); - /* TODO only request orco if needed. */ - GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); + /* Opti: don't request orco if not needed. */ + GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) : + GPU_attribute(CD_ORCO, ""); GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ""); GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION); GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL); GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS); - GPU_link(mat, "generated_from_orco", orco, &orco); + if (out[0].hasoutput) { + GPU_link(mat, "generated_from_orco", orco, &orco); + } GPU_stack_link( mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface); @@ -60,6 +63,14 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, /* for each output. */ for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) { node_shader_gpu_bump_tex_coord(mat, node, &out[i].link); + /* Normalize some vectors after dFdx/dFdy offsets. + * This is the case for interpolated, non linear functions. + * The resulting vector can still be a bit wrong but not as much. + * (see T70644) */ + if (node->branch_tag != 0 && ELEM(i, 1, 6)) { + GPU_link( + mat, "vector_math_normalize", out[i].link, out[i].link, out[i].link, &out[i].link, NULL); + } } return 1; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c index daf4053f182..56e102a118d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c @@ -136,8 +136,8 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && tex->musgrave_type != SHD_MUSGRAVE_FBM); nodeSetSocketAvailability(inGainSock, - tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL && - tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); + tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || + tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); } void register_node_type_sh_tex_musgrave(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c index 73fb022e476..a2e47735490 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c @@ -43,7 +43,11 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, NodeShaderUVMap *attr = node->storage; GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map); - return GPU_stack_link(mat, node, "node_uvmap", in, out, mtface); + GPU_stack_link(mat, node, "node_uvmap", in, out, mtface); + + node_shader_gpu_bump_tex_coord(mat, node, &out[0].link); + + return 1; } /* node type definition */ diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c index fd37c8521c1..b6ba119f695 100644 --- a/source/blender/python/bmesh/bmesh_py_ops.c +++ b/source/blender/python/bmesh/bmesh_py_ops.c @@ -166,10 +166,10 @@ static PyTypeObject bmesh_op_Type = { sizeof(BPy_BMeshOpFunc), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ (reprfunc)bpy_bmesh_op_repr, /* tp_repr */ @@ -282,10 +282,10 @@ static PyTypeObject bmesh_ops_fakemod_Type = { 0, /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ NULL, /* tp_repr */ diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 23be0d68fb0..1b6466dee68 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -1366,6 +1366,7 @@ BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP)); BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint)); BGL_Wrap(IsVertexArray, GLboolean, (GLuint)); BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei)); +BGL_Wrap(VertexAttribIPointer, void, (GLuint, GLint, GLenum, GLsizei, GLvoidP)); /* GL_VERSION_3_1 */ BGL_Wrap(BindBufferBase, void, (GLenum, GLuint, GLuint)); @@ -1709,6 +1710,7 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(GetStringi); PY_MOD_ADD_METHOD(IsVertexArray); PY_MOD_ADD_METHOD(RenderbufferStorage); + PY_MOD_ADD_METHOD(VertexAttribIPointer); } /* GL_VERSION_3_1 */ diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index b90483e89b9..62f5a568ee1 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -20,6 +20,9 @@ * This file defines the 'bgl' module, used for drawing text in OpenGL. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "blf_py_api.h" @@ -176,7 +179,7 @@ PyDoc_STRVAR(py_blf_draw_doc, static PyObject *py_blf_draw(PyObject *UNUSED(self), PyObject *args) { const char *text; - int text_length; + Py_ssize_t text_length; int fontid; if (!PyArg_ParseTuple(args, "is#:blf.draw", &fontid, &text, &text_length)) { diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index d10d281c1f9..1ea7795a0e3 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -688,6 +688,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, /* Preserve prev/next links!!! See T42593. */ prop->prev = prop_exist->prev; prop->next = prop_exist->next; + prop->flag = prop_exist->flag; IDP_FreePropertyContent(prop_exist); *prop_exist = *prop; @@ -896,7 +897,7 @@ static PyObject *BPy_IDGroup_pop(BPy_IDProperty *self, PyObject *args) pyform = BPy_IDGroup_MapDataToPy(idprop); if (pyform == NULL) { - /* ok something bad happened with the pyobject, + /* ok something bad happened with the #PyObject, * so don't remove the prop from the group. if pyform is * NULL, then it already should have raised an exception.*/ return NULL; @@ -1171,7 +1172,7 @@ PyTypeObject BPy_IDGroup_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ @@ -1576,7 +1577,7 @@ PyTypeObject BPy_IDArray_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ @@ -1691,7 +1692,7 @@ PyTypeObject BPy_IDGroup_Iter_Type = { /* Methods to implement standard operations */ NULL, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index 22be0429ea5..d35fc027f43 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -88,21 +88,37 @@ PyDoc_STRVAR(py_imbuf_resize_doc, "\n" " :arg size: New size.\n" " :type size: pair of ints\n" - " :arg method: Method of resizing (TODO)\n" + " :arg method: Method of resizing ('FAST', 'BILINEAR')\n" " :type method: str\n"); static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw) { PY_IMBUF_CHECK_OBJ(self); uint size[2]; - char *method = NULL; + + enum { FAST, BILINEAR }; + const struct PyC_StringEnumItems method_items[] = { + {FAST, "FAST"}, + {BILINEAR, "BILINEAR"}, + {0, NULL}, + }; + struct PyC_StringEnum method = {method_items, FAST}; static const char *_keywords[] = {"size", "method", NULL}; - static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &size[0], &size[1], &method)) { + static _PyArg_Parser _parser = {"(II)|O&:resize", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &size[0], &size[1], PyC_ParseStringEnum, &method)) { return NULL; } - IMB_scaleImBuf(self->ibuf, UNPACK2(size)); + if (method.value_found == FAST) { + IMB_scalefastImBuf(self->ibuf, UNPACK2(size)); + } + else if (method.value_found == BILINEAR) { + IMB_scaleImBuf(self->ibuf, UNPACK2(size)); + } + else { + BLI_assert(0); + } Py_RETURN_NONE; } @@ -227,6 +243,51 @@ static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closur return 0; } +PyDoc_STRVAR(py_imbuf_filepath_doc, "filepath associated with this image.\n\n:type: string"); +static PyObject *py_imbuf_filepath_get(Py_ImBuf *self, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_OBJ(self); + ImBuf *ibuf = self->ibuf; + return PyC_UnicodeFromByte(ibuf->name); +} + +static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_INT(self); + + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, "expected a string!"); + return -1; + } + + ImBuf *ibuf = self->ibuf; + Py_ssize_t value_str_len_max = sizeof(ibuf->name); + Py_ssize_t value_str_len; + const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len); + if (value_str_len >= value_str_len_max) { + PyErr_Format(PyExc_TypeError, "filepath length over %zd", value_str_len_max - 1); + return -1; + } + memcpy(ibuf->name, value_str, value_str_len + 1); + return 0; +} + +PyDoc_STRVAR(py_imbuf_planes_doc, "Number of bits associated with this image.\n\n:type: int"); +static PyObject *py_imbuf_planes_get(Py_ImBuf *self, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_OBJ(self); + ImBuf *imbuf = self->ibuf; + return PyLong_FromLong(imbuf->planes); +} + +PyDoc_STRVAR(py_imbuf_channels_doc, "Number of bit-planes.\n\n:type: int"); +static PyObject *py_imbuf_channels_get(Py_ImBuf *self, void *UNUSED(closure)) +{ + PY_IMBUF_CHECK_OBJ(self); + ImBuf *imbuf = self->ibuf; + return PyLong_FromLong(imbuf->channels); +} + static PyGetSetDef Py_ImBuf_getseters[] = { {(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL}, {(char *)"ppm", @@ -234,6 +295,13 @@ static PyGetSetDef Py_ImBuf_getseters[] = { (setter)py_imbuf_ppm_set, (char *)py_imbuf_ppm_doc, NULL}, + {(char *)"filepath", + (getter)py_imbuf_filepath_get, + (setter)py_imbuf_filepath_set, + (char *)py_imbuf_filepath_doc, + NULL}, + {(char *)"planes", (getter)py_imbuf_planes_get, NULL, (char *)py_imbuf_planes_doc, NULL}, + {(char *)"channels", (getter)py_imbuf_channels_get, NULL, (char *)py_imbuf_channels_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; @@ -258,7 +326,7 @@ static PyObject *py_imbuf_repr(Py_ImBuf *self) const ImBuf *ibuf = self->ibuf; if (ibuf != NULL) { return PyUnicode_FromFormat( - "<imbuf: address=%p, filename='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y); + "<imbuf: address=%p, filepath='%s', size=(%d, %d)>", ibuf, ibuf->name, ibuf->x, ibuf->y); } else { return PyUnicode_FromString("<imbuf: address=0x0>"); @@ -280,7 +348,7 @@ PyTypeObject Py_ImBuf_Type = { /* Methods to implement standard operations */ (destructor)py_imbuf_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ @@ -375,73 +443,73 @@ static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *k } PyDoc_STRVAR(M_imbuf_load_doc, - ".. function:: load(filename)\n" + ".. function:: load(filepath)\n" "\n" " Load an image from a file.\n" "\n" - " :arg filename: the filename of the image.\n" - " :type filename: string\n" + " :arg filepath: the filepath of the image.\n" + " :type filepath: string\n" " :return: the newly loaded image.\n" " :rtype: :class:`ImBuf`\n"); static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - const char *filename; + const char *filepath; - static const char *_keywords[] = {"filename", NULL}; + static const char *_keywords[] = {"filepath", NULL}; static _PyArg_Parser _parser = {"s:load", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filename)) { + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) { return NULL; } - const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0); + const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0); if (file == -1) { - PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno)); + PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno), filepath); return NULL; } - ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename); + ImBuf *ibuf = IMB_loadifffile(file, filepath, IB_rect, NULL, filepath); close(file); if (ibuf == NULL) { PyErr_Format( - PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename); + PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filepath); return NULL; } - BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name)); + BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); return Py_ImBuf_CreatePyObject(ibuf); } PyDoc_STRVAR(M_imbuf_write_doc, - ".. function:: write(image, filename)\n" + ".. function:: write(image, filepath)\n" "\n" " Write an image.\n" "\n" " :arg image: the image to write.\n" " :type image: :class:`ImBuf`\n" - " :arg filename: the filename of the image.\n" - " :type filename: string\n"); + " :arg filepath: the filepath of the image.\n" + " :type filepath: string\n"); static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { Py_ImBuf *py_imb; - const char *filename = NULL; + const char *filepath = NULL; - static const char *_keywords[] = {"image", "filename", NULL}; + static const char *_keywords[] = {"image", "filepath", NULL}; static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filename)) { + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &Py_ImBuf_Type, &py_imb, &filepath)) { return NULL; } - if (filename == NULL) { - filename = py_imb->ibuf->name; + if (filepath == NULL) { + filepath = py_imb->ibuf->name; } - bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect); + bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect); if (ok == false) { PyErr_Format( - PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename); + PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath); return NULL; } diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index ca9f15ed01a..c4a363e25e5 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -25,6 +25,9 @@ * BLI_string_utf8() for unicode conversion. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include <frameobject.h> @@ -231,6 +234,37 @@ int PyC_ParseBool(PyObject *o, void *p) return 1; } +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +int PyC_ParseStringEnum(PyObject *o, void *p) +{ + struct PyC_StringEnum *e = p; + const char *value = _PyUnicode_AsString(o); + if (value == NULL) { + PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name); + return 0; + } + int i; + for (i = 0; e->items[i].id; i++) { + if (STREQ(e->items[i].id, value)) { + e->value_found = e->items[i].value; + return 1; + } + } + + /* Set as a precaution. */ + e->value_found = -1; + + PyObject *enum_items = PyTuple_New(i); + for (i = 0; e->items[i].id; i++) { + PyTuple_SET_ITEM(enum_items, i, PyUnicode_FromString(e->items[i].id)); + } + PyErr_Format(PyExc_ValueError, "expected a string in %S, got '%s'", enum_items, value); + Py_DECREF(enum_items); + return 0; +} + /* silly function, we dont use arg. just check its compatible with __deepcopy__ */ int PyC_CheckArgs_DeepCopy(PyObject *args) { @@ -717,9 +751,10 @@ PyObject *PyC_UnicodeFromByte(const char *str) ****************************************************************************/ PyObject *PyC_DefaultNameSpace(const char *filename) { - PyInterpreterState *interp = PyThreadState_GET()->interp; + PyObject *modules = PyImport_GetModuleDict(); + PyObject *builtins = PyEval_GetBuiltins(); PyObject *mod_main = PyModule_New("__main__"); - PyDict_SetItemString(interp->modules, "__main__", mod_main); + PyDict_SetItemString(modules, "__main__", mod_main); Py_DECREF(mod_main); /* sys.modules owns now */ PyModule_AddStringConstant(mod_main, "__name__", "__main__"); if (filename) { @@ -727,8 +762,8 @@ PyObject *PyC_DefaultNameSpace(const char *filename) * note: this wont map to a real file when executing text-blocks and buttons. */ PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename)); } - PyModule_AddObject(mod_main, "__builtins__", interp->builtins); - Py_INCREF(interp->builtins); /* AddObject steals a reference */ + PyModule_AddObject(mod_main, "__builtins__", builtins); + Py_INCREF(builtins); /* AddObject steals a reference */ return PyModule_GetDict(mod_main); } @@ -755,15 +790,15 @@ bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]) /* restore MUST be called after this */ void PyC_MainModule_Backup(PyObject **main_mod) { - PyInterpreterState *interp = PyThreadState_GET()->interp; - *main_mod = PyDict_GetItemString(interp->modules, "__main__"); + PyObject *modules = PyImport_GetModuleDict(); + *main_mod = PyDict_GetItemString(modules, "__main__"); Py_XINCREF(*main_mod); /* don't free */ } void PyC_MainModule_Restore(PyObject *main_mod) { - PyInterpreterState *interp = PyThreadState_GET()->interp; - PyDict_SetItemString(interp->modules, "__main__", main_mod); + PyObject *modules = PyImport_GetModuleDict(); + PyDict_SetItemString(modules, "__main__", main_mod); Py_XDECREF(main_mod); } @@ -836,7 +871,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) va_list vargs; - int *sizes = PyMem_MALLOC(sizeof(int) * (n / 2)); + Py_ssize_t *sizes = PyMem_MALLOC(sizeof(*sizes) * (n / 2)); int i; PyObject *py_dict = PyC_DefaultNameSpace(filepath); diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 4454aa11d77..1f552c3d78d 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -126,6 +126,17 @@ bool PyC_RunString_AsString(const char **imports, int PyC_ParseBool(PyObject *o, void *p); +struct PyC_StringEnumItems { + int value; + const char *id; +}; +struct PyC_StringEnum { + const struct PyC_StringEnumItems *items; + int value_found; +}; + +int PyC_ParseStringEnum(PyObject *o, void *p); + int PyC_CheckArgs_DeepCopy(PyObject *args); /* Integer parsing (with overflow checks), -1 on error. */ diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 70f76896898..6505e59624b 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -183,7 +183,7 @@ static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyDoc_STRVAR( bpygpu_offscreen_draw_view3d_doc, - ".. method:: draw_view3d(scene, view3d, region, view_matrix, projection_matrix)\n" + ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n" "\n" " Draw the 3d viewport in the offscreen object.\n" "\n" diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 8c34699b598..52b35478dd0 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -147,39 +147,28 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec // PyDoc_STRVAR(bpy_user_resource_doc[] = // now in bpy/utils.py static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - const char *type; + const struct PyC_StringEnumItems type_items[] = { + {BLENDER_USER_DATAFILES, "DATAFILES"}, + {BLENDER_USER_CONFIG, "CONFIG"}, + {BLENDER_USER_SCRIPTS, "SCRIPTS"}, + {BLENDER_USER_AUTOSAVE, "AUTOSAVE"}, + {0, NULL}, + }; + struct PyC_StringEnum type = {type_items}; + const char *subdir = NULL; - int folder_id; const char *path; static const char *_keywords[] = {"type", "subdir", NULL}; - static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) { - return NULL; - } - - /* stupid string compare */ - if (STREQ(type, "DATAFILES")) { - folder_id = BLENDER_USER_DATAFILES; - } - else if (STREQ(type, "CONFIG")) { - folder_id = BLENDER_USER_CONFIG; - } - else if (STREQ(type, "SCRIPTS")) { - folder_id = BLENDER_USER_SCRIPTS; - } - else if (STREQ(type, "AUTOSAVE")) { - folder_id = BLENDER_USER_AUTOSAVE; - } - else { - PyErr_SetString(PyExc_ValueError, "invalid resource argument"); + static _PyArg_Parser _parser = {"O&|s:user_resource", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) { return NULL; } /* same logic as BKE_appdir_folder_id_create(), * but best leave it up to the script author to create */ - path = BKE_appdir_folder_id_user_notest(folder_id, subdir); + path = BKE_appdir_folder_id_user_notest(type.value_found, subdir); return PyC_UnicodeFromByte(path ? path : ""); } @@ -195,34 +184,25 @@ PyDoc_STRVAR(bpy_system_resource_doc, " :type path: string\n"); static PyObject *bpy_system_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - const char *type; + const struct PyC_StringEnumItems type_items[] = { + {BLENDER_SYSTEM_DATAFILES, "DATAFILES"}, + {BLENDER_SYSTEM_SCRIPTS, "SCRIPTS"}, + {BLENDER_SYSTEM_PYTHON, "PYTHON"}, + {0, NULL}, + }; + struct PyC_StringEnum type = {type_items}; + const char *subdir = NULL; - int folder_id; const char *path; static const char *_keywords[] = {"type", "path", NULL}; - static _PyArg_Parser _parser = {"s|s:system_resource", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &subdir)) { + static _PyArg_Parser _parser = {"O&|s:system_resource", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, PyC_ParseStringEnum, &type, &subdir)) { return NULL; } - /* stupid string compare */ - if (STREQ(type, "DATAFILES")) { - folder_id = BLENDER_SYSTEM_DATAFILES; - } - else if (STREQ(type, "SCRIPTS")) { - folder_id = BLENDER_SYSTEM_SCRIPTS; - } - else if (STREQ(type, "PYTHON")) { - folder_id = BLENDER_SYSTEM_PYTHON; - } - else { - PyErr_SetString(PyExc_ValueError, "invalid resource argument"); - return NULL; - } - - path = BKE_appdir_folder_id(folder_id, subdir); + path = BKE_appdir_folder_id(type.value_found, subdir); return PyC_UnicodeFromByte(path ? path : ""); } @@ -243,33 +223,25 @@ PyDoc_STRVAR( " :rtype: string\n"); static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - const char *type; + const struct PyC_StringEnumItems type_items[] = { + {BLENDER_RESOURCE_PATH_USER, "USER"}, + {BLENDER_RESOURCE_PATH_LOCAL, "LOCAL"}, + {BLENDER_RESOURCE_PATH_SYSTEM, "SYSTEM"}, + {0, NULL}, + }; + struct PyC_StringEnum type = {type_items}; + int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100; - int folder_id; const char *path; static const char *_keywords[] = {"type", "major", "minor", NULL}; - static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &type, &major, &minor)) { - return NULL; - } - - /* stupid string compare */ - if (STREQ(type, "USER")) { - folder_id = BLENDER_RESOURCE_PATH_USER; - } - else if (STREQ(type, "LOCAL")) { - folder_id = BLENDER_RESOURCE_PATH_LOCAL; - } - else if (STREQ(type, "SYSTEM")) { - folder_id = BLENDER_RESOURCE_PATH_SYSTEM; - } - else { - PyErr_SetString(PyExc_ValueError, "invalid resource argument"); + static _PyArg_Parser _parser = {"O&|ii:resource_path", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, PyC_ParseStringEnum, &type, &major, &minor)) { return NULL; } - path = BKE_appdir_folder_id_version(folder_id, (major * 100) + minor, false); + path = BKE_appdir_folder_id_version(type.value_found, (major * 100) + minor, false); return PyC_UnicodeFromByte(path ? path : ""); } diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index 3c1dbfba72e..fffa43c1dcd 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -780,10 +780,10 @@ static PyTypeObject BlenderAppTranslationsType = { 0, /* tp_itemsize */ /* methods */ /* No destructor, this is a singleton! */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ NULL, /* tp_repr */ diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 5ea16c8c197..b797624f23c 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -92,7 +92,7 @@ static PyTypeObject bpy_lib_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)bpy_lib_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 6b63d1ef2c3..4fd81a707fb 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -22,6 +22,9 @@ * existing blender types. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "RNA_types.h" @@ -2101,7 +2104,7 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; bool def = false; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -2204,7 +2207,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; bool def[PYRNA_STACK_ARRAY] = {0}; int size = 3; PropertyRNA *prop; @@ -2336,7 +2339,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -2456,7 +2459,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1; int def[PYRNA_STACK_ARRAY] = {0}; int size = 3; @@ -2599,7 +2602,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, def = 0.0f; int precision = 2; @@ -2735,7 +2738,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3; float def[PYRNA_STACK_ARRAY] = {0.0f}; int precision = 2, size = 3; @@ -2869,7 +2872,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw if (srna) { const char *id = NULL, *name = NULL, *description = "", *def = ""; - int id_len; + Py_ssize_t id_len; int maxlen = 0; PropertyRNA *prop; PyObject *pyopts = NULL; @@ -3015,7 +3018,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; PyObject *def = NULL; - int id_len; + Py_ssize_t id_len; int defvalue = 0; PyObject *items, *items_fast; const EnumPropertyItem *eitems; @@ -3191,7 +3194,7 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) if (srna) { const char *id = NULL, *name = NULL, *description = ""; - int id_len; + Py_ssize_t id_len; PropertyRNA *prop; StructRNA *ptype; PyObject *type = Py_None; @@ -3286,7 +3289,7 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(CollectionProperty); if (srna) { - int id_len; + Py_ssize_t id_len; const char *id = NULL, *name = NULL, *description = ""; PropertyRNA *prop; StructRNA *ptype; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c5424ca6ffb..570c5012ed8 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -70,6 +70,8 @@ /* Only for types. */ #include "BKE_node.h" +#include "DEG_depsgraph_query.h" + #include "../generic/idprop_py_api.h" /* For IDprop lookups. */ #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" @@ -918,7 +920,10 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) tmp_str = PyUnicode_FromString(id->name + 2); - if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { + if (DEG_get_original_id(id) != id) { + ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str); + } + else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { ret = PyUnicode_FromFormat( "bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str); } @@ -926,14 +931,25 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) const char *path; ID *real_id = NULL; path = RNA_path_from_real_ID_to_struct(G_MAIN, &self->ptr, &real_id); - if (path) { - if (real_id != id) { + if (path != NULL) { + /* 'real_id' may be NULL in some cases, although the only valid one is evaluated data, + * which should have already been caught above. + * So assert, but handle it without crashing for release builds. */ + BLI_assert(real_id != NULL); + + if (real_id != NULL) { Py_DECREF(tmp_str); tmp_str = PyUnicode_FromString(real_id->name + 2); + ret = PyUnicode_FromFormat( + "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path); + } + else { + /* Can't find the path, print something useful as a fallback. */ + ret = PyUnicode_FromFormat("bpy.data.%s[%R]...%s", + BKE_idcode_to_name_plural(GS(id->name)), + tmp_str, + RNA_struct_identifier(self->ptr.type)); } - ret = PyUnicode_FromFormat( - "bpy.data.%s[%R].%s", BKE_idcode_to_name_plural(GS(real_id->name)), tmp_str, path); - MEM_freeN((void *)path); } else { @@ -1928,7 +1944,7 @@ static int pyrna_py_to_prop( * layout.prop(self.properties, "filepath") * * we need to do this trick. - * if the prop is not an operator type and the pyobject is an operator, + * if the prop is not an operator type and the PyObject is an operator, * use its properties in place of itself. * * This is so bad that it is almost a good reason to do away with fake @@ -3710,9 +3726,9 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject PyDoc_STRVAR(pyrna_struct_is_property_overridable_library_doc, ".. method:: is_property_overridable_library(property)\n" "\n" - " Check if a property is statically overridable.\n" + " Check if a property is overridable.\n" "\n" - " :return: True when the property is statically overridable.\n" + " :return: True when the property is overridable.\n" " :rtype: boolean\n"); static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *self, PyObject *args) { @@ -3736,14 +3752,13 @@ static PyObject *pyrna_struct_is_property_overridable_library(BPy_StructRNA *sel return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop)); } -PyDoc_STRVAR( - pyrna_struct_property_overridable_library_set_doc, - ".. method:: property_overridable_library_set(property)\n" - "\n" - " Define a property as statically overridable or not (only for custom properties!).\n" - "\n" - " :return: True when the overridable status of the property was successfully set.\n" - " :rtype: boolean\n"); +PyDoc_STRVAR(pyrna_struct_property_overridable_library_set_doc, + ".. method:: property_overridable_library_set(property, overridable)\n" + "\n" + " Define a property as overridable or not (only for custom properties!).\n" + "\n" + " :return: True when the overridable status of the property was successfully set.\n" + " :rtype: boolean\n"); static PyObject *pyrna_struct_property_overridable_library_set(BPy_StructRNA *self, PyObject *args) { PropertyRNA *prop; @@ -3986,7 +4001,7 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self) } /** - * \note Return value is borrowed, caller must incref. + * \note Return value is borrowed, caller must #Py_INCREF. */ static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id) { @@ -6222,10 +6237,10 @@ PyTypeObject pyrna_struct_meta_idprop_Type = { 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* deprecated in Python 3.0! */ NULL, /* tp_repr */ @@ -6304,7 +6319,7 @@ PyTypeObject pyrna_struct_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_struct_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6393,7 +6408,7 @@ PyTypeObject pyrna_prop_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6477,7 +6492,7 @@ PyTypeObject pyrna_prop_array_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_array_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6560,7 +6575,7 @@ PyTypeObject pyrna_prop_collection_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6646,7 +6661,7 @@ static PyTypeObject pyrna_prop_collection_idprop_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -6731,10 +6746,10 @@ PyTypeObject pyrna_func_Type = { sizeof(BPy_FunctionRNA), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ + NULL, /* tp_dealloc */ + (printfunc)NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ NULL, /* tp_compare */ /* DEPRECATED in Python 3.0! */ (reprfunc)pyrna_func_repr, /* tp_repr */ @@ -6828,7 +6843,7 @@ static PyTypeObject pyrna_prop_collection_iter_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)pyrna_prop_collection_iter_dealloc, /* tp_dealloc */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, @@ -7193,7 +7208,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna) #endif /* Newclass will now have 2 ref's, ???, - * probably 1 is internal since decrefing here segfaults. */ + * probably 1 is internal since #Py_DECREF here segfaults. */ /* PyC_ObSpit("new class ref", newclass); */ diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 5e535d0e3ce..8aa6aa91fcf 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -277,7 +277,7 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, char pyrna_struct_keyframe_insert_doc[] = ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, " - "group=\"\")\n" + "group=\"\", options=set())\n" "\n" " Insert a keyframe on the property given, adding fcurves and animation data when " "necessary.\n" @@ -294,7 +294,7 @@ char pyrna_struct_keyframe_insert_doc[] = " :arg group: The name of the group the F-Curve should be added to if it doesn't exist " "yet.\n" " :type group: str\n" - " :arg options: Optional flags:\n" + " :arg options: Optional set of flags:\n" "\n" " - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant " "F-Curves.\n" diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index 4e21a8e0389..b587738c8d7 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -921,7 +921,7 @@ PyTypeObject color_Type = { sizeof(ColorObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 56662465b52..3fd9bf666e2 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -750,7 +750,7 @@ PyTypeObject euler_Type = { sizeof(EulerObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 6fd0fab2cdd..c6e6d395b6b 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -3141,7 +3141,7 @@ PyTypeObject matrix_Type = { sizeof(MatrixObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ - NULL, /*tp_print*/ + (printfunc)NULL, /*tp_print*/ NULL, /*tp_getattr*/ NULL, /*tp_setattr*/ NULL, /*tp_compare*/ @@ -3532,7 +3532,7 @@ PyTypeObject matrix_access_Type = { sizeof(MatrixAccessObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)MatrixAccess_dealloc, /*tp_dealloc*/ - NULL, /*tp_print*/ + (printfunc)NULL, /*tp_print*/ NULL, /*tp_getattr*/ NULL, /*tp_setattr*/ NULL, /*tp_compare*/ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 267971408bf..0de1ffb9879 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -176,6 +176,50 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self) return ret; } +PyDoc_STRVAR(Quaternion_to_swing_twist_doc, + ".. method:: to_swing_twist(axis)\n" + "\n" + " Split the rotation into a swing quaternion with the specified\n" + "axis fixed at zero, and the remaining twist rotation angle.\n" + "\n" + " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n" + " :return: swing, twist angle.\n" + " :rtype: (:class:`Quaternion`, float) pair\n"); +static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg) +{ + PyObject *ret; + + const char *axis_str = NULL; + float swing[4], twist; + int axis; + + if (axis_arg && PyUnicode_Check(axis_arg)) { + axis_str = _PyUnicode_AsString(axis_arg); + } + + if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) { + axis = axis_str[0] - 'X'; + } + else { + PyErr_SetString(PyExc_ValueError, + "Quaternion.to_swing_twist(): " + "the axis agrument must be " + "a string in 'X', 'Y', 'Z'"); + return NULL; + } + + if (BaseMath_ReadCallback(self) == -1) { + return NULL; + } + + twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL); + + ret = PyTuple_New(2); + PyTuple_SET_ITEMS( + ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist)); + return ret; +} + PyDoc_STRVAR( Quaternion_to_exponential_map_doc, ".. method:: to_exponential_map()\n" @@ -1368,6 +1412,10 @@ static struct PyMethodDef Quaternion_methods[] = { (PyCFunction)Quaternion_to_axis_angle, METH_NOARGS, Quaternion_to_axis_angle_doc}, + {"to_swing_twist", + (PyCFunction)Quaternion_to_swing_twist, + METH_O, + Quaternion_to_swing_twist_doc}, {"to_exponential_map", (PyCFunction)Quaternion_to_exponential_map, METH_NOARGS, @@ -1479,7 +1527,7 @@ PyTypeObject quaternion_Type = { sizeof(QuaternionObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)BaseMathObject_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index aa7cbadde14..387e560d946 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -691,7 +691,8 @@ PyDoc_STRVAR(Vector_to_track_quat_doc, static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args) { float vec[3], quat[4]; - const char *strack, *sup; + const char *strack = NULL; + const char *sup = NULL; short track = 2, up = 1; if (!PyArg_ParseTuple(args, "|ss:to_track_quat", &strack, &sup)) { @@ -2350,26 +2351,26 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos * * axis_dict = {} * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} - * axises = 'xyzw' - * while len(axises) >= 2: - * for axis_0 in axises: + * axis_chars = 'xyzw' + * while len(axis_chars) >= 2: + * for axis_0 in axis_chars: * axis_0_pos = axis_pos[axis_0] - * for axis_1 in axises: + * for axis_1 in axis_chars: * axis_1_pos = axis_pos[axis_1] * axis_dict[axis_0 + axis_1] = ( * '((%s | SWIZZLE_VALID_AXIS) | ' * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % * (axis_0_pos, axis_1_pos)) - * if len(axises) > 2: - * for axis_2 in axises: + * if len(axis_chars) > 2: + * for axis_2 in axis_chars: * axis_2_pos = axis_pos[axis_2] * axis_dict[axis_0 + axis_1 + axis_2] = ( * '((%s | SWIZZLE_VALID_AXIS) | ' * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % * (axis_0_pos, axis_1_pos, axis_2_pos)) - * if len(axises) > 3: - * for axis_3 in axises: + * if len(axis_chars) > 3: + * for axis_3 in axis_chars: * axis_3_pos = axis_pos[axis_3] * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( * '((%s | SWIZZLE_VALID_AXIS) | ' @@ -2379,7 +2380,7 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos * % * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) * - * axises = axises[:-1] + * axis_chars = axis_chars[:-1] * items = list(axis_dict.items()) * items.sort( * key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3') @@ -3054,7 +3055,7 @@ PyTypeObject vector_Type = { /* Methods to implement standard operations */ (destructor)BaseMathObject_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ + (printfunc)NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ NULL, /* cmpfunc tp_compare; */ diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 254177b14fe..d28b9a0de8f 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -1267,7 +1267,7 @@ PyTypeObject PyBVHTree_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)py_bvhtree__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 13d36e5af91..9a519abd49f 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1201,8 +1201,8 @@ static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject PyDoc_STRVAR(M_Geometry_tessellate_polygon_doc, ".. function:: tessellate_polygon(veclist_list)\n" "\n" - " Takes a list of polylines (each point a vector) and returns the point indices " - "for a polyline filled with triangles.\n" + " Takes a list of polylines (each point a pair or triplet of numbers) and returns " + "the point indices for a polyline filled with triangles.\n" "\n" " :arg veclist_list: list of polylines\n" " :rtype: list\n"); @@ -1211,13 +1211,15 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject { PyObject *tri_list; /*return this list of tri's */ PyObject *polyLine, *polyVec; - int i, len_polylines, len_polypoints, ls_error = 0; + int i, len_polylines, len_polypoints; + bool list_parse_error = false; + bool is_2d = true; /* Display #ListBase. */ ListBase dispbase = {NULL, NULL}; DispList *dl; float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ - int index, *dl_face, totpoints = 0; + int totpoints = 0; if (!PySequence_Check(polyLineSeq)) { PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines"); @@ -1238,15 +1240,6 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject len_polypoints = PySequence_Size(polyLine); if (len_polypoints > 0) { /* don't bother adding edges as polylines */ -# if 0 - if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { - freedisplist(&dispbase); - Py_DECREF(polyLine); - PyErr_SetString(PyExc_TypeError, - "A point in one of the polylines is not a mathutils.Vector type"); - return NULL; - } -# endif dl = MEM_callocN(sizeof(DispList), "poly disp"); BLI_addtail(&dispbase, dl); dl->type = DL_INDEX3; @@ -1254,49 +1247,38 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject dl->type = DL_POLY; dl->parts = 1; /* no faces, 1 edge loop */ dl->col = 0; /* no material */ - dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts"); - dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index"); + dl->verts = fp = MEM_mallocN(sizeof(float[3]) * len_polypoints, "dl verts"); + dl->index = MEM_callocN(sizeof(int[3]) * len_polypoints, "dl index"); - for (index = 0; index < len_polypoints; index++, fp += 3) { + for (int index = 0; index < len_polypoints; index++, fp += 3) { polyVec = PySequence_GetItem(polyLine, index); - if (VectorObject_Check(polyVec)) { - - if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1) { - ls_error = 1; - } + const int polyVec_len = mathutils_array_parse( + fp, 2, 3 | MU_ARRAY_SPILL, polyVec, "tessellate_polygon: parse coord"); + Py_DECREF(polyVec); - fp[0] = ((VectorObject *)polyVec)->vec[0]; - fp[1] = ((VectorObject *)polyVec)->vec[1]; - if (((VectorObject *)polyVec)->size > 2) { - fp[2] = ((VectorObject *)polyVec)->vec[2]; - } - else { - /* if its a 2d vector then set the z to be zero */ - fp[2] = 0.0f; - } + if (UNLIKELY(polyVec_len == -1)) { + list_parse_error = true; } - else { - ls_error = 1; + else if (polyVec_len == 2) { + fp[2] = 0.0f; + } + else if (polyVec_len == 3) { + is_2d = false; } totpoints++; - Py_DECREF(polyVec); } } Py_DECREF(polyLine); } - if (ls_error) { + if (list_parse_error) { BKE_displist_free(&dispbase); /* possible some dl was allocated */ - PyErr_SetString(PyExc_TypeError, - "A point in one of the polylines " - "is not a mathutils.Vector type"); return NULL; } else if (totpoints) { /* now make the list to return */ - /* TODO, add normal arg */ - BKE_displist_fill(&dispbase, &dispbase, NULL, false); + BKE_displist_fill(&dispbase, &dispbase, is_2d ? ((const float[3]){0, 0, -1}) : NULL, false); /* The faces are stored in a new DisplayList * that's added to the head of the #ListBase. */ @@ -1309,12 +1291,10 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject return NULL; } - index = 0; - dl_face = dl->index; - while (index < dl->parts) { + int *dl_face = dl->index; + for (int index = 0; index < dl->parts; index++) { PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; - index++; } BKE_displist_free(&dispbase); } diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c index b8a7f4d8708..e3f2cd9bd14 100644 --- a/source/blender/python/mathutils/mathutils_kdtree.c +++ b/source/blender/python/mathutils/mathutils_kdtree.c @@ -393,7 +393,7 @@ PyTypeObject PyKDTree_Type = { 0, /* tp_itemsize */ /* methods */ (destructor)PyKDTree__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ + (printfunc)NULL, /* tp_print */ NULL, /* tp_getattr */ NULL, /* tp_setattr */ NULL, /* tp_compare */ @@ -436,7 +436,7 @@ PyTypeObject PyKDTree_Type = { (destructor)NULL, /* tp_del */ }; -PyDoc_STRVAR(py_kdtree_doc, "Generic 3-dimentional kd-tree to perform spatial searches."); +PyDoc_STRVAR(py_kdtree_doc, "Generic 3-dimensional kd-tree to perform spatial searches."); static struct PyModuleDef kdtree_moduledef = { PyModuleDef_HEAD_INIT, "mathutils.kdtree", /* m_name */ diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index fdb90a6e91e..c3125cb72a1 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2506,6 +2506,10 @@ void RE_RenderAnim(Render *re, int efra, int tfra) { + /* Call hooks before taking a copy of scene->r, so user can alter the render settings prior to + * copying (e.g. alter the output path). */ + render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT); + const RenderData rd = scene->r; bMovieHandle *mh = NULL; const int cfrao = rd.cfra; @@ -2515,8 +2519,6 @@ void RE_RenderAnim(Render *re, const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 && (rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); - render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT); - /* do not fully call for each frame, it initializes & pops output window */ if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1)) { return; diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index cb33492763a..c99f5d4075f 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -832,7 +832,7 @@ void RE_point_density_cache(struct Depsgraph *depsgraph, PointDensity *pd) { Scene *scene = DEG_get_evaluated_scene(depsgraph); - /* Same matricies/resolution as dupli_render_particle_set(). */ + /* Same matrices/resolution as dupli_render_particle_set(). */ BLI_mutex_lock(&sample_mutex); cache_pointdensity(depsgraph, scene, pd); BLI_mutex_unlock(&sample_mutex); diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index ddd0ddb46da..59f99a9ff88 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC intern/wm_operator_type.c intern/wm_operators.c intern/wm_panel_type.c + intern/wm_platform_support.c intern/wm_playanim.c intern/wm_splash_screen.c intern/wm_stereo.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 455a30b6ff5..f8b6b5171da 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -102,6 +102,8 @@ void WM_init_opengl(struct Main *bmain); void WM_check(struct bContext *C); void WM_reinit_gizmomap_all(struct Main *bmain); +void WM_script_tag_reload(void); + uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); int WM_window_pixels_x(const struct wmWindow *win); @@ -153,18 +155,15 @@ void WM_opengl_context_dispose(void *context); void WM_opengl_context_activate(void *context); void WM_opengl_context_release(void *context); -/* defines for 'type' WM_window_open_temp */ -enum { - WM_WINDOW_RENDER = 1, - WM_WINDOW_USERPREFS, - WM_WINDOW_DRIVERS, - WM_WINDOW_INFO, - WM_WINDOW_FILESEL, -}; - struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); -struct wmWindow *WM_window_open_temp( - struct bContext *C, int x, int y, int sizex, int sizey, int type); +struct wmWindow *WM_window_open_temp(struct bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + int space_type, + bool dialog); void WM_window_set_dpi(wmWindow *win); bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); @@ -336,6 +335,12 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, /* operator api, default callbacks */ /* invoke callback, uses enum property named "type" */ +int WM_generic_select_modal(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); +int WM_generic_select_invoke(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); @@ -475,6 +480,7 @@ void WM_operator_properties_select_random(struct wmOperatorType *ot); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); void WM_operator_properties_select_operation(struct wmOperatorType *ot); void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot); +void WM_operator_properties_generic_select(struct wmOperatorType *ot); struct CheckerIntervalParams { int nth; /* bypass when set to zero */ int skip; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 5ecd3191bfb..15ad8cbedc4 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -776,7 +776,7 @@ typedef struct wmOperatorType { } wmOperatorType; /** - * Wrapper to reference a wmOperatorType together with some set properties and othere relevant + * Wrapper to reference a #wmOperatorType together with some set properties and other relevant * information to invoke the operator in a customizable way. */ typedef struct wmOperatorCallParams { diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 2313383fe6e..8e796a7981a 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -45,35 +45,90 @@ #include "wm_cursors.h" #include "wm_window.h" -/* XXX this still is mess from old code */ +/* Blender custom cursor. */ +typedef struct BCursor { + char *small_bm; + char *small_mask; -/* Some simple ghost <-> blender conversions */ -static GHOST_TStandardCursor convert_cursor(int curs) + char small_sizex; + char small_sizey; + char small_hotx; + char small_hoty; + + char *big_bm; + char *big_mask; + + char big_sizex; + char big_sizey; + char big_hotx; + char big_hoty; + + bool can_invert_color; +} BCursor; + +static BCursor *BlenderCursor[WM_CURSOR_NUM] = {0}; + +/* Blender cursor to GHOST standard cursor conversion. */ +static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs) { switch (curs) { - default: - case CURSOR_STD: + case WM_CURSOR_DEFAULT: return GHOST_kStandardCursorDefault; - case CURSOR_FACESEL: - return GHOST_kStandardCursorRightArrow; - case CURSOR_WAIT: + case WM_CURSOR_WAIT: return GHOST_kStandardCursorWait; - case CURSOR_EDIT: + case WM_CURSOR_EDIT: + case WM_CURSOR_CROSS: return GHOST_kStandardCursorCrosshair; - case CURSOR_HELP: -#ifdef __APPLE__ - return GHOST_kStandardCursorLeftRight; -#else - return GHOST_kStandardCursorHelp; -#endif - case CURSOR_X_MOVE: + case WM_CURSOR_X_MOVE: return GHOST_kStandardCursorLeftRight; - case CURSOR_Y_MOVE: + case WM_CURSOR_Y_MOVE: return GHOST_kStandardCursorUpDown; - case CURSOR_PENCIL: - return GHOST_kStandardCursorPencil; - case CURSOR_COPY: + case WM_CURSOR_COPY: return GHOST_kStandardCursorCopy; + case WM_CURSOR_HAND: + return GHOST_kStandardCursorMove; + case WM_CURSOR_H_SPLIT: + return GHOST_kStandardCursorHorizontalSplit; + case WM_CURSOR_V_SPLIT: + return GHOST_kStandardCursorVerticalSplit; + case WM_CURSOR_STOP: + return GHOST_kStandardCursorStop; + case WM_CURSOR_KNIFE: + return GHOST_kStandardCursorKnife; + case WM_CURSOR_NSEW_SCROLL: + return GHOST_kStandardCursorNSEWScroll; + case WM_CURSOR_NS_SCROLL: + return GHOST_kStandardCursorNSScroll; + case WM_CURSOR_EW_SCROLL: + return GHOST_kStandardCursorEWScroll; + case WM_CURSOR_EYEDROPPER: + return GHOST_kStandardCursorEyedropper; + case WM_CURSOR_N_ARROW: + return GHOST_kStandardCursorUpArrow; + case WM_CURSOR_S_ARROW: + return GHOST_kStandardCursorDownArrow; + case WM_CURSOR_PAINT: + return GHOST_kStandardCursorCrosshairA; + case WM_CURSOR_DOT: + return GHOST_kStandardCursorCrosshairB; + case WM_CURSOR_CROSSC: + return GHOST_kStandardCursorCrosshairC; + case WM_CURSOR_ERASER: + return GHOST_kStandardCursorEraser; + case WM_CURSOR_ZOOM_IN: + return GHOST_kStandardCursorZoomIn; + case WM_CURSOR_ZOOM_OUT: + return GHOST_kStandardCursorZoomOut; + case WM_CURSOR_TEXT_EDIT: + return GHOST_kStandardCursorText; + case WM_CURSOR_PAINT_BRUSH: + return GHOST_kStandardCursorPencil; + case WM_CURSOR_E_ARROW: + return GHOST_kStandardCursorRightArrow; + case WM_CURSOR_W_ARROW: + return GHOST_kStandardCursorLeftArrow; + default: + return GHOST_kStandardCursorCustom; } } @@ -87,9 +142,9 @@ static void window_set_custom_cursor(wmWindow *win, win->ghostwin, (GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask, 16, 16, hotx, hoty, true); } -static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig) +static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor) { - if (useBig) { + if (U.curssize && cursor->big_bm) { GHOST_SetCustomCursorShape(win->ghostwin, (GHOST_TUns8 *)cursor->big_bm, (GHOST_TUns8 *)cursor->big_mask, @@ -111,60 +166,55 @@ static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useB } } -/* Cursor Globals */ -static BCursor *BlenderCursor[BC_NUMCURSORS]; /*Points to static BCursor Structs */ - void WM_cursor_set(wmWindow *win, int curs) { - if (win == NULL || G.background) { return; /* Can't set custom cursor before Window init */ } - if (curs == CURSOR_NONE) { + if (curs == WM_CURSOR_NONE) { GHOST_SetCursorVisibility(win->ghostwin, 0); return; } -#ifdef _WIN32 - /* the default win32 cross cursor is barely visible, - * only 1 pixel thick, use another one instead */ - if (curs == CURSOR_EDIT) { - curs = BC_CROSSCURSOR; - } -#else - /* in case of large cursor, also use custom cursor because - * large cursors don't work for system cursors */ - if (U.curssize && curs == CURSOR_EDIT) { - curs = BC_CROSSCURSOR; - } -#endif - GHOST_SetCursorVisibility(win->ghostwin, 1); - if (curs == CURSOR_STD && win->modalcursor) { + if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { curs = win->modalcursor; } win->cursor = curs; - /* detect if we use system cursor or Blender cursor */ - if (curs >= BC_GHOST_CURSORS) { - GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs)); + if (curs < 0 || curs >= WM_CURSOR_NUM) { + BLI_assert(!"Invalid cursor number"); + return; } - else { - if ((curs < SYSCURSOR) || (curs >= BC_NUMCURSORS)) { - return; - } - if (curs == SYSCURSOR) { /* System default Cursor */ - GHOST_SetCursorShape(win->ghostwin, convert_cursor(CURSOR_STD)); - } - else if ((U.curssize == 0) || (BlenderCursor[curs]->big_bm == NULL)) { - window_set_custom_cursor_ex(win, BlenderCursor[curs], 0); + GHOST_TStandardCursor ghost_cursor = convert_to_ghost_standard_cursor(curs); + +#if !defined(_WIN32) && !defined(__APPLE__) + /* Workaround crosshair cursors with bad visibility in some cursor themes. + * Better solution would be to always use custom cursors and support DPI + * properly so that the cursors look as good as the native ones. */ + if (U.curssize && ghost_cursor == GHOST_kStandardCursorCrosshair) { + ghost_cursor = GHOST_kStandardCursorCustom; + } +#endif + + if (ghost_cursor != GHOST_kStandardCursorCustom && + GHOST_HasCursorShape(win->ghostwin, ghost_cursor)) { + /* Use native GHOST cursor when available. */ + GHOST_SetCursorShape(win->ghostwin, ghost_cursor); + } + else { + BCursor *bcursor = BlenderCursor[curs]; + if (bcursor) { + /* Use custom bitmap cursor. */ + window_set_custom_cursor_ex(win, bcursor); } else { - window_set_custom_cursor_ex(win, BlenderCursor[curs], 1); + /* Fallback to default cursor if no bitmap found. */ + GHOST_SetCursorShape(win->ghostwin, GHOST_kStandardCursorDefault); } } } @@ -176,7 +226,7 @@ bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const AReg } bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL; - if (tref_rt && tref_rt->cursor != CURSOR_STD) { + if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) { if (win->modalcursor == 0) { WM_cursor_set(win, tref_rt->cursor); win->cursor = tref_rt->cursor; @@ -213,7 +263,7 @@ void WM_cursor_wait(bool val) for (; win; win = win->next) { if (val) { - WM_cursor_modal_set(win, BC_WAITCURSOR); + WM_cursor_modal_set(win, WM_CURSOR_WAIT); } else { WM_cursor_modal_restore(win); @@ -410,15 +460,39 @@ void wm_init_cursor_data(void) /********************** NW_ARROW Cursor **************************/ BEGIN_CURSOR_BLOCK; static char nw_sbm[] = { - 0x03, 0x00, 0x05, 0x00, 0x09, 0x00, 0x11, 0x00, 0x21, 0x00, 0x41, - 0x00, 0x81, 0x00, 0x01, 0x01, 0x01, 0x02, 0xc1, 0x03, 0x49, 0x00, - 0x8d, 0x00, 0x8b, 0x00, 0x10, 0x01, 0x90, 0x01, 0x60, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x3e, + 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x01, 0xfe, 0x03, 0xfe, 0x07, + 0x7e, 0x00, 0x6e, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0x00, 0x00, }; static char nw_smsk[] = { 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3f, 0x00, 0x7f, - 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00, - 0xff, 0x00, 0xfb, 0x00, 0xf0, 0x01, 0xf0, 0x01, 0x60, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x03, 0xff, 0x07, 0xff, 0x0f, + 0xff, 0x0f, 0xff, 0x00, 0xef, 0x01, 0xe7, 0x01, 0xc3, 0x00, + }; + + static char nw_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, + 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, + 0xfe, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x07, + 0x00, 0xfe, 0xff, 0x0f, 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xfe, 0x3f, + 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x7e, 0x7c, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1e, + 0xf8, 0x00, 0x00, 0x0e, 0xf8, 0x00, 0x00, 0x06, 0xf0, 0x01, 0x00, 0x02, 0xf0, 0x01, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char nw_lmsk[] = { + 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, + 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, + 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x0f, + 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f, + 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, + 0xfc, 0x01, 0x00, 0x1f, 0xfc, 0x01, 0x00, 0x0f, 0xf8, 0x03, 0x00, 0x07, 0xf8, 0x03, 0x00, + 0x03, 0xf0, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, }; static BCursor NWArrowCursor = { @@ -427,34 +501,60 @@ void wm_init_cursor_data(void) nw_smsk, 16, 16, - 6, - 7, + 0, + 0, /* big */ - NULL, - NULL, + nw_lbm, + nw_lmsk, 32, 32, - 15, - 15, + 0, + 0, /* can invert color */ true, }; - BlenderCursor[BC_NW_ARROWCURSOR] = &NWArrowCursor; + BlenderCursor[WM_CURSOR_DEFAULT] = &NWArrowCursor; + BlenderCursor[WM_CURSOR_COPY] = &NWArrowCursor; + BlenderCursor[WM_CURSOR_NW_ARROW] = &NWArrowCursor; END_CURSOR_BLOCK; ///********************** NS_ARROW Cursor *************************/ BEGIN_CURSOR_BLOCK; static char ns_sbm[] = { - 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x3c, - 0x1e, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x3c, 0x1e, - 0x04, 0x10, 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, + 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0x80, + 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, }; static char ns_smsk[] = { - 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, - 0x1f, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f, - 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, + 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, + 0x1f, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xfc, 0x1f, + 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, + }; + + static char ns_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, + 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char ns_lmsk[] = { + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07, + 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, + 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, + 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xe0, 0xff, + 0xff, 0x01, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, }; static BCursor NSArrowCursor = { @@ -463,11 +563,11 @@ void wm_init_cursor_data(void) ns_smsk, 16, 16, - 6, + 7, 7, /* big */ - NULL, - NULL, + ns_lbm, + ns_lmsk, 32, 32, 15, @@ -476,21 +576,46 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor; + BlenderCursor[WM_CURSOR_Y_MOVE] = &NSArrowCursor; + BlenderCursor[WM_CURSOR_NS_ARROW] = &NSArrowCursor; END_CURSOR_BLOCK; /********************** EW_ARROW Cursor *************************/ BEGIN_CURSOR_BLOCK; static char ew_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x2c, 0x34, 0xe6, - 0x67, 0x03, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0xe6, 0x67, 0x2c, 0x34, - 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x18, + 0x18, 0x1c, 0x38, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, 0x10, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char ew_smsk[] = { - 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x3c, 0x3c, 0xfe, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, - 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x30, 0x0c, 0x38, 0x1c, 0x3c, + 0x3c, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, 0x38, 0x1c, + 0x30, 0x0c, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char ew_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x01, 0x80, 0x07, 0xf0, + 0x01, 0x80, 0x0f, 0xf8, 0x01, 0x80, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0xff, 0xff, 0x7f, + 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x01, 0x80, 0x1f, 0xf0, 0x01, 0x80, + 0x0f, 0xe0, 0x01, 0x80, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char ew_lmsk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x80, 0x03, + 0xc0, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x03, 0xc0, 0x0f, 0xf8, + 0x03, 0xc0, 0x1f, 0xfc, 0x03, 0xc0, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0x03, 0xc0, 0x3f, 0xf8, 0x03, 0xc0, + 0x1f, 0xf0, 0x03, 0xc0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x03, + 0xc0, 0x01, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static BCursor EWArrowCursor = { @@ -500,10 +625,10 @@ void wm_init_cursor_data(void) 16, 16, 7, - 6, + 7, /* big */ - NULL, - NULL, + ew_lbm, + ew_lmsk, 32, 32, 15, @@ -512,45 +637,46 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_EW_ARROWCURSOR] = &EWArrowCursor; + BlenderCursor[WM_CURSOR_X_MOVE] = &EWArrowCursor; + BlenderCursor[WM_CURSOR_EW_ARROW] = &EWArrowCursor; END_CURSOR_BLOCK; /********************** Wait Cursor *****************************/ BEGIN_CURSOR_BLOCK; static char wait_sbm[] = { - 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x84, 0x21, 0xc8, 0x13, 0xd0, - 0x0b, 0xa0, 0x04, 0x20, 0x05, 0xa0, 0x04, 0x10, 0x09, 0x88, 0x11, - 0xc4, 0x23, 0xe2, 0x47, 0xfa, 0x5f, 0x02, 0x40, 0xfe, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf0, 0x07, 0xb0, 0x06, 0x60, + 0x03, 0xc0, 0x01, 0x80, 0x00, 0x80, 0x00, 0xc0, 0x01, 0x60, 0x03, + 0x30, 0x06, 0x10, 0x04, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, }; static char wait_smsk[] = { - 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x8c, 0x31, 0xd8, 0x1b, 0xf0, - 0x0f, 0xe0, 0x06, 0x60, 0x07, 0xe0, 0x06, 0x30, 0x0d, 0x98, 0x19, - 0xcc, 0x33, 0xe6, 0x67, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, + 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xf0, + 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, + 0xf8, 0x0f, 0xf8, 0x0f, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f, }; static char wait_lbm[] = { - 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, - 0x30, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x18, 0xc0, 0x03, 0x0c, 0x30, 0x20, - 0x07, 0x06, 0x60, 0xf0, 0x0f, 0x03, 0xc0, 0xd0, 0x8d, 0x01, 0x80, 0x79, 0xcf, 0x00, 0x00, - 0xf3, 0x67, 0x00, 0x00, 0x66, 0x37, 0x00, 0x00, 0x8c, 0x33, 0x00, 0x00, 0x0c, 0x32, 0x00, - 0x00, 0xcc, 0x33, 0x00, 0x00, 0x8c, 0x30, 0x00, 0x00, 0x46, 0x61, 0x00, 0x00, 0x03, 0xc3, - 0x00, 0x80, 0x01, 0x83, 0x01, 0xc0, 0xc0, 0x03, 0x03, 0x60, 0xa0, 0x05, 0x06, 0x30, 0xf0, - 0x0f, 0x0c, 0x18, 0xf8, 0x1d, 0x18, 0x0c, 0x5c, 0x3f, 0x30, 0x0c, 0xff, 0x5f, 0x30, 0x0c, - 0xf7, 0xfe, 0x31, 0xcc, 0xfb, 0x9f, 0x33, 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30, - 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, + 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, + 0x7f, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0f, 0x3c, 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, + 0x3c, 0x0f, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x30, 0x03, + 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1f, + 0x3e, 0x00, 0x80, 0x0f, 0x7c, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x03, 0x70, 0x00, 0x80, + 0x01, 0x60, 0x00, 0x80, 0x01, 0x60, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char wait_lmsk[] = { - 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, - 0x3f, 0x3c, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x1e, 0x78, 0xc0, 0x03, 0x0f, 0xf0, 0xa0, - 0x87, 0x07, 0xe0, 0xf1, 0xcf, 0x03, 0xc0, 0xf3, 0xef, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00, - 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x3c, 0x3f, 0x00, - 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xbc, 0x3c, 0x00, 0x00, 0xde, 0x79, 0x00, 0x00, 0x0f, 0xf3, - 0x00, 0x80, 0x07, 0xe3, 0x01, 0xc0, 0xc3, 0xc3, 0x03, 0xe0, 0xe1, 0x87, 0x07, 0xf0, 0xf0, - 0x0f, 0x0f, 0x78, 0xf8, 0x1f, 0x1e, 0x3c, 0x7c, 0x3f, 0x3c, 0x3c, 0xff, 0x7f, 0x3c, 0xbc, - 0xff, 0xff, 0x3d, 0xfc, 0xfb, 0xbf, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, - 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, + 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, + 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, + 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07, + 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, + 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, + 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xff, 0x03, + 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03, }; static BCursor WaitCursor = { @@ -568,48 +694,50 @@ void wm_init_cursor_data(void) 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_WAITCURSOR] = &WaitCursor; + BlenderCursor[WM_CURSOR_WAIT] = &WaitCursor; END_CURSOR_BLOCK; - /********************** Cross Cursor ***************************/ + /****************** Normal Cross Cursor ************************/ BEGIN_CURSOR_BLOCK; static char cross_sbm[] = { 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, - 0x01, 0x80, 0x01, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x01, 0x80, 0x01, + 0x01, 0x00, 0x00, 0x3e, 0x7c, 0x3e, 0x7c, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, + }; static char cross_smsk[] = { - 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, - 0x01, 0xc0, 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0xc0, 0x03, 0x80, 0x01, - 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, + 0x03, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0xff, 0xff, 0xc0, 0x03, + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, }; static char cross_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x78, 0x1e, 0x00, - 0xfc, 0x1f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x3f, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x40, 0x02, - 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x3f, 0xfc, 0x7f, 0xfe, 0x3f, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char cross_lmsk[] = { - 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, - 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00, - 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e, - 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xc0, 0x03, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, }; static BCursor CrossCursor = { @@ -627,121 +755,227 @@ void wm_init_cursor_data(void) 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_CROSSCURSOR] = &CrossCursor; + BlenderCursor[WM_CURSOR_EDIT] = &CrossCursor; + BlenderCursor[WM_CURSOR_CROSS] = &CrossCursor; END_CURSOR_BLOCK; - /********************** EditCross Cursor ***********************/ + /****************** Painting Cursor ************************/ BEGIN_CURSOR_BLOCK; - static char editcross_sbm[] = { - 0x0e, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x19, 0x03, 0x1d, 0x03, 0x11, - 0x03, 0x0e, 0x03, 0x00, 0x03, 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03, - 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, + static char paint_sbm[] = { + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, + }; + + static char paint_smsk[] = { + 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x8f, 0x78, 0xcf, 0x79, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0x00, 0x00, + }; + static char paint_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x01, 0x7f, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, }; - static char editcross_smsk[] = { - 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x03, 0x1f, 0x03, 0x1f, 0x03, 0x1f, - 0x03, 0x0e, 0x03, 0x80, 0x07, 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07, - 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, + static char paint_lmsk[] = { + 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x01, 0x7f, + 0xff, 0xc1, 0x83, 0xff, 0xff, 0xc1, 0x83, 0xff, 0xfe, 0x80, 0x01, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, }; - static BCursor EditCrossCursor = { + static BCursor PaintCursor = { /* small */ - editcross_sbm, - editcross_smsk, + paint_sbm, + paint_smsk, 16, 16, - 9, - 8, + 7, + 7, /* big */ - NULL, - NULL, + paint_lbm, + paint_lmsk, 32, 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_EDITCROSSCURSOR] = &EditCrossCursor; + BlenderCursor[WM_CURSOR_PAINT] = &PaintCursor; END_CURSOR_BLOCK; - /********************** Box Select *************************/ + /********************** Dot Cursor ***********************/ BEGIN_CURSOR_BLOCK; - static char box_sbm[32] = { - 0x7f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x06, 0x41, 0x06, 0x41, - 0x06, 0x7f, 0x06, 0x00, 0x06, 0xe0, 0x79, 0xe0, 0x79, 0x00, 0x06, - 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, + static char dot_sbm[] = { + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, }; - static char box_smsk[32] = { - 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x06, 0x63, 0x06, 0x63, 0x06, 0x7f, - 0x06, 0x7f, 0x06, 0x00, 0x0f, 0xf0, 0xf9, 0xf0, 0xf9, 0x00, 0x0f, - 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, + static char dot_smsk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static char dot_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - static BCursor BoxSelCursor = { + static char dot_lmsk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static BCursor DotCursor = { /* small */ - box_sbm, - box_smsk, + dot_sbm, + dot_smsk, 16, 16, - 9, - 8, + 7, + 7, + /* big */ + dot_lbm, + dot_lmsk, + 32, + 32, + 14, + 14, + /* don't invert color */ + false, + }; + + BlenderCursor[WM_CURSOR_DOT] = &DotCursor; + END_CURSOR_BLOCK; + + /************* Minimal Crosshair Cursor ***************/ + BEGIN_CURSOR_BLOCK; + static char crossc_sbm[] = { + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x55, 0x55, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + }; + + static char crossc_smsk[] = { + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, + 0x00, 0x80, 0x00, 0x7f, 0x7f, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, + }; + static char crossc_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char crossc_lmsk[] = { + 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x1e, 0x00, + 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x70, 0x0e, + 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, + }; + + static BCursor CrossCursorC = { + /* small */ + crossc_sbm, + crossc_smsk, + 16, + 16, + 7, + 7, /* big */ - NULL, - NULL, + crossc_lbm, + crossc_lmsk, 32, 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_BOXSELCURSOR] = &BoxSelCursor; - + BlenderCursor[WM_CURSOR_CROSSC] = &CrossCursorC; END_CURSOR_BLOCK; + /********************** Knife Cursor ***********************/ BEGIN_CURSOR_BLOCK; static char knife_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x5a, 0x00, - 0x34, 0x00, 0x2a, 0x00, 0x17, 0x80, 0x06, 0x40, 0x03, 0xa0, 0x03, - 0xd0, 0x01, 0x68, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x0f, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01, + 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x0e, 0x00, 0x00, 0x00, }; static char knife_smsk[] = { - 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0xfe, 0x00, - 0x7e, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x0e, 0x60, 0x07, 0xb0, 0x07, - 0xd8, 0x03, 0xec, 0x01, 0x7e, 0x00, 0x1f, 0x00, 0x07, 0x00, + 0x00, 0x40, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0x78, 0x00, 0x3c, 0x00, + 0x1e, 0x00, 0x0f, 0x80, 0x1f, 0xc0, 0x0f, 0xe0, 0x07, 0xf0, 0x03, + 0xf8, 0x01, 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0f, 0x00, }; static char knife_lbm[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, - 0x00, 0x7f, 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0xc0, 0x5f, 0x00, 0x00, 0xc0, 0x6f, 0x00, - 0x00, 0xc0, 0x37, 0x00, 0x00, 0xa8, 0x1b, 0x00, 0x00, 0x54, 0x0d, 0x00, 0x00, 0xa8, 0x00, - 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x07, - 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4, - 0x07, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0xc0, - 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x1f, + 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, + 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0xe0, + 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char knife_lmsk[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, - 0x80, 0xff, 0x00, 0x00, 0xc0, 0xbf, 0x00, 0x00, 0xe0, 0xdf, 0x00, 0x00, 0xe0, 0xef, 0x00, - 0x00, 0xf8, 0x77, 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0xfe, 0x1d, 0x00, 0x00, 0xfe, 0x0f, - 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe0, 0x7f, - 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xd8, 0x1f, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x00, 0xf6, - 0x0f, 0x00, 0x00, 0xfb, 0x06, 0x00, 0x80, 0xbd, 0x01, 0x00, 0xc0, 0x6e, 0x00, 0x00, 0xe0, - 0x1b, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, + 0xc0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, + 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xff, 0x01, + 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0x7f, + 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff, + 0x07, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, + 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, + 0xff, 0x03, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, }; static BCursor KnifeCursor = { @@ -759,11 +993,11 @@ void wm_init_cursor_data(void) 32, 0, 31, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor; + BlenderCursor[WM_CURSOR_KNIFE] = &KnifeCursor; END_CURSOR_BLOCK; @@ -771,9 +1005,9 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char vloop_sbm[] = { - 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x66, - 0x60, 0x62, 0x6f, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x00, 0x00, 0x60, 0x60, 0x60, 0x6f, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0xfe, 0xf0, 0x96, + 0x9f, 0x92, 0x90, 0xf0, 0xf0, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, + 0x20, 0x40, 0xf0, 0xf0, 0x90, 0x90, 0x90, 0x9f, 0xf0, 0xf0, }; static char vloop_smsk[] = { @@ -783,27 +1017,27 @@ void wm_init_cursor_data(void) }; static char vloop_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, - 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, - 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x3c, 0x3c, - 0x3c, 0x00, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x0c, 0x3c, 0xff, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, - 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, - 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0xff, 0x3c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, + 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfe, 0x01, + 0x00, 0x00, 0xfe, 0x7e, 0x00, 0x7e, 0x7e, 0xff, 0x00, 0xff, 0x3e, 0xc3, 0x00, 0xc3, 0x1e, + 0xc3, 0xff, 0xc3, 0x0e, 0xc3, 0xff, 0xc3, 0x06, 0xc3, 0x00, 0xc3, 0x02, 0xff, 0x00, 0xff, + 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, + 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, + 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xc3, 0x00, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0xff, 0xc3, 0x00, 0xc3, 0x00, 0xc3, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e, }; static char vloop_lmsk[] = { - 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, - 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff, - 0x0f, 0xff, 0x00, 0xff, 0x03, 0x3c, 0x00, 0x3c, 0x03, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, - 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, - 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07, + 0x00, 0x00, 0xff, 0x7f, 0x00, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x7f, + 0xe7, 0xff, 0xe7, 0x3f, 0xe7, 0xff, 0xe7, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0x00, 0xff, + 0x07, 0x7e, 0x00, 0x7e, 0x03, 0x38, 0x00, 0x38, 0x01, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, + 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xff, 0x00, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xe7, 0xff, 0xe7, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0x7e, 0x00, 0x7e, }; static BCursor VLoopCursor = { @@ -821,26 +1055,50 @@ void wm_init_cursor_data(void) 32, 0, 0, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor; + BlenderCursor[WM_CURSOR_VERTEX_LOOP] = &VLoopCursor; END_CURSOR_BLOCK; /********************** TextEdit Cursor ***********************/ BEGIN_CURSOR_BLOCK; static char textedit_sbm[] = { - 0xe0, 0x03, 0x10, 0x04, 0x60, 0x03, 0x40, 0x01, 0x40, 0x01, 0x40, - 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, - 0x40, 0x01, 0x40, 0x01, 0x60, 0x03, 0x10, 0x04, 0xe0, 0x03, + 0x00, 0x00, 0x70, 0x07, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, + 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x70, 0x07, 0x00, 0x00, }; static char textedit_smsk[] = { - 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0xc0, + 0x70, 0x07, 0xf8, 0x0f, 0xf0, 0x07, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, - 0xc0, 0x01, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, + 0xc0, 0x01, 0xc0, 0x01, 0xf0, 0x07, 0xf8, 0x0f, 0x70, 0x07, + }; + + static char textedit_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xe0, 0x01, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xff, 0x3f, 0x00, + 0x00, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char textedit_lmsk[] = { + 0x00, 0x3f, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, + 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, + 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, + 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, + 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, + 0x80, 0xff, 0x7f, 0x00, 0x00, 0x3f, 0x3f, 0x00, }; static BCursor TextEditCursor = { @@ -849,35 +1107,58 @@ void wm_init_cursor_data(void) textedit_smsk, 16, 16, - 9, - 8, + 7, + 7, /* big */ - NULL, - NULL, + textedit_lbm, + textedit_lmsk, 32, 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_TEXTEDITCURSOR] = &TextEditCursor; + BlenderCursor[WM_CURSOR_TEXT_EDIT] = &TextEditCursor; END_CURSOR_BLOCK; /********************** Paintbrush Cursor ***********************/ BEGIN_CURSOR_BLOCK; static char paintbrush_sbm[] = { - - 0x00, 0xe0, 0x00, 0x98, 0x00, 0x44, 0x00, 0x42, 0x00, 0x21, 0x80, - 0x20, 0x40, 0x13, 0x40, 0x17, 0xa0, 0x0b, 0x98, 0x05, 0x04, 0x02, - 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x81, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x74, 0x00, 0x2e, 0x00, + 0x1f, 0x80, 0x0f, 0xc0, 0x07, 0xe0, 0x03, 0xf0, 0x01, 0xf8, 0x00, + 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00, }; static char paintbrush_smsk[] = { - 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x3f, 0x80, - 0x3f, 0xc0, 0x1f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf8, 0x07, 0xfc, 0x03, - 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xff, 0x00, 0x7f, 0x00, + 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x00, 0x7f, 0x80, + 0x3f, 0xc0, 0x1f, 0xe0, 0x0f, 0xf0, 0x07, 0xf8, 0x03, 0xfc, 0x01, + 0xfe, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x1f, 0x00, 0x0f, 0x00, + }; + + static char paintbrush_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, + 0x10, 0x1f, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, + 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, + 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, + 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, + 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char paintbrush_lmsk[] = { + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xc0, + 0x3f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, + 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, + 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, + 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, + 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, + 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, }; static BCursor PaintBrushCursor = { @@ -889,32 +1170,116 @@ void wm_init_cursor_data(void) 0, 15, /* big */ - NULL, - NULL, + paintbrush_lbm, + paintbrush_lmsk, 32, 32, - 15, - 15, - /* can invert color */ - true, + 0, + 31, + /* don't invert color */ + false, }; - BlenderCursor[BC_PAINTBRUSHCURSOR] = &PaintBrushCursor; + BlenderCursor[WM_CURSOR_PAINT_BRUSH] = &PaintBrushCursor; + END_CURSOR_BLOCK; + + /********************** Eraser Cursor ***********************/ + BEGIN_CURSOR_BLOCK; + static char eraser_sbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x07, + 0xfe, 0x03, 0xfe, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char eraser_smsk[] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x1f, 0x80, 0x3f, 0xc0, + 0x7f, 0xe0, 0xff, 0xf0, 0x7f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfe, 0x0f, + 0xff, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00, + }; + + static char eraser_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, + 0x01, 0x06, 0x00, 0xc0, 0x00, 0x0c, 0x00, 0x60, 0x00, 0x18, 0x00, 0x30, 0x00, 0x30, 0x00, + 0x18, 0x00, 0x60, 0x00, 0x4c, 0x00, 0xc0, 0x00, 0xe6, 0x00, 0xc0, 0x00, 0xf3, 0x01, 0x60, + 0x80, 0xf9, 0x03, 0x30, 0xc0, 0xfc, 0x07, 0x18, 0x60, 0xfe, 0x0f, 0x0c, 0x30, 0xff, 0x1f, + 0x06, 0x98, 0xff, 0x3f, 0x03, 0xcc, 0xff, 0x9f, 0x01, 0xe6, 0xff, 0xcf, 0x00, 0xf3, 0xff, + 0x67, 0x00, 0xf9, 0xff, 0x33, 0x00, 0xfd, 0xff, 0x19, 0x00, 0xfd, 0xff, 0x0c, 0x00, 0xfd, + 0x7f, 0x06, 0x00, 0xfd, 0x3f, 0x03, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char eraser_lmsk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x80, + 0xff, 0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0x3f, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, 0x7f, + 0x80, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, + 0x07, 0xf8, 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x1f, 0x00, 0xff, 0xff, 0x0f, 0x00, 0xff, + 0xff, 0x07, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static BCursor EraserCursor = { + /* small */ + eraser_sbm, + eraser_smsk, + 16, + 16, + 0, + 14, + /* big */ + eraser_lbm, + eraser_lmsk, + 32, + 32, + 0, + 28, + /* don't invert color */ + false, + }; + + BlenderCursor[WM_CURSOR_ERASER] = &EraserCursor; END_CURSOR_BLOCK; /********************** Hand Cursor ***********************/ BEGIN_CURSOR_BLOCK; static char hand_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0x98, - 0x6d, 0xb0, 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, - 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x1f, 0xc0, 0x1f, + 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d, 0x98, 0x6d, 0xb8, 0x6d, 0xb0, + 0x6d, 0xb0, 0x6d, 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, 0x7c, 0x35, + 0x78, 0x35, 0x70, 0x15, 0x60, 0x15, 0xc0, 0x1f, 0xc0, 0x1f, }; static char hand_smsk[] = { - 0x00, 0x00, 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc, - 0xff, 0xf8, 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f, + 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f, 0xfc, 0xff, 0xfc, 0xff, 0xf8, + 0xff, 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, + 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f, + }; + + static char hand_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x30, 0x0f, + 0x00, 0x00, 0x78, 0xcf, 0x00, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78, 0xef, 0x01, 0x00, 0x78, + 0xef, 0x01, 0x00, 0x78, 0xef, 0x1d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00, + 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x00, 0x78, 0xef, 0x3d, 0x70, 0x78, 0xef, 0x3d, + 0xf0, 0x78, 0xef, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff, 0x3d, 0xf0, 0xf8, 0xff, + 0x3f, 0xf0, 0xb9, 0xf7, 0x3f, 0xe0, 0xbb, 0xf7, 0x3f, 0xe0, 0xbf, 0xf7, 0x3e, 0xe0, 0xbf, + 0xf7, 0x3e, 0xc0, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x80, 0xbf, 0xf7, 0x3e, 0x00, + 0xbf, 0xf7, 0x1e, 0x00, 0xbe, 0xf7, 0x1e, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, + 0x00, 0xf8, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07, + }; + + static char hand_lmsk[] = { + 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0xff, + 0x01, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfc, + 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, 0x00, + 0xfc, 0xff, 0x7f, 0x60, 0xfc, 0xff, 0x7f, 0xf8, 0xfc, 0xff, 0x7f, 0xf8, 0xfd, 0xff, 0x7f, + 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xfd, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, + 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x7f, 0xf0, 0xff, + 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0x7f, 0x80, + 0xff, 0xff, 0x7f, 0x80, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x1f, }; static BCursor HandCursor = { @@ -926,17 +1291,17 @@ void wm_init_cursor_data(void) 8, 8, /* big */ - NULL, - NULL, + hand_lbm, + hand_lmsk, 32, 32, - 15, - 15, - /* can invert color */ - true, + 17, + 17, + /* don't invert color */ + false, }; - BlenderCursor[BC_HANDCURSOR] = &HandCursor; + BlenderCursor[WM_CURSOR_HAND] = &HandCursor; END_CURSOR_BLOCK; @@ -944,15 +1309,39 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char nsewscroll_sbm[] = { - 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, - 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x40, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x30, 0x06, 0x60, 0x06, 0x60, 0x0c, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x02, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00, }; static char nsewscroll_smsk[] = { - 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x0c, - 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30, - 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, + 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0x40, 0x02, 0x0c, + 0x30, 0x1e, 0x78, 0x0f, 0xf0, 0x0f, 0xf8, 0x1e, 0x78, 0x0c, 0x30, + 0x40, 0x02, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, + }; + + static char nsewscroll_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, + 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x38, + 0x1c, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x02, 0xe0, + 0x00, 0x00, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x3e, + 0x3e, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00, + 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, + 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char nsewscroll_lmsk[] = { + 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f, + 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7c, + 0x3e, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x40, 0x10, 0x08, 0x02, 0xe0, 0x00, 0x00, 0x07, 0xf0, + 0x01, 0x80, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f, + 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80, + 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0x40, 0x10, + 0x08, 0x02, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, + 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, }; static BCursor NSEWScrollCursor = { @@ -961,11 +1350,11 @@ void wm_init_cursor_data(void) nsewscroll_smsk, 16, 16, - 8, - 8, + 7, + 7, /* big */ - NULL, - NULL, + nsewscroll_lbm, + nsewscroll_lmsk, 32, 32, 15, @@ -974,7 +1363,7 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_NSEW_SCROLLCURSOR] = &NSEWScrollCursor; + BlenderCursor[WM_CURSOR_NSEW_SCROLL] = &NSEWScrollCursor; END_CURSOR_BLOCK; @@ -982,15 +1371,39 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char nsscroll_sbm[] = { - 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0x70, 0x07, 0x20, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, + 0x70, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, }; static char nsscroll_smsk[] = { - 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, + 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0x70, + 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x70, 0x07, + 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, + }; + + static char nsscroll_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, + 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c, + 0x0e, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char nsscroll_lmsk[] = { + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xf8, 0x07, + 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, + 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x3e, 0x1f, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, + 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x1c, 0x0e, 0x00, 0x00, 0x3e, + 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00, + 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, }; static BCursor NSScrollCursor = { @@ -999,11 +1412,11 @@ void wm_init_cursor_data(void) nsscroll_smsk, 16, 16, - 8, - 8, + 7, + 7, /* big */ - NULL, - NULL, + nsscroll_lbm, + nsscroll_lmsk, 32, 32, 15, @@ -1012,7 +1425,7 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_NS_SCROLLCURSOR] = &NSScrollCursor; + BlenderCursor[WM_CURSOR_NS_SCROLL] = &NSScrollCursor; END_CURSOR_BLOCK; @@ -1020,15 +1433,39 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char ewscroll_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x30, 0x0e, 0x70, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, + 0x1c, 0x1c, 0x38, 0x0e, 0x70, 0x1c, 0x38, 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char ewscroll_smsk[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, - 0x30, 0x1e, 0x78, 0x1f, 0xf8, 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x7c, + 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x3e, 0x7c, 0x7c, 0x3e, 0x38, 0x1c, + 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char ewscroll_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, + 0x07, 0xe0, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xfc, 0x01, 0x80, 0x3f, 0xfe, 0x00, 0x00, 0x7f, + 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x01, 0x80, 0x3f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x07, 0xe0, + 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char ewscroll_lmsk[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x01, 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x07, 0xe0, 0x0f, 0xf8, + 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff, + 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0, + 0x1f, 0xf0, 0x07, 0xe0, 0x0f, 0xe0, 0x03, 0xc0, 0x07, 0xc0, 0x01, 0x80, 0x03, 0x80, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static BCursor EWScrollCursor = { @@ -1037,11 +1474,11 @@ void wm_init_cursor_data(void) ewscroll_smsk, 16, 16, - 8, - 8, + 7, + 7, /* big */ - NULL, - NULL, + ewscroll_lbm, + ewscroll_lmsk, 32, 32, 15, @@ -1050,7 +1487,7 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_EW_SCROLLCURSOR] = &EWScrollCursor; + BlenderCursor[WM_CURSOR_EW_SCROLL] = &EWScrollCursor; END_CURSOR_BLOCK; @@ -1058,15 +1495,39 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char eyedropper_sbm[] = { - 0x00, 0x30, 0x00, 0x48, 0x00, 0x85, 0x80, 0x82, 0x40, 0x40, 0x80, - 0x20, 0x40, 0x11, 0xa0, 0x23, 0xd0, 0x15, 0xe8, 0x0a, 0x74, 0x01, - 0xb4, 0x00, 0x4a, 0x00, 0x35, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x17, 0x00, + 0x0e, 0x00, 0x1d, 0x80, 0x0b, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, + 0x38, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, }; static char eyedropper_smsk[] = { - 0x00, 0x30, 0x00, 0x78, 0x00, 0xfd, 0x80, 0xff, 0xc0, 0x7f, 0x80, - 0x3f, 0xc0, 0x1f, 0xe0, 0x3f, 0xf0, 0x1f, 0xf8, 0x0b, 0xfc, 0x01, - 0xfc, 0x00, 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00, + 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfa, 0x00, 0x7f, 0x80, 0x3f, 0x00, + 0x1f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x0b, 0xf0, 0x01, 0xf8, 0x00, + 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00, + }; + + static char eyedropper_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x7f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00, + 0xee, 0x1f, 0x00, 0x00, 0xdf, 0x0f, 0x00, 0x00, 0xbf, 0x07, 0x00, 0x00, 0x7e, 0x03, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x80, 0xf7, 0x03, 0x00, 0xc0, 0xef, 0x01, + 0x00, 0xe0, 0xcf, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0xdc, 0x01, + 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, 0x3b, 0x00, 0x00, 0xc0, 0x1d, + 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xf8, + 0x01, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char eyedropper_lmsk[] = { + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, + 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, + 0xff, 0x3f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, + 0x00, 0xff, 0x03, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0x03, + 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xcf, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, + 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, + 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfc, + 0x03, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, }; static BCursor EyedropperCursor = { @@ -1075,108 +1536,134 @@ void wm_init_cursor_data(void) eyedropper_smsk, 16, 16, - 1, + 0, 15, /* big */ - NULL, - NULL, + eyedropper_lbm, + eyedropper_lmsk, 32, 32, - 15, - 15, - /* can invert color */ - true, + 1, + 30, + /* don't invert color */ + false, }; - BlenderCursor[BC_EYEDROPPER_CURSOR] = &EyedropperCursor; + BlenderCursor[WM_CURSOR_EYEDROPPER] = &EyedropperCursor; END_CURSOR_BLOCK; /********************** Swap Area Cursor ***********************/ BEGIN_CURSOR_BLOCK; static char swap_sbm[] = { - 0xc0, 0xff, 0x40, 0x80, 0x40, 0x80, 0x40, 0x9c, 0x40, 0x98, 0x40, - 0x94, 0x00, 0x82, 0xfe, 0x80, 0x7e, 0xfd, 0xbe, 0x01, 0xda, 0x01, + 0xc0, 0xff, 0x40, 0x80, 0x40, 0xbc, 0x40, 0xb8, 0x40, 0xb8, 0x40, + 0xa4, 0x00, 0x82, 0xfe, 0x81, 0x7e, 0x81, 0xbe, 0xfd, 0xda, 0x01, 0xe2, 0x01, 0xe2, 0x01, 0xc2, 0x01, 0xfe, 0x01, 0x00, 0x00, }; static char swap_smsk[] = { 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, }; + static char swap_lbm[] = { + 0x00, 0xe0, 0xff, 0xff, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0xf8, + 0x9f, 0x00, 0x20, 0xf0, 0x9f, 0x00, 0x20, 0xe0, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20, + 0x80, 0x9f, 0x00, 0x20, 0xc0, 0x9f, 0x00, 0x20, 0xe0, 0x9e, 0x00, 0x20, 0x70, 0x9c, 0x00, + 0x20, 0x38, 0x98, 0x00, 0x20, 0x1c, 0x90, 0x00, 0x00, 0x0e, 0x80, 0xfe, 0xff, 0x07, 0x80, + 0xfe, 0x7f, 0x03, 0x80, 0xfe, 0x3f, 0x02, 0x80, 0xfe, 0x1f, 0x03, 0x80, 0xfe, 0x8f, 0xfb, + 0xff, 0xf6, 0xc7, 0x03, 0x00, 0xe6, 0xe3, 0x03, 0x00, 0xc6, 0xf1, 0x03, 0x00, 0x86, 0xf8, + 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06, 0xfe, 0x03, 0x00, 0x06, 0xfc, 0x03, 0x00, 0x06, + 0xf8, 0x03, 0x00, 0x06, 0xf0, 0x03, 0x00, 0x06, 0xe0, 0x03, 0x00, 0xfe, 0xff, 0x03, 0x00, + 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static char swap_lmsk[] = { + 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, + 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, + 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, + 0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, + 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, + 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, + 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, + }; + static BCursor SwapCursor = { /* small */ swap_sbm, swap_smsk, 16, 16, - 8, - 8, + 7, + 7, /* big */ - NULL, - NULL, + swap_lbm, + swap_lmsk, 32, 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, }; - BlenderCursor[BC_SWAPAREA_CURSOR] = &SwapCursor; + BlenderCursor[WM_CURSOR_SWAP_AREA] = &SwapCursor; END_CURSOR_BLOCK; - /********************** Horizontal Split Cursor ***********************/ + /********************** Vertical Split Cursor ***********************/ BEGIN_CURSOR_BLOCK; - static char hsplit_sbm[] = { - 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88, - 0x08, 0x8C, 0x18, 0x8E, 0x38, 0x8C, 0x18, 0x88, 0x08, 0x80, 0x00, - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + static char vsplit_sbm[] = { + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x88, + 0x11, 0x8c, 0x31, 0x86, 0x61, 0x86, 0x61, 0x8c, 0x31, 0x88, 0x11, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, }; - static char hsplit_smsk[] = { - 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xD0, 0x05, 0xD8, 0x0D, 0xDC, - 0x1D, 0xDE, 0x3D, 0xDF, 0x7D, 0xDE, 0x3D, 0xDC, 0x1D, 0xD8, 0x0D, - 0xD0, 0x05, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0x00, 0x00, + static char vsplit_smsk[] = { + 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc8, 0x13, 0xdc, + 0x3b, 0xde, 0x7b, 0xcf, 0xf3, 0xcf, 0xf3, 0xde, 0x7b, 0xdc, 0x3b, + 0xc8, 0x13, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, }; - static char hsplit_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, - 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x84, 0x21, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80, - 0x87, 0xE1, 0x01, 0xC0, 0x87, 0xE1, 0x03, 0xE0, 0x87, 0xE1, 0x07, 0xF0, 0x87, 0xE1, 0x0F, - 0xF8, 0x87, 0xE1, 0x1F, 0xF0, 0x87, 0xE1, 0x0F, 0xE0, 0x87, 0xE1, 0x07, 0xC0, 0x87, 0xE1, - 0x03, 0x80, 0x87, 0xE1, 0x01, 0x00, 0x87, 0xE1, 0x00, 0x00, 0x86, 0x61, 0x00, 0x00, 0x84, - 0x21, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static char vsplit_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, + 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, + 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x80, 0x38, 0x1c, 0x01, 0xc0, 0x39, 0x9c, 0x03, 0xe0, + 0x3b, 0xdc, 0x07, 0xf0, 0x39, 0x9c, 0x0f, 0xf8, 0x38, 0x1c, 0x1f, 0x7c, 0x38, 0x1c, 0x3e, + 0x3e, 0x38, 0x1c, 0x7c, 0x3e, 0x38, 0x1c, 0x7c, 0x7c, 0x38, 0x1c, 0x3e, 0xf8, 0x38, 0x1c, + 0x1f, 0xf0, 0x39, 0x9c, 0x0f, 0xe0, 0x3b, 0xdc, 0x07, 0xc0, 0x39, 0x9c, 0x03, 0x80, 0x38, + 0x1c, 0x01, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, + 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + }; - static char hsplit_lmsk[] = { - 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, - 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xCE, - 0x73, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x80, 0xCF, 0xF3, 0x01, 0xC0, 0xCF, 0xF3, 0x03, 0xE0, - 0xCF, 0xF3, 0x07, 0xF0, 0xCF, 0xF3, 0x0F, 0xF8, 0xCF, 0xF3, 0x1F, 0xFC, 0xCF, 0xF3, 0x3F, - 0xFE, 0xCF, 0xF3, 0x7F, 0xFC, 0xCF, 0xF3, 0x3F, 0xF8, 0xCF, 0xF3, 0x1F, 0xF0, 0xCF, 0xF3, - 0x0F, 0xE0, 0xCF, 0xF3, 0x07, 0xC0, 0xCF, 0xF3, 0x03, 0x80, 0xCF, 0xF3, 0x01, 0x00, 0xCF, - 0xF3, 0x00, 0x00, 0xCE, 0x73, 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0xC8, 0x13, 0x00, 0x00, - 0xC8, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, - 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; + static char vsplit_lmsk[] = { + 0x00, 0x18, 0x18, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, + 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, + 0x1e, 0x00, 0x80, 0x78, 0x1e, 0x01, 0xc0, 0x79, 0x9e, 0x03, 0xe0, 0x7b, 0xde, 0x07, 0xf0, + 0x7f, 0xfe, 0x0f, 0xf8, 0x7b, 0xde, 0x1f, 0xfc, 0x79, 0x9e, 0x3f, 0xfe, 0x78, 0x1e, 0x7f, + 0x7f, 0x78, 0x1e, 0xfe, 0x7f, 0x78, 0x1e, 0xfe, 0xfe, 0x78, 0x1e, 0x7f, 0xfc, 0x79, 0x9e, + 0x3f, 0xf8, 0x7b, 0xde, 0x1f, 0xf0, 0x7f, 0xfe, 0x0f, 0xe0, 0x7b, 0xde, 0x07, 0xc0, 0x79, + 0x9e, 0x03, 0x80, 0x78, 0x1e, 0x01, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, + 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, 0x00, 0x78, 0x1e, 0x00, + 0x00, 0x38, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x00, + }; - static BCursor HSplitCursor = { + static BCursor VSplitCursor = { /* small */ - hsplit_sbm, - hsplit_smsk, + vsplit_sbm, + vsplit_smsk, 16, 16, 7, 7, /* big */ - hsplit_lbm, - hsplit_lmsk, + vsplit_lbm, + vsplit_lmsk, 32, 32, 15, @@ -1185,58 +1672,60 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_H_SPLITCURSOR] = &HSplitCursor; + BlenderCursor[WM_CURSOR_V_SPLIT] = &VSplitCursor; END_CURSOR_BLOCK; - /********************** Vertical Split Cursor ***********************/ + /********************** Horizontal Split Cursor ***********************/ BEGIN_CURSOR_BLOCK; - static char vsplit_sbm[] = { - 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + static char hsplit_sbm[] = { + 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x06, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00, }; - static char vsplit_smsk[] = { - 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0x00, - 0x00, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0x00, 0x00, 0xF8, 0x0F, - 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, + static char hsplit_smsk[] = { + 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0x60, 0x06, 0x01, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, + 0x60, 0x06, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, }; - static char vsplit_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, - 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, - 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, - 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static char hsplit_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, + 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0x3e, + 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, + 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x10, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, + 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xc0, 0x03, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; - static char vsplit_lmsk[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, - 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, - 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, - 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, - 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, - 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, - 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static char hsplit_lmsk[] = { + 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x0f, + 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x7f, + 0xfe, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x08, 0x10, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x10, 0x00, 0x00, 0x1c, + 0x38, 0x00, 0x00, 0x3e, 0x7c, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, + 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, + }; - static BCursor VSplitCursor = { + static BCursor HSplitCursor = { /* small */ - vsplit_sbm, - vsplit_smsk, + hsplit_sbm, + hsplit_smsk, 16, 16, 7, 7, /* big */ - vsplit_lbm, - vsplit_lmsk, + hsplit_lbm, + hsplit_lmsk, 32, 32, 15, @@ -1245,7 +1734,7 @@ void wm_init_cursor_data(void) true, }; - BlenderCursor[BC_V_SPLITCURSOR] = &VSplitCursor; + BlenderCursor[WM_CURSOR_H_SPLIT] = &HSplitCursor; END_CURSOR_BLOCK; @@ -1253,38 +1742,40 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char narrow_sbm[] = { - 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, - 0x0F, 0xFC, 0x1F, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, + 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, + 0x0f, 0x7c, 0x1f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char narrow_smsk[] = { - 0x80, 0x00, 0xC0, 0x01, 0xE0, 0x03, 0xF0, 0x07, 0xF8, 0x0F, 0xFC, - 0x1F, 0xFE, 0x3F, 0xFF, 0x7F, 0xF0, 0x07, 0xF0, 0x07, 0xF0, 0x07, - 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, + 0x1f, 0xfe, 0x3f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char narrow_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, - 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, - 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F, - 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, - 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, - 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, + 0x7f, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xfe, 0x03, 0xc0, + 0x7f, 0xfc, 0x07, 0xe0, 0x3f, 0xf8, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf8, 0x0f, 0xe0, 0x3f, + 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00, 0x1f, 0xe0, 0x00, 0x00, + 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char narrow_lmsk[] = { - 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF0, 0x07, - 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFF, - 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, - 0xFF, 0xFF, 0x07, 0xF8, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x3F, - 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, - 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, - 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f, + 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0xfe, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x07, 0xe0, + 0xff, 0xfe, 0x0f, 0xf0, 0x7f, 0xfc, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf0, 0x7f, + 0xfe, 0x0f, 0xe0, 0xff, 0xfc, 0x07, 0xc0, 0x7f, 0xf8, 0x03, 0x80, 0x3f, 0xf0, 0x01, 0x00, + 0x1f, 0xe0, 0x00, 0x00, 0x0e, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static BCursor NArrowCursor = { /* small */ @@ -1293,19 +1784,19 @@ void wm_init_cursor_data(void) 16, 16, 7, - 4, + 5, /* big */ narrow_lbm, narrow_lmsk, 32, 32, - 15, - 10, + 16, + 12, /* can invert color */ true, }; - BlenderCursor[BC_N_ARROWCURSOR] = &NArrowCursor; + BlenderCursor[WM_CURSOR_N_ARROW] = &NArrowCursor; END_CURSOR_BLOCK; @@ -1313,38 +1804,40 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char sarrow_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, - 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xFC, 0x1F, 0xF8, 0x0F, - 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7c, 0x1f, 0xf8, 0x0f, + 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, }; static char sarrow_smsk[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0, - 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xFF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, - 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0xfe, 0x3f, 0xfc, 0x1f, + 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, }; static char sarrow_lbm[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, - 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, - 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, - 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF, - 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, - 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, + 0xfc, 0x01, 0xc0, 0x1f, 0xfe, 0x03, 0xe0, 0x3f, 0xfc, 0x07, 0xf0, 0x1f, 0xf8, 0x0f, 0xf8, + 0x0f, 0xf0, 0x1f, 0xfc, 0x07, 0xe0, 0x3f, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0x01, 0x80, 0xff, + 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, + 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char sarrow_lmsk[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, - 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, - 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x00, - 0x00, 0xFE, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, - 0x1F, 0xF8, 0xFF, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, - 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, - 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, - 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x80, 0x0f, 0xfc, 0x01, 0xc0, 0x1f, + 0xfe, 0x03, 0xe0, 0x3f, 0xff, 0x07, 0xf0, 0x7f, 0xfe, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xfc, + 0x1f, 0xf8, 0x3f, 0xfe, 0x0f, 0xf0, 0x7f, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff, + 0xff, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, + 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + }; static BCursor SArrowCursor = { /* small */ @@ -1353,19 +1846,19 @@ void wm_init_cursor_data(void) 16, 16, 7, - 11, + 10, /* big */ sarrow_lbm, sarrow_lmsk, 32, 32, 15, - 21, + 18, /* can invert color */ true, }; - BlenderCursor[BC_S_ARROWCURSOR] = &SArrowCursor; + BlenderCursor[WM_CURSOR_S_ARROW] = &SArrowCursor; END_CURSOR_BLOCK; @@ -1373,38 +1866,40 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char earrow_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0xE0, - 0x1F, 0xE0, 0x3F, 0xE0, 0x7F, 0xE0, 0x3F, 0xE0, 0x1F, 0x00, 0x0E, - 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x0f, 0x00, + 0x1f, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x1f, 0x80, 0x0f, + 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, }; static char earrow_smsk[] = { - 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0F, 0xF0, 0x1F, 0xF0, - 0x3F, 0xF0, 0x7F, 0xF0, 0xFF, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x1F, - 0x00, 0x0F, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x1f, 0x80, + 0x3f, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0x7f, 0x80, 0x3f, 0xc0, 0x1f, + 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, }; static char earrow_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, - 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x1F, - 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, - 0x07, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, - 0x7E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, + 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, + 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, + 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, + 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, + 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, + 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char earrow_lmsk[] = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0F, - 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x07, 0x80, - 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x7F, - 0x80, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x7F, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, - 0x1F, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0x00, - 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, - 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f, + 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, + 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, + 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf0, 0x7f, + 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, + 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, + 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, + 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static BCursor EArrowCursor = { /* small */ @@ -1412,20 +1907,20 @@ void wm_init_cursor_data(void) earrow_smsk, 16, 16, - 11, + 10, 7, /* big */ earrow_lbm, earrow_lmsk, 32, 32, + 18, 15, - 22, /* can invert color */ true, }; - BlenderCursor[BC_E_ARROWCURSOR] = &EArrowCursor; + BlenderCursor[WM_CURSOR_E_ARROW] = &EArrowCursor; END_CURSOR_BLOCK; @@ -1433,38 +1928,40 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char warrow_sbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0xF8, - 0x07, 0xFC, 0x07, 0xFE, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x00, - 0x60, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x01, 0xf8, + 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x01, + 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; static char warrow_smsk[] = { - 0x80, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, - 0x0F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFE, 0x0F, 0xFC, 0x0F, 0xF8, 0x0F, - 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x80, 0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x03, 0xfc, + 0x01, 0xfe, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0xfc, 0x01, 0xf8, 0x03, + 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, }; static char warrow_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, - 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7C, - 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xC0, - 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00, - 0xFC, 0xFF, 0xFF, 0x00, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, - 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7E, - 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, + 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xfe, + 0x03, 0x00, 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, + 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, + 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, + 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, + 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char warrow_lmsk[] = { - 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00, - 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xF0, - 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, 0xFC, 0xFF, 0xFF, 0x01, 0xF8, 0xFF, 0xFF, - 0x01, 0xF0, 0xFF, 0xFF, 0x01, 0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x01, 0x80, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, - 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, + 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xff, + 0x07, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xf0, + 0x7f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, + 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x3f, 0x00, + 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x80, 0xff, + 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, + 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static BCursor WArrowCursor = { /* small */ @@ -1472,20 +1969,20 @@ void wm_init_cursor_data(void) warrow_smsk, 16, 16, - 4, + 5, 7, /* big */ warrow_lbm, warrow_lmsk, 32, 32, - 15, + 18, 15, /* can invert color */ true, }; - BlenderCursor[BC_W_ARROWCURSOR] = &WArrowCursor; + BlenderCursor[WM_CURSOR_W_ARROW] = &WArrowCursor; END_CURSOR_BLOCK; @@ -1493,38 +1990,40 @@ void wm_init_cursor_data(void) BEGIN_CURSOR_BLOCK; static char stop_sbm[] = { - 0x00, 0x00, 0xE0, 0x07, 0x38, 0x1C, 0x1C, 0x30, 0x3C, 0x20, 0x76, - 0x60, 0xE2, 0x40, 0xC2, 0x41, 0x82, 0x43, 0x02, 0x47, 0x06, 0x6E, - 0x04, 0x3C, 0x0C, 0x38, 0x38, 0x1C, 0xE0, 0x07, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x07, 0xf8, 0x1f, 0x1c, 0x3c, 0x3c, 0x30, 0x76, + 0x70, 0xe6, 0x60, 0xc6, 0x61, 0x86, 0x63, 0x06, 0x67, 0x0e, 0x6e, + 0x0c, 0x3c, 0x3c, 0x38, 0xf8, 0x1f, 0xe0, 0x07, 0x00, 0x00, }; static char stop_smsk[] = { - 0xE0, 0x07, 0xF8, 0x1F, 0xFC, 0x3F, 0x3E, 0x7C, 0x7E, 0x70, 0xFF, - 0xF0, 0xF7, 0xE1, 0xE7, 0xE3, 0xC7, 0xE7, 0x87, 0xEF, 0x0F, 0xFF, - 0x0E, 0x7E, 0x3E, 0x7C, 0xFC, 0x3F, 0xF8, 0x1F, 0xE0, 0x07, + 0xe0, 0x07, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0x7e, 0x7c, 0xff, + 0xf8, 0xff, 0xf1, 0xef, 0xf3, 0xcf, 0xf7, 0x8f, 0xff, 0x1f, 0xff, + 0x3e, 0x7e, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xe0, 0x07, }; static char stop_lbm[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x0F, 0xF0, - 0x00, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x01, 0x00, 0x07, 0xF0, 0x01, 0x00, 0x0E, 0xF0, 0x01, - 0x00, 0x0C, 0xF8, 0x03, 0x00, 0x18, 0x1C, 0x07, 0x00, 0x38, 0x0C, 0x0E, 0x00, 0x30, 0x0C, - 0x1C, 0x00, 0x30, 0x06, 0x38, 0x00, 0x60, 0x06, 0x70, 0x00, 0x60, 0x06, 0xE0, 0x00, 0x60, - 0x06, 0xC0, 0x01, 0x60, 0x06, 0x80, 0x03, 0x60, 0x06, 0x00, 0x07, 0x60, 0x06, 0x00, 0x0E, - 0x60, 0x06, 0x00, 0x1C, 0x60, 0x0C, 0x00, 0x38, 0x30, 0x0C, 0x00, 0x70, 0x30, 0x1C, 0x00, - 0xE0, 0x38, 0x18, 0x00, 0xC0, 0x1F, 0x30, 0x00, 0x80, 0x0F, 0x70, 0x00, 0x80, 0x0F, 0xE0, - 0x00, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x7F, 0x00, - 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, + 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0xe0, 0x03, 0xc0, 0x07, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0x03, + 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x1e, 0xbc, 0x0f, 0x00, 0x3c, 0x1c, 0x1f, 0x00, 0x38, 0x1c, + 0x3e, 0x00, 0x38, 0x1e, 0x7c, 0x00, 0x78, 0x0e, 0xf8, 0x00, 0x70, 0x0e, 0xf0, 0x01, 0x70, + 0x0e, 0xe0, 0x03, 0x70, 0x0e, 0xc0, 0x07, 0x70, 0x0e, 0x80, 0x0f, 0x70, 0x0e, 0x00, 0x1f, + 0x70, 0x1e, 0x00, 0x3e, 0x78, 0x1c, 0x00, 0x7c, 0x38, 0x1c, 0x00, 0xf8, 0x38, 0x3c, 0x00, + 0xf0, 0x3d, 0x78, 0x00, 0xe0, 0x1f, 0xf0, 0x00, 0xc0, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xe0, + 0x03, 0xc0, 0x07, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, + 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + }; static char stop_lmsk[] = { - 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, - 0x03, 0xE0, 0x1F, 0xF8, 0x07, 0xF0, 0x03, 0xC0, 0x0F, 0xF8, 0x03, 0x80, 0x1F, 0xFC, 0x07, - 0x00, 0x3F, 0xFC, 0x0F, 0x00, 0x3E, 0xFE, 0x1F, 0x00, 0x7C, 0x9E, 0x3F, 0x00, 0x78, 0x1E, - 0x7F, 0x00, 0x78, 0x1F, 0xFE, 0x00, 0xF8, 0x0F, 0xFC, 0x01, 0xF0, 0x0F, 0xF8, 0x03, 0xF0, - 0x0F, 0xF0, 0x07, 0xF0, 0x0F, 0xE0, 0x0F, 0xF0, 0x0F, 0xC0, 0x1F, 0xF0, 0x0F, 0x80, 0x3F, - 0xF0, 0x1F, 0x00, 0x7F, 0xF8, 0x1E, 0x00, 0xFE, 0x78, 0x1E, 0x00, 0xFC, 0x79, 0x3E, 0x00, - 0xF8, 0x7F, 0x7C, 0x00, 0xF0, 0x3F, 0xFC, 0x00, 0xE0, 0x3F, 0xF8, 0x01, 0xC0, 0x1F, 0xF0, - 0x03, 0xC0, 0x0F, 0xE0, 0x1F, 0xF8, 0x07, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x01, - 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xF0, 0x0F, 0x00}; + 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, + 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0x3f, 0xfc, 0x1f, 0xf8, 0x07, 0xe0, 0x1f, 0xfc, 0x0f, + 0xc0, 0x3f, 0xfe, 0x1f, 0x80, 0x7f, 0xfe, 0x3f, 0x00, 0x7f, 0xfe, 0x7f, 0x00, 0x7e, 0xbf, + 0xff, 0x00, 0xfc, 0x3f, 0xff, 0x01, 0xfc, 0x3f, 0xfe, 0x03, 0xfc, 0x1f, 0xfc, 0x07, 0xf8, + 0x1f, 0xf8, 0x0f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf8, 0x1f, 0xe0, 0x3f, 0xf8, 0x3f, 0xc0, 0x7f, + 0xfc, 0x3f, 0x80, 0xff, 0xfc, 0x3f, 0x00, 0xff, 0xfd, 0x7e, 0x00, 0xfe, 0x7f, 0xfe, 0x00, + 0xfc, 0x7f, 0xfe, 0x01, 0xf8, 0x7f, 0xfc, 0x03, 0xf0, 0x3f, 0xf8, 0x07, 0xe0, 0x1f, 0xf8, + 0x3f, 0xfc, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x01, + 0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0x00, + }; static BCursor StopCursor = { /* small */ @@ -1541,11 +2040,135 @@ void wm_init_cursor_data(void) 32, 15, 15, - /* can invert color */ - true, + /* don't invert color */ + false, + }; + + BlenderCursor[WM_CURSOR_STOP] = &StopCursor; + + END_CURSOR_BLOCK; + + /********************** Zoom In Cursor ***********************/ + BEGIN_CURSOR_BLOCK; + + static char zoomin_sbm[] = { + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xb8, 0x03, 0xbc, + 0x07, 0x0c, 0x06, 0xbc, 0x07, 0xb8, 0x03, 0xf8, 0x0b, 0xe0, 0x14, + 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60, + }; + + static char zoomin_smsk[] = { + 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe, + 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f, + 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60, + }; + + static char zoomin_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, + 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xe7, + 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0x7e, + 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xe7, 0x7f, 0x00, 0xfe, 0xe7, 0x7f, 0x00, + 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xe7, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f, + 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e, + 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, + 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82, + 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38, + }; + + static char zoomin_lmsk[] = { + 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f, + 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, + 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, + 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, + 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, + 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38, + }; + + static BCursor ZoomInCursor = { + /* small */ + zoomin_sbm, + zoomin_smsk, + 16, + 16, + 6, + 6, + /* big */ + zoomin_lbm, + zoomin_lmsk, + 32, + 32, + 11, + 11, + /* don't invert color */ + false, + }; + + BlenderCursor[WM_CURSOR_ZOOM_IN] = &ZoomInCursor; + + END_CURSOR_BLOCK; + + /********************** Zoom Out Cursor ***********************/ + BEGIN_CURSOR_BLOCK; + + static char zoomout_sbm[] = { + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xf8, 0x03, 0xfc, + 0x07, 0x0c, 0x06, 0xfc, 0x07, 0xf8, 0x03, 0xf8, 0x0b, 0xe0, 0x14, + 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x00, 0x90, 0x00, 0x60, + }; + + static char zoomout_smsk[] = { + 0x00, 0x00, 0xe0, 0x00, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07, 0xfe, + 0x0f, 0xfe, 0x0f, 0xfe, 0x0f, 0xfc, 0x07, 0xfc, 0x0f, 0xf8, 0x1f, + 0xe0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0x60, + }; + + static char zoomout_lbm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, + 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xf8, 0xff, 0x1f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, + 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x7e, + 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, + 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x5f, + 0x00, 0xf8, 0xff, 0x9f, 0x00, 0xf0, 0xff, 0x0f, 0x01, 0xc0, 0xff, 0x03, 0x02, 0x00, 0x7e, + 0x04, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x20, 0x00, + 0x00, 0x40, 0x40, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82, + 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x38, + }; + + static char zoomout_lmsk[] = { + 0x00, 0x7e, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x1f, + 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, + 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0x7f, + 0x00, 0xfc, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xc0, 0xff, + 0xff, 0x07, 0x00, 0x7e, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00, + 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x38, + }; + + static BCursor ZoomOutCursor = { + /* small */ + zoomout_sbm, + zoomout_smsk, + 16, + 16, + 6, + 6, + /* big */ + zoomout_lbm, + zoomout_lmsk, + 32, + 32, + 11, + 11, + /* don't invert color */ + false, }; - BlenderCursor[BC_STOPCURSOR] = &StopCursor; + BlenderCursor[WM_CURSOR_ZOOM_OUT] = &ZoomOutCursor; END_CURSOR_BLOCK; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index ba6a0c4ebe1..901594850dd 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -265,7 +265,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e if (opname) { BLI_strncpy(drag->opname, opname, sizeof(drag->opname)); - // WM_cursor_modal_set(win, CURSOR_COPY); + // WM_cursor_modal_set(win, WM_CURSOR_COPY); } // else // WM_cursor_modal_restore(win); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 77672e04030..a744cfb8c28 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -58,6 +58,8 @@ #include "BKE_sound.h" +#include "BLT_translation.h" + #include "ED_fileselect.h" #include "ED_info.h" #include "ED_screen.h" @@ -2336,22 +2338,22 @@ static int wm_handler_fileselect_do(bContext *C, int val) { wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile; int action = WM_HANDLER_CONTINUE; switch (val) { case EVT_FILESELECT_FULL_OPEN: { wmWindow *win = CTX_wm_window(C); - const int sizex = 1020 * UI_DPI_FAC; - const int sizey = 600 * UI_DPI_FAC; - - if (WM_window_open_temp(C, - WM_window_pixels_x(win) / 2, - WM_window_pixels_y(win) / 2, - sizex, - sizey, - WM_WINDOW_FILESEL) != NULL) { - ScrArea *area = CTX_wm_area(C); + ScrArea *area; + + if ((area = ED_screen_temp_space_open(C, + IFACE_("Blender File View"), + WM_window_pixels_x(win) / 2, + WM_window_pixels_y(win) / 2, + U.file_space_data.temp_win_sizex * UI_DPI_FAC, + U.file_space_data.temp_win_sizey * UI_DPI_FAC, + SPACE_FILE, + U.filebrowser_display_type, + true))) { ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); BLI_assert(area->spacetype == SPACE_FILE); @@ -2361,10 +2363,10 @@ static int wm_handler_fileselect_do(bContext *C, region_header->alignment = RGN_ALIGN_BOTTOM; /* settings for filebrowser, sfile is not operator owner but sends events */ - sfile = (SpaceFile *)area->spacedata.first; + SpaceFile *sfile = (SpaceFile *)area->spacedata.first; sfile->op = handler->op; - ED_fileselect_set_params(sfile); + ED_fileselect_set_params_from_userdef(sfile); } else { BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!"); @@ -2390,17 +2392,27 @@ static int wm_handler_fileselect_do(bContext *C, } } else { - for (wmWindow *win = wm->windows.first; win; win = win->next) { - if (WM_window_is_temp_screen(win)) { - bScreen *screen = WM_window_get_active_screen(win); - ScrArea *file_sa = screen->areabase.first; + wmWindow *temp_win; + ScrArea *ctx_sa = CTX_wm_area(C); + + for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) { + bScreen *screen = WM_window_get_active_screen(temp_win); + ScrArea *file_sa = screen->areabase.first; + + if (screen->temp && (file_sa->spacetype == SPACE_FILE)) { + int win_size[2]; - BLI_assert(file_sa->spacetype == SPACE_FILE); + /* Get DPI/pixelsize independent size to be stored in preferences. */ + WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */ + win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC; + win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC; + + ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size); if (BLI_listbase_is_single(&file_sa->spacedata)) { - BLI_assert(ctx_win != win); + BLI_assert(ctx_win != temp_win); - wm_window_close(C, wm, win); + wm_window_close(C, wm, temp_win); CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs. /* Some operators expect a drawable context (for EVT_FILESELECT_EXEC) */ @@ -2409,7 +2421,7 @@ static int wm_handler_fileselect_do(bContext *C, * opening (UI_BLOCK_MOVEMOUSE_QUIT) */ wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); wm->winactive = ctx_win; /* Reports use this... */ - if (handler->context.win == win) { + if (handler->context.win == temp_win) { handler->context.win = NULL; } } @@ -2423,6 +2435,11 @@ static int wm_handler_fileselect_do(bContext *C, break; } } + + if (!temp_win && ctx_sa->full) { + ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL); + ED_screen_full_prevspace(C, ctx_sa); + } } wm_handler_op_context(C, handler, ctx_win->eventstate); @@ -2721,7 +2738,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers /* Clear the tool-tip whenever a key binding is handled, without this tool-tips * are kept when a modal operators starts (annoying but otherwise harmless). */ if (action & WM_HANDLER_BREAK) { - WM_tooltip_clear(C, CTX_wm_window(C)); + /* Window may be gone after file read. */ + if (CTX_wm_window(C) != NULL) { + WM_tooltip_clear(C, CTX_wm_window(C)); + } } } else if (handler_base->type == WM_HANDLER_TYPE_UI) { @@ -3536,15 +3556,52 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - /* Don't add the file handler to the temporary window, or else it owns the handlers for itself, - * causing dangling pointers once it's destructed through a handler. It has a parent which should - * hold the handlers itself. */ - ListBase *modalhandlers = WM_window_is_temp_screen(win) ? &win->parent->modalhandlers : - &win->modalhandlers; + const bool is_temp_screen = WM_window_is_temp_screen(win); + const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW); + /* Don't add the file handler to the temporary window if one is opened, or else it owns the + * handlers for itself, causing dangling pointers once it's destructed through a handler. It has + * a parent which should hold the handlers itself. */ + ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers : + &win->modalhandlers; /* Close any popups, like when opening a file browser from the splash. */ UI_popup_handlers_remove_all(C, modalhandlers); + if (!is_temp_screen) { + /* only allow 1 file selector open per window */ + LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) { + if (handler_base->type == WM_HANDLER_TYPE_OP) { + wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; + if (handler->is_fileselect == false) { + continue; + } + bScreen *screen = CTX_wm_screen(C); + bool cancel_handler = true; + + /* find the area with the file selector for this handler */ + ED_screen_areas_iter(win, screen, sa) + { + if (sa->spacetype == SPACE_FILE) { + SpaceFile *sfile = sa->spacedata.first; + + if (sfile->op == handler->op) { + CTX_wm_area_set(C, sa); + wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL); + cancel_handler = false; + break; + } + } + } + + /* if not found we stop the handler without changing the screen */ + if (cancel_handler) { + wm_handler_fileselect_do( + C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL); + } + } + } + } + wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__); handler->head.type = WM_HANDLER_TYPE_OP; @@ -4157,19 +4214,31 @@ static void wm_eventemulation(wmEvent *event, bool test_only) if (U.flag & USER_TWOBUTTONMOUSE) { if (event->type == LEFTMOUSE) { - if (event->val == KM_PRESS && event->alt) { - event->type = MIDDLEMOUSE; - event->alt = 0; + short *mod = ( +#if !defined(WIN32) + (U.mouse_emulate_3_button_modifier == USER_EMU_MMB_MOD_OSKEY) ? &event->oskey : + &event->alt +#else + /* Disable for WIN32 for now because it accesses the start menu. */ + &event->alt +#endif + ); - if (!test_only) { - emulating_event = MIDDLEMOUSE; + if (event->val == KM_PRESS) { + if (*mod) { + *mod = 0; + event->type = MIDDLEMOUSE; + + if (!test_only) { + emulating_event = MIDDLEMOUSE; + } } } else if (event->val == KM_RELEASE) { /* only send middle-mouse release if emulated */ if (emulating_event == MIDDLEMOUSE) { event->type = MIDDLEMOUSE; - event->alt = 0; + *mod = 0; } if (!test_only) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 561300ab7b9..f96a8c3d7fd 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2515,7 +2515,7 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, - FILE_HORIZONTALDISPLAY, + FILE_VERTICALDISPLAY, FILE_SORT_TIME); } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index ce2319e0394..3374d17cbfd 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -575,7 +575,7 @@ void WM_OT_link(wmOperatorType *ot) FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | - WM_FILESEL_RELPATH | WM_FILESEL_FILES, + WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); @@ -599,7 +599,7 @@ void WM_OT_append(wmOperatorType *ot) FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | - WM_FILESEL_FILES, + WM_FILESEL_FILES | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 6a6861ae697..c8c35ba1bfc 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -99,6 +99,7 @@ #include "wm.h" #include "wm_files.h" #include "wm_window.h" +#include "wm_platform_support.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -314,6 +315,10 @@ void WM_init(bContext *C, int argc, const char **argv) #endif WM_init_opengl(G_MAIN); + if (!WM_platform_support_perform_checks()) { + exit(-1); + } + UI_init(); } @@ -681,3 +686,12 @@ void WM_exit(bContext *C) exit(G.is_break == true); } + +/** + * Needed for cases when operators are re-registered + * (when operator type pointers are stored). + */ +void WM_script_tag_reload(void) +{ + UI_interface_tag_script_reload(); +} diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 04775a7a880..21636153904 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -78,15 +78,6 @@ void WM_operator_properties_filesel(wmOperatorType *ot, {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem file_action_types[] = { - {FILE_OPENFILE, - "OPENFILE", - 0, - "Open", - "Use the file browser for opening files or a directory"}, - {FILE_SAVE, "SAVE", 0, "Save", "Use the file browser for saving a file"}, - {0, NULL, 0, NULL, NULL}, - }; if (flag & WM_FILESEL_FILEPATH) { RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file"); @@ -207,9 +198,6 @@ void WM_operator_properties_filesel(wmOperatorType *ot, prop = RNA_def_enum( ot->srna, "sort_method", rna_enum_file_sort_items, sort, "File sorting mode", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - prop = RNA_def_enum(ot->srna, "action_type", file_action_types, action, "Action Type", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } static void wm_operator_properties_select_action_ex(wmOperatorType *ot, @@ -408,6 +396,16 @@ void WM_operator_properties_select_operation_simple(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +void WM_operator_properties_generic_select(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "wait_to_deselect_others", false, "Wait to Deselect Others", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); +} + void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot) { WM_operator_properties_border(ot); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9657347a1c4..6bafbed9804 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -41,6 +41,7 @@ #include "CLG_log.h" #include "DNA_ID.h" +#include "DNA_brush_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" @@ -58,6 +59,7 @@ #include "BLI_utildefines.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" @@ -140,13 +142,13 @@ void WM_operator_bl_idname(char *to, const char *from) if (from) { const char *sep = strchr(from, '.'); - if (sep) { - int ofs = (sep - from); - + int from_len; + if (sep && (from_len = strlen(from)) < OP_MAX_TYPENAME - 3) { + const int ofs = (sep - from); memcpy(to, from, sizeof(char) * ofs); BLI_str_toupper_ascii(to, ofs); - strcpy(to + ofs, "_OT_"); - strcpy(to + (ofs + 4), sep + 1); + memcpy(to + ofs, "_OT_", 4); + memcpy(to + (ofs + 4), sep + 1, (from_len - ofs)); } else { /* should not happen but support just in case */ @@ -427,26 +429,16 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr } \ (void)0 -# define CTX_TEST_PTR_DATA_TYPE(C, member, rna_type, rna_ptr, dataptr_cmp) \ +# define TEST_PTR_DATA_TYPE(member, rna_type, rna_ptr, dataptr_cmp) \ { \ const char *ctx_member = member; \ - if (RNA_struct_is_a((ptr)->type, &(rna_type)) && (ptr)->data == (dataptr_cmp)) { \ + if (RNA_struct_is_a((rna_ptr)->type, &(rna_type)) && (rna_ptr)->data == (dataptr_cmp)) { \ member_id = ctx_member; \ break; \ } \ } \ (void)0 -# define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \ - { \ - const char *ctx_member_full = member_full; \ - if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \ - member_id = ctx_member_full; \ - break; \ - } \ - } \ - (void)0 - switch (GS(ptr->owner_id->name)) { case ID_SCE: { CTX_TEST_PTR_ID(C, "scene", ptr->owner_id); @@ -482,19 +474,50 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr SpaceLink *space_data = CTX_wm_space_data(C); - CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data); - CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DOverlay, ptr, space_data); - CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DShading, ptr, space_data); - CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C)); - CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C)); - - CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data); - CTX_TEST_SPACE_TYPE( - SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings)); - CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads); - CTX_TEST_SPACE_TYPE(SPACE_GRAPH, "space_data.dopesheet", CTX_wm_space_graph(C)->ads); - CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads)); - CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params); + TEST_PTR_DATA_TYPE("space_data", RNA_Space, ptr, space_data); + TEST_PTR_DATA_TYPE("area", RNA_Area, ptr, CTX_wm_area(C)); + TEST_PTR_DATA_TYPE("region", RNA_Region, ptr, CTX_wm_region(C)); + + switch (space_data->spacetype) { + case SPACE_VIEW3D: { + const View3D *v3d = (View3D *)space_data; + const View3DShading *shading = &v3d->shading; + + TEST_PTR_DATA_TYPE("space_data", RNA_View3DOverlay, ptr, v3d); + TEST_PTR_DATA_TYPE("space_data", RNA_View3DShading, ptr, shading); + break; + } + case SPACE_GRAPH: { + const SpaceGraph *sipo = (SpaceGraph *)space_data; + const bDopeSheet *ads = sipo->ads; + TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads); + break; + } + case SPACE_FILE: { + const SpaceFile *sfile = (SpaceFile *)space_data; + const FileSelectParams *params = sfile->params; + TEST_PTR_DATA_TYPE("space_data", RNA_FileSelectParams, ptr, params); + break; + } + case SPACE_IMAGE: { + const SpaceImage *sima = (SpaceImage *)space_data; + TEST_PTR_DATA_TYPE("space_data", RNA_SpaceUVEditor, ptr, sima); + break; + } + case SPACE_NLA: { + const SpaceNla *snla = (SpaceNla *)space_data; + const bDopeSheet *ads = snla->ads; + TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads); + break; + } + case SPACE_ACTION: { + const SpaceAction *sact = (SpaceAction *)space_data; + const bDopeSheet *ads = &sact->ads; + TEST_PTR_DATA_TYPE("space_data", RNA_DopeSheet, ptr, ads); + break; + } + } + break; } default: @@ -502,7 +525,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr } # undef CTX_TEST_PTR_ID # undef CTX_TEST_PTR_ID_CAST -# undef CTX_TEST_SPACE_TYPE +# undef TEST_PTR_DATA_TYPE } return member_id; @@ -698,6 +721,82 @@ void WM_operator_properties_free(PointerRNA *ptr) /** \name Default Operator Callbacks * \{ */ +int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr, + "wait_to_deselect_others"); + const short init_event_type = (short)POINTER_AS_INT(op->customdata); + int ret_value = 0; + + /* get settings from RNA properties for operator */ + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + if (init_event_type == 0) { + if (event->val == KM_PRESS) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, true); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + op->customdata = POINTER_FROM_INT((int)event->type); + if (ret_value & OPERATOR_RUNNING_MODAL) { + WM_event_add_modal_handler(C, op); + } + return ret_value | OPERATOR_PASS_THROUGH; + } + else { + /* If we are in init phase, and cannot validate init of modal operations, + * just fall back to basic exec. + */ + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + } + else if (event->type == init_event_type && event->val == KM_RELEASE) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + const int drag_delta[2] = { + mval[0] - event->mval[0], + mval[1] - event->mval[1], + }; + /* If user moves mouse more than defined threshold, we consider select operator as + * finished. Otherwise, it is still running until we get an 'release' event. In any + * case, we pass through event, but select op is not finished yet. */ + if (WM_event_drag_test_with_delta(event, drag_delta)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + else { + /* Important not to return anything other than PASS_THROUGH here, + * otherwise it prevents underlying tweak detection code to work properly. */ + return OPERATOR_PASS_THROUGH; + } + } + + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; +} + +int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + RNA_int_set(op->ptr, "mouse_x", event->mval[0]); + RNA_int_set(op->ptr, "mouse_y", event->mval[1]); + + op->customdata = POINTER_FROM_INT(0); + + return op->type->modal(C, op, event); +} + void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op) { if (op->flag & OP_IS_INVOKE) { @@ -1862,6 +1961,7 @@ typedef struct { StructRNA *image_id_srna; float initial_value, current_value, min_value, max_value; int initial_mouse[2]; + int initial_co[2]; int slow_mouse[2]; bool slow_mode; Dial *dial; @@ -1924,6 +2024,9 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e rc->initial_mouse[0] = event->x; rc->initial_mouse[1] = event->y; + rc->initial_co[0] = event->x; + rc->initial_co[1] = event->y; + switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: @@ -1935,7 +2038,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; break; case PROP_FACTOR: - d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + + d[0] = rc->initial_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; break; case PROP_ANGLE: @@ -1962,8 +2065,10 @@ static void radial_control_set_tex(RadialControl *rc) switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) { case ID_BR: - if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, - rc->use_secondary_tex))) { + if ((ibuf = BKE_brush_gen_radial_control_imbuf( + rc->image_id_ptr.data, + rc->use_secondary_tex, + !ELEM(rc->subtype, PROP_NONE, PROP_PIXEL, PROP_DISTANCE)))) { glGenTextures(1, &rc->gltex); glBindTexture(GL_TEXTURE_2D, rc->gltex); glTexImage2D( @@ -2061,6 +2166,22 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph immUnbindProgram(); } +static void radial_control_paint_curve(uint pos, Brush *br, float radius, int line_segments) +{ + GPU_line_width(2.0f); + immUniformColor4f(0.8f, 0.8f, 0.8f, 0.85f); + float step = (radius * 2.0f) / (float)line_segments; + BKE_curvemapping_initialize(br->curve); + immBegin(GPU_PRIM_LINES, line_segments * 2); + for (int i = 0; i < line_segments; i++) { + float h1 = BKE_brush_curve_strength_clamped(br, fabsf((i * step) - radius), radius); + immVertex2f(pos, -radius + (i * step), h1 * radius); + float h2 = BKE_brush_curve_strength_clamped(br, fabsf(((i + 1) * step) - radius), radius); + immVertex2f(pos, -radius + ((i + 1) * step), h2 * radius); + } + immEnd(); +} + static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata) { RadialControl *rc = customdata; @@ -2094,7 +2215,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void alpha = 0.75; break; case PROP_FACTOR: - r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + + r1 = rc->current_value * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE; rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; @@ -2115,9 +2236,17 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void break; } - /* Keep cursor in the original place */ - x = rc->initial_mouse[0]; - y = rc->initial_mouse[1]; + if (rc->subtype == PROP_ANGLE) { + /* Use the initial mouse position to draw the rotation preview. This avoids starting the + * rotation in a random direction */ + x = rc->initial_mouse[0]; + y = rc->initial_mouse[1]; + } + else { + /* Keep cursor in the original place */ + x = rc->initial_co[0]; + y = rc->initial_co[1]; + } GPU_matrix_translate_2f((float)x, (float)y); GPU_blend(true); @@ -2141,7 +2270,6 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fvAlpha(col, 0.5f); if (rc->subtype == PROP_ANGLE) { GPU_matrix_push(); @@ -2164,25 +2292,40 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void } /* draw circles on top */ - imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40); - imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40); + GPU_line_width(2.0f); + immUniformColor3fvAlpha(col, 0.8f); + imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 80); + + GPU_line_width(1.0f); + immUniformColor3fvAlpha(col, 0.5f); + imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 80); if (rmin > 0.0f) { - imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40); + /* Inner fill circle to increase the contrast of the value */ + float black[3] = {0.0f}; + immUniformColor3fvAlpha(black, 0.2f); + imm_draw_circle_fill_2d(pos, 0.0, 0.0f, rmin, 80); + + immUniformColor3fvAlpha(col, 0.5f); + imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 80); } + + /* draw curve falloff preview */ + if (RNA_type_to_ID_code(rc->image_id_ptr.type) == ID_BR && rc->subtype == PROP_FACTOR) { + Brush *br = rc->image_id_ptr.data; + if (br) { + radial_control_paint_curve(pos, br, r2, 120); + } + } + immUnbindProgram(); - BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi); - BLF_enable(fontid, BLF_SHADOW); - BLF_shadow(fontid, 3, (const float[4]){0.0f, 0.0f, 0.0f, 0.5f}); - BLF_shadow_offset(fontid, 1, -1); + BLF_size(fontid, 1.75f * fstyle_points * U.pixelsize, U.dpi); /* draw value */ BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight); BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f); BLF_draw(fontid, str, strdrawlen); - BLF_disable(fontid, BLF_SHADOW); - GPU_blend(false); GPU_line_smooth(false); } @@ -2575,38 +2718,38 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even } else { delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + delta[1] = 0.0f; if (rc->zoom_prop) { RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); delta[0] /= zoom[0]; - delta[1] /= zoom[1]; } dist = len_v2(delta); delta[0] = event->x - rc->slow_mouse[0]; - delta[1] = event->y - rc->slow_mouse[1]; if (rc->zoom_prop) { delta[0] /= zoom[0]; - delta[1] /= zoom[1]; } - dist = dist + 0.1f * (delta[0] + delta[1]); + dist = dist + 0.1f * (delta[0]); } } else { delta[0] = rc->initial_mouse[0] - event->x; delta[1] = rc->initial_mouse[1] - event->y; - if (rc->zoom_prop) { RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); delta[0] /= zoom[0]; delta[1] /= zoom[1]; } - - dist = len_v2(delta); + if (rc->subtype == PROP_ANGLE) { + dist = len_v2(delta); + } + else { + dist = clamp_f(-delta[0], 0.0f, FLT_MAX); + } } /* calculate new value and apply snapping */ @@ -2633,6 +2776,8 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even if (snap) { new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; } + /* Invert new value to increase the factor moving the mouse to the right */ + new_value = 1 - new_value; break; case PROP_ANGLE: new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision; diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c new file mode 100644 index 00000000000..94eceafc59b --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -0,0 +1,219 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#include "wm_platform_support.h" +#include "wm_window_private.h" + +#include <string.h> + +#include "BLI_sys_types.h" +#include "BLI_dynstr.h" +#include "BLI_path_util.h" +#include "BLI_fileops.h" +#include "BLI_string.h" +#include "BLI_linklist.h" + +#include "BLT_translation.h" + +#include "BKE_appdir.h" +#include "BKE_global.h" + +#include "GPU_platform.h" + +#include "GHOST_C-api.h" + +#define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 + +/* Check if user has already approved the given platform_support_key. */ +static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) +{ + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + bool result = false; + + if (G.factory_startup) { + return result; + } + + if (cfgdir) { + char filepath[FILE_MAX]; + BLI_make_file_string("/", filepath, cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); + LinkNode *lines = BLI_file_read_as_lines(filepath); + for (LinkNode *line_node = lines; line_node; line_node = line_node->next) { + char *line = line_node->link; + if (STREQ(line, platform_support_key)) { + result = true; + break; + } + } + + if (!result && update) { + FILE *fp = BLI_fopen(filepath, "a"); + if (fp) { + fprintf(fp, "%s\n", platform_support_key); + fclose(fp); + } + } + + BLI_file_free_lines(lines); + } + return result; +} + +static void wm_platform_support_create_link(char *link) +{ + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, "https://docs.blender.org/manual/en/dev/troubleshooting/gpu/"); +#if defined(_WIN32) + BLI_dynstr_append(ds, "windows/"); +#elif defined(__APPLE__) + BLI_dynstr_append(ds, "apple/"); +#else /* UNIX */ + BLI_dynstr_append(ds, "linux/"); +#endif + + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "intel.html"); + } + else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "nvidia.html"); + } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + BLI_dynstr_append(ds, "amd.html"); + } + else { + BLI_dynstr_append(ds, "unknown.html"); + } + + BLI_assert(BLI_dynstr_get_len(ds) < WM_PLATFORM_SUPPORT_TEXT_SIZE); + BLI_dynstr_get_cstring_ex(ds, link); + BLI_dynstr_free(ds); +} + +bool WM_platform_support_perform_checks() +{ + char title[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char message[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + char link[WM_PLATFORM_SUPPORT_TEXT_SIZE]; + + bool result = true; + + eGPUSupportLevel support_level = GPU_platform_support_level(); + const char *platform_key = GPU_platform_support_level_key(); + + /* check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing addons via installers. */ + if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && + wm_platform_support_check_approval(platform_key, !G.background)) { + /* if it matches the user has confirmed and whishes to use it */ + return result; + } + + /* update the message and link based on the found support level */ + GHOST_DialogOptions dialog_options = 0; + + switch (support_level) { + default: + case GPU_SUPPORT_LEVEL_SUPPORTED: + break; + + case GPU_SUPPORT_LEVEL_LIMITED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Limited Platform Support")); + slen = 0; + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver has limited support. It may work, but with " + "issues.")); + + /* TODO: Extra space is needed for the split function in GHOST_SystemX11. We should change + * the behavior in GHOST_SystemX11. */ + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Newer graphics drivers may be available to improve Blender support.")); + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + + dialog_options = GHOST_DialogWarning; + break; + } + + case GPU_SUPPORT_LEVEL_UNSUPPORTED: { + size_t slen = 0; + STR_CONCAT(title, slen, "Blender - "); + STR_CONCAT( + title, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Platform Unsupported")); + slen = 0; + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Your graphics card or driver is not supported.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT( + message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, + "Newer graphics drivers may be available to improve Blender support.")); + + STR_CONCAT(message, slen, "\n \n"); + STR_CONCAT(message, slen, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Graphics card:\n")); + STR_CONCAT(message, slen, GPU_platform_gpu_name()); + STR_CONCAT(message, slen, "\n \n"); + + STR_CONCAT(message, + slen, + CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "The program will now close.")); + dialog_options = GHOST_DialogError; + result = false; + break; + } + } + wm_platform_support_create_link(link); + + bool show_message = ELEM( + support_level, GPU_SUPPORT_LEVEL_LIMITED, GPU_SUPPORT_LEVEL_UNSUPPORTED); + + /* We are running in the background print the message in the console. */ + if ((G.background || G.debug & G_DEBUG) && show_message) { + printf("%s\n\n%s\n%s\n", title, message, link); + } + if (G.background) { + /* Don't show the message-box when running in background mode. + * Printing to console is enough. */ + result = true; + } + else if (show_message) { + WM_ghost_show_message_box( + title, message, "Find Latest Drivers", "Continue Anyway", link, dialog_options); + } + + return result; +} diff --git a/source/blender/windowmanager/intern/wm_platform_support.h b/source/blender/windowmanager/intern/wm_platform_support.h new file mode 100644 index 00000000000..a8e20f6bcdf --- /dev/null +++ b/source/blender/windowmanager/intern/wm_platform_support.h @@ -0,0 +1,30 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_PLATFORM_SUPPORT_H__ +#define __WM_PLATFORM_SUPPORT_H__ + +#include "BLI_sys_types.h" + +bool WM_platform_support_perform_checks(void); + +#endif diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index d3f7661a008..3603ce81654 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -178,68 +178,79 @@ static void wm_block_splash_add_labels(uiBlock *block, int x, int y) #endif /* WITH_BUILDINFO */ } -static ImBuf *wm_block_splash_image(void) +static ImBuf *wm_block_splash_image(int r_unit_size[2]) { #ifndef WITH_HEADLESS extern char datatoc_splash_png[]; extern int datatoc_splash_png_size; extern char datatoc_splash_2x_png[]; extern int datatoc_splash_2x_png_size; + const bool is_2x = U.dpi_fac > 1.0; + const int imb_scale = is_2x ? 2 : 1; - ImBuf *ibuf = NULL; + /* We could allow this to be variable, + * for now don't since allowing it might create layout issues. + * + * Only check width because splashes sometimes change height + * and we don't want to break app-templates. */ + const int x_expect = 501 * imb_scale; - if (U.dpi_fac > 1.0) { - ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_2x_png, - datatoc_splash_2x_png_size, - IB_rect, - NULL, - "<splash screen>"); - } - else { - ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_splash_png, - datatoc_splash_png_size, - IB_rect, - NULL, - "<splash screen>"); - } + ImBuf *ibuf = NULL; - /* overwrite splash with template image */ if (U.app_template[0] != '\0') { - ImBuf *ibuf_template = NULL; char splash_filepath[FILE_MAX]; char template_directory[FILE_MAX]; - if (BKE_appdir_app_template_id_search( U.app_template, template_directory, sizeof(template_directory))) { BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, - (U.dpi_fac > 1.0) ? "splash_2x.png" : "splash.png"); - ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL); - if (ibuf_template) { - const int x_expect = ibuf->x; - const int y_expect = 250 * (int)U.dpi_fac; - /* don't cover the header text */ - if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) { - memcpy(ibuf->rect, - ibuf_template->rect, - ibuf_template->x * ibuf_template->y * sizeof(char[4])); - } - else { - CLOG_ERROR(WM_LOG_OPERATORS, - "Splash expected %dx%d found %dx%d, ignoring: %s\n", - x_expect, - y_expect, - ibuf_template->x, - ibuf_template->y, - splash_filepath); - } - IMB_freeImBuf(ibuf_template); + is_2x ? "splash_2x.png" : "splash.png"); + ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL); + + /* We could skip this check, see comment about 'x_expect' above. */ + if (ibuf && ibuf->x != x_expect) { + CLOG_ERROR(WM_LOG_OPERATORS, + "Splash expected %d width found %d, ignoring: %s\n", + x_expect, + ibuf->x, + splash_filepath); + IMB_freeImBuf(ibuf); + ibuf = NULL; } } } + + if (ibuf == NULL) { + const uchar *splash_data; + size_t splash_data_size; + + if (is_2x) { + splash_data = (const uchar *)datatoc_splash_2x_png; + splash_data_size = datatoc_splash_2x_png_size; + } + else { + splash_data = (const uchar *)datatoc_splash_png; + splash_data_size = datatoc_splash_png_size; + } + + ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>"); + + BLI_assert(ibuf->x == x_expect); + } + + if (is_2x) { + r_unit_size[0] = ibuf->x / 2; + r_unit_size[1] = ibuf->y / 2; + } + else { + r_unit_size[0] = ibuf->x; + r_unit_size[1] = ibuf->y; + } + return ibuf; #else + UNUSED_VARS(r_unit_size); return NULL; #endif } @@ -258,15 +269,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - ImBuf *ibuf = wm_block_splash_image(); + /* Size before dpi scaling (halved for hi-dpi image). */ + int ibuf_unit_size[2]; + ImBuf *ibuf = wm_block_splash_image(ibuf_unit_size); but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, - U.dpi_fac * 501, - U.dpi_fac * 250, + U.dpi_fac * ibuf_unit_size[0], + U.dpi_fac * ibuf_unit_size[1], /* Button owns the imbuf now. */ ibuf, 0.0, @@ -277,17 +290,18 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar UI_but_func_set(but, wm_block_splash_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - int x = U.dpi_fac * 502; - int y = U.dpi_fac * 237; + int x = U.dpi_fac * (ibuf_unit_size[0] + 1); + int y = U.dpi_fac * (ibuf_unit_size[1] - 13); wm_block_splash_add_labels(block, x, y); + const int layout_margin_x = U.dpi_fac * 26; uiLayout *layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, - U.dpi_fac * 26, + layout_margin_x, 0, - U.dpi_fac * 450, + (U.dpi_fac * ibuf_unit_size[0]) - (layout_margin_x * 2), U.dpi_fac * 110, 0, style); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 7437001cdfc..fa2320585d7 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -61,7 +61,9 @@ #include "wm.h" #include "wm_draw.h" #include "wm_files.h" +#include "wm_platform_support.h" #include "wm_window.h" +#include "wm_window_private.h" #include "wm_event_system.h" #include "ED_anim_api.h" @@ -78,7 +80,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_draw.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" @@ -409,8 +411,10 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) /* this is event from ghost, or exit-blender op */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { - /* First check if there is another main window remaining. */ wmWindow *win_other; + const bool is_dialog = GHOST_IsDialogWindow(win->ghostwin); + + /* First check if there is another main window remaining. */ for (win_other = wm->windows.first; win_other; win_other = win_other->next) { if (win_other != win && win_other->parent == NULL && !WM_window_is_temp_screen(win_other)) { break; @@ -422,10 +426,15 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) return; } - /* close child windows */ - for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) { - if (win_child->parent == win) { - wm_window_close(C, wm, win_child); + /* Close child windows and bring windows back to front that dialogs have pushed behind the main + * window. */ + for (wmWindow *iter_win = wm->windows.first; iter_win; iter_win = iter_win->next) { + if (iter_win->parent == win) { + wm_window_close(C, wm, iter_win); + } + else if (is_dialog && iter_win != win && iter_win->parent && + (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) { + wm_window_raise(iter_win); } } @@ -547,7 +556,10 @@ static void wm_window_ensure_eventstate(wmWindow *win) } /* belongs to below */ -static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win) +static void wm_window_ghostwindow_add(wmWindowManager *wm, + const char *title, + wmWindow *win, + bool is_dialog) { GHOST_WindowHandle ghostwin; GHOST_GLSettings glSettings = {0}; @@ -569,15 +581,29 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm wmWindow *prev_windrawable = wm->windrawable; wm_window_clear_drawable(wm); - ghostwin = GHOST_CreateWindow(g_system, - title, - win->posx, - posy, - win->sizex, - win->sizey, - (GHOST_TWindowState)win->windowstate, - GHOST_kDrawingContextTypeOpenGL, - glSettings); + if (is_dialog && win->parent) { + ghostwin = GHOST_CreateDialogWindow(g_system, + win->parent->ghostwin, + title, + win->posx, + posy, + win->sizex, + win->sizey, + (GHOST_TWindowState)win->windowstate, + GHOST_kDrawingContextTypeOpenGL, + glSettings); + } + else { + ghostwin = GHOST_CreateWindow(g_system, + title, + win->posx, + posy, + win->sizex, + win->sizey, + (GHOST_TWindowState)win->windowstate, + GHOST_kDrawingContextTypeOpenGL, + glSettings); + } if (ghostwin) { GHOST_RectangleHandle bounds; @@ -635,6 +661,68 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm } } +static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog) +{ + wmKeyMap *keymap; + + if (win->ghostwin == NULL) { + if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) { + win->posx = wm_init_state.start_x; + win->posy = wm_init_state.start_y; + win->sizex = wm_init_state.size_x; + win->sizey = wm_init_state.size_y; + + if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) { + win->windowstate = GHOST_kWindowStateNormal; + wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM; + } + else { + win->windowstate = GHOST_WINDOW_STATE_DEFAULT; + } + } + + if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) { + win->windowstate = wm_init_state.windowstate; + wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE; + } + + /* without this, cursor restore may fail, T45456 */ + if (win->cursor == 0) { + win->cursor = WM_CURSOR_DEFAULT; + } + + wm_window_ghostwindow_add(wm, "Blender", win, is_dialog); + } + + if (win->ghostwin != NULL) { + /* If we have no ghostwin this is a buggy window that should be removed. + * However we still need to initialize it correctly so the screen doesn't hang. */ + + /* happens after fileread */ + wm_window_ensure_eventstate(win); + } + + /* add keymap handlers (1 handler for all keys in map!) */ + keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0); + WM_event_add_keymap_handler(&win->handlers, keymap); + + keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0); + WM_event_add_keymap_handler(&win->handlers, keymap); + + keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0); + WM_event_add_keymap_handler(&win->modalhandlers, keymap); + + /* add drop boxes */ + { + ListBase *lb = WM_dropboxmap_find("Window", 0, 0); + WM_event_add_dropbox_handler(&win->handlers, lb); + } + wm_window_title(wm, win); + + /* add topbar */ + ED_screen_global_areas_refresh(win); +} + /** * Initialize #wmWindow without ghostwin, open these and clear. * @@ -650,9 +738,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm */ void wm_window_ghostwindows_ensure(wmWindowManager *wm) { - wmKeyMap *keymap; - wmWindow *win; - BLI_assert(G.background == false); /* No command-line prefsize? then we set this. @@ -682,63 +767,8 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) #endif } - for (win = wm->windows.first; win; win = win->next) { - if (win->ghostwin == NULL) { - if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) { - win->posx = wm_init_state.start_x; - win->posy = wm_init_state.start_y; - win->sizex = wm_init_state.size_x; - win->sizey = wm_init_state.size_y; - - if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) { - win->windowstate = GHOST_kWindowStateNormal; - wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM; - } - else { - win->windowstate = GHOST_WINDOW_STATE_DEFAULT; - } - } - - if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) { - win->windowstate = wm_init_state.windowstate; - wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE; - } - - /* without this, cursor restore may fail, T45456 */ - if (win->cursor == 0) { - win->cursor = CURSOR_STD; - } - - wm_window_ghostwindow_add(wm, "Blender", win); - } - - if (win->ghostwin != NULL) { - /* If we have no ghostwin this is a buggy window that should be removed. - * However we still need to initialize it correctly so the screen doesn't hang. */ - - /* happens after fileread */ - wm_window_ensure_eventstate(win); - } - - /* add keymap handlers (1 handler for all keys in map!) */ - keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0); - WM_event_add_keymap_handler(&win->handlers, keymap); - - keymap = WM_keymap_ensure(wm->defaultconf, "Screen", 0, 0); - WM_event_add_keymap_handler(&win->handlers, keymap); - - keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", 0, 0); - WM_event_add_keymap_handler(&win->modalhandlers, keymap); - - /* add drop boxes */ - { - ListBase *lb = WM_dropboxmap_find("Window", 0, 0); - WM_event_add_dropbox_handler(&win->handlers, lb); - } - wm_window_title(wm, win); - - /* add topbar */ - ED_screen_global_areas_refresh(win); + for (wmWindow *win = wm->windows.first; win; win = win->next) { + wm_window_ghostwindow_ensure(wm, win, false); } } @@ -792,20 +822,26 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) * Uses `screen->temp` tag to define what to do, currently it limits * to only one "temp" window for render out, preferences, filewindow, etc... * - * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS... - * \return the window or NULL. + * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type) + * \return the window or NULL in case of failure. */ -wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type) +wmWindow *WM_window_open_temp(bContext *C, + const char *title, + int x, + int y, + int sizex, + int sizey, + int space_type, + bool dialog) { Main *bmain = CTX_data_main(C); + wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_prev = CTX_wm_window(C); wmWindow *win; bScreen *screen; ScrArea *sa; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - eSpace_Type space_type = SPACE_EMPTY; - const char *title; /* convert to native OS window coordinates */ const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin); @@ -824,9 +860,10 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i /* changes rect to fit within desktop */ wm_window_check_position(&rect); - /* test if we have a temp screen already */ - for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) { - if (WM_window_is_temp_screen(win)) { + /* Reuse temporary or dialog window if one is open (but don't use a dialog for a regular + * temporary window, or vice versa). */ + for (win = wm->windows.first; win; win = win->next) { + if (WM_window_is_temp_screen(win) && (dialog == GHOST_IsDialogWindow(win->ghostwin))) { break; } } @@ -844,11 +881,6 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i win->sizex = BLI_rcti_size_x(&rect); win->sizey = BLI_rcti_size_y(&rect); - if (win->ghostwin) { - wm_window_set_size(win, win->sizex, win->sizey); - wm_window_raise(win); - } - if (WM_window_get_active_workspace(win) == NULL) { WorkSpace *workspace = WM_window_get_active_workspace(win_prev); BKE_workspace_active_set(win->workspace_hook, workspace); @@ -873,6 +905,9 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i /* make window active, and validate/resize */ CTX_wm_window_set(C, win); + if (!win->ghostwin) { + wm_window_ghostwindow_ensure(wm, win, dialog); + } WM_check(C); /* It's possible `win->ghostwin == NULL`. @@ -885,60 +920,21 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i sa = screen->areabase.first; CTX_wm_area_set(C, sa); - if (type == WM_WINDOW_RENDER) { - space_type = SPACE_IMAGE; - } - else if (type == WM_WINDOW_DRIVERS) { - space_type = SPACE_GRAPH; - } - else if (type == WM_WINDOW_USERPREFS) { - space_type = SPACE_USERPREF; - } - else if (type == WM_WINDOW_FILESEL) { - space_type = SPACE_FILE; - } - else if (type == WM_WINDOW_INFO) { - space_type = SPACE_INFO; - } - else { - BLI_assert(false); - } ED_area_newspace(C, sa, space_type, false); ED_screen_change(C, screen); - ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ - - /* do additional setup for specific editor type */ - if (type == WM_WINDOW_DRIVERS) { - ED_drivers_editor_init(C, sa); - } - - if (sa->spacetype == SPACE_IMAGE) { - title = IFACE_("Blender Render"); - } - else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) { - title = IFACE_("Blender Preferences"); - } - else if (sa->spacetype == SPACE_FILE) { - title = IFACE_("Blender File View"); - } - else if (sa->spacetype == SPACE_GRAPH) { - title = IFACE_("Blender Drivers Editor"); - } - else if (sa->spacetype == SPACE_INFO) { - title = IFACE_("Blender Info Log"); - } - else { - title = "Blender"; - } + ED_screen_refresh(wm, win); /* test scale */ if (win->ghostwin) { + wm_window_set_size(win, win->sizex, win->sizey); + wm_window_raise(win); + GHOST_SetTitle(win->ghostwin, title); return win; } else { /* very unlikely! but opening a new window can fail */ - wm_window_close(C, CTX_wm_manager(C), win); + wm_window_close(C, wm, win); CTX_wm_window_set(C, win_prev); return NULL; @@ -2437,4 +2433,14 @@ void WM_opengl_context_release(void *context) GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); } +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options) +{ + BLI_assert(g_system); + GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options); +} /** \} */ diff --git a/source/blender/windowmanager/intern/wm_window_private.h b/source/blender/windowmanager/intern/wm_window_private.h new file mode 100644 index 00000000000..115539861d7 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_window_private.h @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup wm + */ +#ifndef __WM_WINDOW_PRIVATE_H__ +#define __WM_WINDOW_PRIVATE_H__ + +#include "BLI_sys_types.h" +#include "GHOST_Types.h" + +/* *************** Message box *************** */ +/* `WM_ghost_show_message_box` is implemented in `wm_windows.c` it is + * defined here as it was implemented to be used for showing + * a message to the user when the platform is not (fully) supported. + * + * In all other cases this message box should not be used. */ +void WM_ghost_show_message_box(const char *title, + const char *message, + const char *help_label, + const char *continue_label, + const char *link, + GHOST_DialogOptions dialog_options); + +#endif diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h index 6793937c413..7a28aeb3c70 100644 --- a/source/blender/windowmanager/wm_cursors.h +++ b/source/blender/windowmanager/wm_cursors.h @@ -24,80 +24,57 @@ #ifndef __WM_CURSORS_H__ #define __WM_CURSORS_H__ -void wm_init_cursor_data(void); - -#define BC_GHOST_CURSORS 1000 - -/* old cursors */ -enum { - CURSOR_FACESEL = BC_GHOST_CURSORS, - CURSOR_WAIT, - CURSOR_EDIT, - CURSOR_X_MOVE, - CURSOR_Y_MOVE, - CURSOR_HELP, - CURSOR_STD, - CURSOR_NONE, - CURSOR_PENCIL, - CURSOR_COPY, -}; - -// typedef struct BCursor_s BCursor; -typedef struct BCursor { - - char *small_bm; - char *small_mask; - - char small_sizex; - char small_sizey; - char small_hotx; - char small_hoty; - - char *big_bm; - char *big_mask; - - char big_sizex; - char big_sizey; - char big_hotx; - char big_hoty; - - bool can_invert_color; +struct wmEvent; +struct wmWindow; -} BCursor; +typedef enum WMCursorType { + WM_CURSOR_DEFAULT = 1, + WM_CURSOR_TEXT_EDIT, + WM_CURSOR_WAIT, + WM_CURSOR_STOP, + WM_CURSOR_EDIT, + WM_CURSOR_COPY, + WM_CURSOR_HAND, + + WM_CURSOR_CROSS, + WM_CURSOR_PAINT, + WM_CURSOR_DOT, + WM_CURSOR_CROSSC, + + WM_CURSOR_KNIFE, + WM_CURSOR_VERTEX_LOOP, + WM_CURSOR_PAINT_BRUSH, + WM_CURSOR_ERASER, + WM_CURSOR_EYEDROPPER, + + WM_CURSOR_SWAP_AREA, + WM_CURSOR_X_MOVE, + WM_CURSOR_Y_MOVE, + WM_CURSOR_H_SPLIT, + WM_CURSOR_V_SPLIT, + + WM_CURSOR_NW_ARROW, + WM_CURSOR_NS_ARROW, + WM_CURSOR_EW_ARROW, + WM_CURSOR_N_ARROW, + WM_CURSOR_S_ARROW, + WM_CURSOR_E_ARROW, + WM_CURSOR_W_ARROW, + + WM_CURSOR_NSEW_SCROLL, + WM_CURSOR_NS_SCROLL, + WM_CURSOR_EW_SCROLL, + + WM_CURSOR_ZOOM_IN, + WM_CURSOR_ZOOM_OUT, + + WM_CURSOR_NONE, -#define SYSCURSOR 1 -enum { - BC_NW_ARROWCURSOR = 2, - BC_NS_ARROWCURSOR, - BC_EW_ARROWCURSOR, - BC_WAITCURSOR, - BC_CROSSCURSOR, - BC_EDITCROSSCURSOR, - BC_BOXSELCURSOR, - BC_KNIFECURSOR, - BC_VLOOPCURSOR, - BC_TEXTEDITCURSOR, - BC_PAINTBRUSHCURSOR, - BC_HANDCURSOR, - BC_NSEW_SCROLLCURSOR, - BC_NS_SCROLLCURSOR, - BC_EW_SCROLLCURSOR, - BC_EYEDROPPER_CURSOR, - BC_SWAPAREA_CURSOR, - BC_H_SPLITCURSOR, - BC_V_SPLITCURSOR, - BC_N_ARROWCURSOR, - BC_S_ARROWCURSOR, - BC_E_ARROWCURSOR, - BC_W_ARROWCURSOR, - BC_STOPCURSOR, /* --- ALWAYS LAST ----- */ - BC_NUMCURSORS, -}; - -struct wmEvent; -struct wmWindow; + WM_CURSOR_NUM, +} WMCursorType; +void wm_init_cursor_data(void); bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event); #endif /* __WM_CURSORS_H__ */ |