diff options
author | Julian Eisel <julian@blender.org> | 2020-03-16 20:14:24 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2020-03-16 20:14:24 +0300 |
commit | ddbbd9928ec443f813ee4d46011288e360278e9f (patch) | |
tree | 91f50fc6e8e8b68be5686903aca191d43cdafae5 /source/blender | |
parent | b86be9b2145458037fd0b17433b7af0efa7b6472 (diff) | |
parent | d2ef342b2a50a7eac725889708fd689ffa126e25 (diff) |
Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
Diffstat (limited to 'source/blender')
185 files changed, 4654 insertions, 2632 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index eb7078213da..2a4394ee096 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 283 -#define BLENDER_SUBVERSION 8 +#define BLENDER_SUBVERSION 9 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index aebe04f3a7a..f93003dc423 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -117,7 +117,7 @@ void BKE_camera_view_frame(const struct Scene *scene, float r_vec[4][3]); bool BKE_camera_view_frame_fit_to_scene(struct Depsgraph *depsgraph, - struct Scene *scene, + const struct Scene *scene, struct Object *camera_ob, float r_co[3], float *r_scale); @@ -130,33 +130,34 @@ bool BKE_camera_view_frame_fit_to_coords(const struct Depsgraph *depsgraph, /* Camera multi-view API */ -struct Object *BKE_camera_multiview_render(struct Scene *scene, +struct Object *BKE_camera_multiview_render(const struct Scene *scene, struct Object *camera, const char *viewname); -void BKE_camera_multiview_view_matrix(struct RenderData *rd, +void BKE_camera_multiview_view_matrix(const struct RenderData *rd, const struct Object *camera, const bool is_left, float r_viewmat[4][4]); -void BKE_camera_multiview_model_matrix(struct RenderData *rd, +void BKE_camera_multiview_model_matrix(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4]); -void BKE_camera_multiview_model_matrix_scaled(struct RenderData *rd, +void BKE_camera_multiview_model_matrix_scaled(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4]); -void BKE_camera_multiview_window_matrix(struct RenderData *rd, +void BKE_camera_multiview_window_matrix(const struct RenderData *rd, const struct Object *camera, const char *viewname, float r_winmat[4][4]); -float BKE_camera_multiview_shift_x(struct RenderData *rd, +float BKE_camera_multiview_shift_x(const struct RenderData *rd, const struct Object *camera, const char *viewname); -void BKE_camera_multiview_params(struct RenderData *rd, +void BKE_camera_multiview_params(const struct RenderData *rd, struct CameraParams *params, const struct Object *camera, const char *viewname); -bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, const struct Object *camera); +bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd, + const struct Object *camera); /* Camera background image API */ struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam); diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index d5fb55af06c..96837f380d4 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -33,10 +33,10 @@ extern "C" { struct ClothModifierData; struct CollisionModifierData; struct Depsgraph; +struct GHash; struct Mesh; struct Object; struct Scene; -struct GHash; #define DO_INLINE MALWAYS_INLINE diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 3284896795b..5d23029df9e 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -34,8 +34,10 @@ struct CurveMapping; struct Depsgraph; struct GHash; struct ListBase; +struct MDeformVert; struct Main; struct Material; +struct MaterialGPencilStyle; struct Object; struct Scene; struct SpaceImage; @@ -47,8 +49,6 @@ struct bGPDlayer_Mask; struct bGPDspoint; struct bGPDstroke; struct bGPdata; -struct MaterialGPencilStyle; -struct MDeformVert; #define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) #define GPENCIL_SIMPLIFY_ONPLAY(playing) \ @@ -193,6 +193,7 @@ void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name); struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name); void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl); void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd); +void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames); /* Brush */ struct Material *BKE_gpencil_brush_material_get(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h index 9562ace3c51..e6e82900f6d 100644 --- a/source/blender/blenkernel/BKE_idtype.h +++ b/source/blender/blenkernel/BKE_idtype.h @@ -70,7 +70,7 @@ typedef struct IDTypeInfo { * Bitflag matching id_code, used for filtering (e.g. in file browser), see DNA_ID.h's * FILTER_ID_XX enums. */ - int id_filter; + int64_t id_filter; /** * Define the position of this data-block type in the virtual list of all data in a Main that is diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 524bd3318f6..4ce740a1f5a 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -68,7 +68,7 @@ void BKE_render_result_stamp_info(struct Scene *scene, * Fills in the static stamp data (i.e. everything except things that can change per frame). * The caller is responsible for freeing the allocated memory. */ -struct StampData *BKE_stamp_info_from_scene_static(struct Scene *scene); +struct StampData *BKE_stamp_info_from_scene_static(const struct Scene *scene); bool BKE_stamp_is_known_field(const char *field_name); void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf); void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index c663ae76564..4ee255d4e61 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -98,16 +98,15 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *object, int direction); -void multiresModifier_base_apply(struct MultiresModifierData *mmd, - struct Scene *scene, - struct Object *ob); -void multiresModifier_subdivide(struct MultiresModifierData *mmd, - struct Scene *scene, - struct Object *ob, - int updateblock, - int simple); -void multiresModifier_sync_levels_ex(struct Scene *scene, - struct Object *ob_dst, +void multiresModifier_base_apply(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd); +void multiresModifier_subdivide_legacy(struct MultiresModifierData *mmd, + struct Scene *scene, + struct Object *ob, + int updateblock, + int simple); +void multiresModifier_sync_levels_ex(struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst); @@ -131,6 +130,10 @@ int multires_mdisp_corners(struct MDisps *s); /* update multires data after topology changing */ void multires_topology_changed(struct Mesh *me); +void multires_ensure_external_read(struct Mesh *mesh, int top_level); +void multiresModifier_ensure_external_read(struct Mesh *mesh, + const struct MultiresModifierData *mmd); + /**** interpolation stuff ****/ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v); int mdisp_rot_face_to_crn(struct MVert *mvert, @@ -145,18 +148,32 @@ int mdisp_rot_face_to_crn(struct MVert *mvert, /* Reshaping, define in multires_reshape.c */ +bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + const float (*vert_coords)[3], + const int num_vert_coords); bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph, struct MultiresModifierData *mmd, struct Object *dst, struct Object *src); bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, - struct MultiresModifierData *mmd, struct Object *ob, - struct ModifierData *md); + struct MultiresModifierData *mmd, + struct ModifierData *deform_md); bool multiresModifier_reshapeFromCCG(const int tot_level, struct Mesh *coarse_mesh, struct SubdivCCG *subdiv_ccg); +/* Subdivide multires displacement once. */ +void multiresModifier_subdivide(struct Object *object, struct MultiresModifierData *mmd); + +/* Subdivide displacement to the given level. + * If level is lower than the current top level nothing happens. */ +void multiresModifier_subdivide_to_level(struct Object *object, + struct MultiresModifierData *mmd, + const int top_level); + /* Subdivision integration, defined in multires_subdiv.c */ struct SubdivSettings; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index a8ebd32ad4d..886591d7728 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -76,9 +76,7 @@ bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md); bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type); -void BKE_object_link_modifiers(struct Scene *scene, - struct Object *ob_dst, - const struct Object *ob_src); +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob, const int flag); void BKE_object_free_shaderfx(struct Object *ob, const int flag); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 9fd732027d1..881f3356a86 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -56,12 +56,12 @@ struct SubdivCCG; struct SubdivCCG; struct Tex; struct ToolSettings; -struct tPaletteColorHSV; struct UnifiedPaintSettings; struct View3D; struct ViewLayer; struct bContext; struct bToolRef; +struct tPaletteColorHSV; enum eOverlayFlags; diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 8018178fcee..f78c7b66bb4 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -78,7 +78,7 @@ void BKE_scene_remove_rigidbody_object(struct Main *bmain, 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); +struct Object *BKE_scene_object_find_by_name(const struct Scene *scene, const char *name); /* Scene base iteration function. * Define struct here, so no need to bother with alloc/free it. @@ -118,8 +118,8 @@ struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAM #endif 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); +const char *BKE_scene_find_marker_name(const struct Scene *scene, int frame); +const char *BKE_scene_find_last_marker_name(const struct Scene *scene, int frame); int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int cfra); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 2a45d89bad4..31951cc101a 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -393,7 +393,7 @@ void BKE_sequence_single_fix(struct Sequence *seq); bool BKE_sequence_test_overlap(struct ListBase *seqbasep, struct Sequence *test); void BKE_sequence_translate(struct Scene *scene, struct Sequence *seq, int delta); void BKE_sequence_sound_init(struct Scene *scene, struct Sequence *seq); -struct Sequence *BKE_sequencer_foreground_frame_get(struct Scene *scene, int frame); +const struct Sequence *BKE_sequencer_foreground_frame_get(const struct Scene *scene, int frame); struct ListBase *BKE_sequence_seqbase(struct ListBase *seqbase, struct Sequence *seq); struct Sequence *BKE_sequence_metastrip(ListBase *seqbase /* = ed->seqbase */, struct Sequence *meta /* = NULL */, diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index e6d931276bf..1298f25fcc4 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -105,7 +105,10 @@ typedef struct SoundInfo { bool BKE_sound_info_get(struct Main *main, struct bSound *sound, SoundInfo *sound_info); #if defined(WITH_AUDASPACE) -AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume); +AUD_Device *BKE_sound_mixdown(const struct Scene *scene, + AUD_DeviceSpecs specs, + int start, + float volume); #endif void BKE_sound_reset_scene_runtime(struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h index 7fc740a4a9b..79605e99306 100644 --- a/source/blender/blenkernel/BKE_writeavi.h +++ b/source/blender/blenkernel/BKE_writeavi.h @@ -36,7 +36,7 @@ struct Scene; typedef struct bMovieHandle { int (*start_movie)(void *context_v, - struct Scene *scene, + const struct Scene *scene, struct RenderData *rd, int rectx, int recty, @@ -55,14 +55,20 @@ typedef struct bMovieHandle { void (*end_movie)(void *context_v); /* Optional function. */ - void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); + void (*get_movie_path)(char *string, + const struct RenderData *rd, + bool preview, + const char *suffix); void *(*context_create)(void); void (*context_free)(void *context_v); } bMovieHandle; bMovieHandle *BKE_movie_handle_get(const char imtype); -void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix); +void BKE_movie_filepath_get(char *string, + const struct RenderData *rd, + bool preview, + const char *suffix); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 9da28c849d9..467e6ab7242 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -62,7 +62,7 @@ struct ReportList; struct Scene; int BKE_ffmpeg_start(void *context_v, - struct Scene *scene, + const struct Scene *scene, struct RenderData *rd, int rectx, int recty, @@ -80,14 +80,14 @@ int BKE_ffmpeg_append(void *context_v, const char *suffix, struct ReportList *reports); void BKE_ffmpeg_filepath_get(char *string, - struct RenderData *rd, + const struct RenderData *rd, bool preview, const char *suffix); void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset); void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf); void BKE_ffmpeg_codec_settings_verify(struct RenderData *rd); -bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd); +bool BKE_ffmpeg_alpha_channel_is_supported(const struct RenderData *rd); int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str); void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 135168a6de4..047901b4c81 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -168,7 +168,12 @@ set(SRC intern/modifier.c intern/movieclip.c intern/multires.c - intern/multires_reshape_legacy.c + intern/multires_reshape.c + intern/multires_reshape_apply_base.c + intern/multires_reshape_ccg.c + intern/multires_reshape_smooth.c + intern/multires_reshape_util.c + intern/multires_reshape_vertcos.c intern/multires_subdiv.c intern/nla.c intern/node.c @@ -378,6 +383,7 @@ set(SRC intern/data_transfer_intern.h intern/lib_intern.h intern/multires_inline.h + intern/multires_reshape.h intern/pbvh_intern.h intern/subdiv_converter.h intern/subdiv_inline.h diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index d1a6ebb222c..1a2d8290609 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -666,7 +666,7 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params, /* don't move the camera, just yield the fit location */ /* r_scale only valid/useful for ortho cameras */ bool BKE_camera_view_frame_fit_to_scene( - Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale) + Depsgraph *depsgraph, const Scene *scene, Object *camera_ob, float r_co[3], float *r_scale) { CameraParams params; CameraViewFrameData data_cb; @@ -813,7 +813,7 @@ static void camera_stereo3d_model_matrix(const Object *camera, } /* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */ -void BKE_camera_multiview_view_matrix(RenderData *rd, +void BKE_camera_multiview_view_matrix(const RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4]) @@ -832,7 +832,7 @@ static bool camera_is_left(const char *viewname) return true; } -void BKE_camera_multiview_model_matrix(RenderData *rd, +void BKE_camera_multiview_model_matrix(const RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4]) @@ -841,7 +841,7 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, normalize_m4(r_modelmat); } -void BKE_camera_multiview_model_matrix_scaled(RenderData *rd, +void BKE_camera_multiview_model_matrix_scaled(const RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4]) @@ -860,7 +860,7 @@ void BKE_camera_multiview_model_matrix_scaled(RenderData *rd, } } -void BKE_camera_multiview_window_matrix(RenderData *rd, +void BKE_camera_multiview_window_matrix(const RenderData *rd, const Object *camera, const char *viewname, float r_winmat[4][4]) @@ -879,7 +879,7 @@ void BKE_camera_multiview_window_matrix(RenderData *rd, copy_m4_m4(r_winmat, params.winmat); } -bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera) +bool BKE_camera_multiview_spherical_stereo(const RenderData *rd, const Object *camera) { Camera *cam; const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; @@ -903,9 +903,8 @@ bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera) return false; } -static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix) +static Object *camera_multiview_advanced(const Scene *scene, Object *camera, const char *suffix) { - SceneRenderView *srv; char name[MAX_NAME]; const char *camera_name = camera->id.name + 2; const int len_name = strlen(camera_name); @@ -914,7 +913,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha name[0] = '\0'; /* we need to take the better match, thus the len_suffix_max test */ - for (srv = scene->r.views.first; srv; srv = srv->next) { + for (const SceneRenderView *srv = scene->r.views.first; srv; srv = srv->next) { const int len_suffix = strlen(srv->suffix); if ((len_suffix < len_suffix_max) || (len_name < len_suffix)) { @@ -938,7 +937,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha } /* returns the camera to be used for render */ -Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname) +Object *BKE_camera_multiview_render(const Scene *scene, Object *camera, const char *viewname) { const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0; @@ -993,7 +992,9 @@ static float camera_stereo3d_shift_x(const Object *camera, const char *viewname) return shift; } -float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname) +float BKE_camera_multiview_shift_x(const RenderData *rd, + const Object *camera, + const char *viewname) { const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; Camera *data = camera->data; @@ -1011,7 +1012,7 @@ float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const c } } -void BKE_camera_multiview_params(RenderData *rd, +void BKE_camera_multiview_params(const RenderData *rd, CameraParams *params, const Object *camera, const char *viewname) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index f38810322a8..3a86e3084d8 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4822,7 +4822,7 @@ static bConstraintTypeInfo CTI_FOLLOWTRACK = { followtrack_evaluate, /* evaluate */ }; -/* ----------- Camre Solver ------------- */ +/* ----------- Camera Solver ------------- */ static void camerasolver_new_data(void *cdata) { diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 9919a0d7385..366137b5fa6 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -705,8 +705,7 @@ static void bb_allocateData(FluidObjectBB *bb, bool use_velocity, bool use_influ } bb->distances = MEM_malloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_distances"); - /* Initialize to infinity. */ - memset(bb->distances, 0x7f7f7f7f, sizeof(float) * bb->total_cells); + copy_vn_fl(bb->distances, bb->total_cells, FLT_MAX); bb->valid = true; } @@ -3272,12 +3271,12 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj } me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces); - mverts = me->mvert; - mpolys = me->mpoly; - mloops = me->mloop; if (!me) { return NULL; } + mverts = me->mvert; + mpolys = me->mpoly; + mloops = me->mloop; /* Get size (dimension) but considering scaling scaling. */ copy_v3_v3(cell_size_scaled, mds->cell_size); @@ -3674,8 +3673,9 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, /* Reset fluid if no fluid present (obviously) * or if timeline gets reset to startframe */ - if (!mds->fluid || is_startframe) { + if (!mds->fluid) { BKE_fluid_modifier_reset_ex(mmd, false); + BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me); } /* Guiding parent res pointer needs initialization */ @@ -3687,8 +3687,6 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } } - BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me); - /* ensure that time parameters are initialized correctly before every step */ float fps = scene->r.frs_sec / scene->r.frs_sec_base; mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale; @@ -3743,10 +3741,9 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH; baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES; baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE; - bake_outdated = mds->cache_flag & - (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | - FLUID_DOMAIN_OUTDATED_NOISE | FLUID_DOMAIN_OUTDATED_MESH | - FLUID_DOMAIN_OUTDATED_PARTICLES | FLUID_DOMAIN_OUTDATED_GUIDE); + bake_outdated = mds->cache_flag & (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | + FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES | + FLUID_DOMAIN_OUTDATED_GUIDE); bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide; resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr); @@ -4897,7 +4894,6 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) mmd->flow->type = FLUID_FLOW_TYPE_SMOKE; mmd->flow->behavior = FLUID_FLOW_BEHAVIOR_GEOMETRY; - mmd->flow->type = FLUID_FLOW_TYPE_SMOKE; mmd->flow->flags = FLUID_FLOW_ABSOLUTE | FLUID_FLOW_USE_PART_SIZE | FLUID_FLOW_USE_INFLOW; } else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 6cd2d36c188..c0b40721ccc 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1120,6 +1120,32 @@ void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd) } } +static int gpencil_cb_cmp_frame(void *thunk, const void *a, const void *b) +{ + const bGPDframe *frame_a = a; + const bGPDframe *frame_b = b; + + if (frame_a->framenum < frame_b->framenum) { + return -1; + } + if (frame_a->framenum > frame_b->framenum) { + return 1; + } + if (thunk != NULL) { + *((bool *)thunk) = true; + } + /* Sort selected last. */ + if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) { + return 1; + } + return 0; +} + +void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames) +{ + BLI_listbase_sort_r(&gpl->frames, gpencil_cb_cmp_frame, r_has_duplicate_frames); +} + /* get the active gp-layer for editing */ bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd) { @@ -3909,6 +3935,9 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig /* Assign original point pointer. */ for (int i = 0; i < gps_orig->totpoints; i++) { + if (i > gps_eval->totpoints - 1) { + break; + } bGPDspoint *pt_eval = &gps_eval->points[i]; pt_eval->runtime.pt_orig = &gps_orig->points[i]; pt_eval->runtime.idx_orig = i; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 4220408749a..22ec1fe1b98 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -145,8 +145,10 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c BLI_duplicatelist(&image_dst->tiles, &image_src->tiles); - for (int i = 0; i < TEXTARGET_COUNT; i++) { - image_dst->gputexture[i] = NULL; + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + image_dst->gputexture[i][eye] = NULL; + } } if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { @@ -529,9 +531,11 @@ bool BKE_image_scale(Image *image, int width, int height) bool BKE_image_has_opengl_texture(Image *ima) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (ima->gputexture[i] != NULL) { - return true; + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + if (ima->gputexture[i][eye] != NULL) { + return true; + } } } return false; @@ -1813,7 +1817,7 @@ typedef struct StampData { * \param use_dynamic: Also include data that can change on a per-frame basis. */ static void stampdata( - Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, bool use_dynamic) + const Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, bool use_dynamic) { char text[256]; struct tm *tl; @@ -1935,7 +1939,7 @@ static void stampdata( } if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) { - Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); + const Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); if (seq) { STRNCPY(text, seq->name + 2); @@ -2479,7 +2483,7 @@ void BKE_render_result_stamp_info(Scene *scene, } } -struct StampData *BKE_stamp_info_from_scene_static(Scene *scene) +struct StampData *BKE_stamp_info_from_scene_static(const Scene *scene) { struct StampData *stamp_data; @@ -3318,9 +3322,11 @@ static void image_free_tile(Image *ima, ImageTile *tile) continue; } - if (ima->gputexture[i] != NULL) { - GPU_texture_free(ima->gputexture[i]); - ima->gputexture[i] = NULL; + for (int eye = 0; eye < 2; eye++) { + if (ima->gputexture[i][eye] != NULL) { + GPU_texture_free(ima->gputexture[i][eye]); + ima->gputexture[i][eye] = NULL; + } } } @@ -3587,14 +3593,16 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la BLI_strncpy(tile->label, label, sizeof(tile->label)); } - /* Reallocate GPU tile array. */ - if (ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] != NULL) { - GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]); - ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY] = NULL; - } - if (ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] != NULL) { - GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING]); - ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING] = NULL; + for (int eye = 0; eye < 2; eye++) { + /* Reallocate GPU tile array. */ + if (ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye]); + ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][eye] = NULL; + } + if (ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye] != NULL) { + GPU_texture_free(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye]); + ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][eye] = NULL; + } } return tile; diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index c342185d0b8..27d4b8dd047 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -162,7 +162,8 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) { bNodeTree *ntree = NULL; Key *key = NULL; - const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0; + const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 && + (id->flag & LIB_EMBEDDED_DATA) == 0; lib_id_library_local_paths(bmain, id->lib, id); diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index f0bab4c0aa2..ce8fcc4eeb9 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1420,6 +1420,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, const CustomData_MeshMasks *mask, bool take_ownership) { + BLI_assert(mesh_src->id.tag & LIB_TAG_NO_MAIN); + /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ /* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh); * check whether it is still true with Mesh */ @@ -1571,6 +1573,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb) { + BLI_assert(mesh_src->id.tag & LIB_TAG_NO_MAIN); + int a, totvert = mesh_src->totvert; float *fp; MVert *mvert; diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 7b655b2d8fc..e14803e4193 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -3576,6 +3576,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, if (id) { /* ensure external data is transferred */ + /* TODO(sergey): Use multiresModifier_ensure_external_read(). */ CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); } diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index f3d65f584d1..4e97d0fc05c 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -57,6 +57,8 @@ #include "DEG_depsgraph_query.h" +#include "multires_reshape.h" + #include <math.h> #include <string.h> @@ -645,7 +647,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) GridPaintMask *gpm; multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); @@ -711,7 +713,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, MDisps *mdisps; multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); multires_force_sculpt_rebuild(ob); @@ -789,158 +791,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene, return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags); } -/* assumes no is normalized; return value's sign is negative if v is on - * the other side of the plane */ -static float v3_dist_from_plane(float v[3], float center[3], float no[3]) -{ - float s[3]; - sub_v3_v3v3(s, v, center); - return dot_v3v3(s, no); -} - -void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob) -{ - DerivedMesh *cddm, *dispdm, *origdm; - Mesh *me; - const MeshElemMap *pmap; - float(*origco)[3]; - int i, j, k, offset, totlvl; - - multires_force_sculpt_rebuild(ob); - - me = BKE_mesh_from_object(ob); - totlvl = mmd->totlvl; - - /* nothing to do */ - if (!totlvl) { - return; - } - - /* XXX - probably not necessary to regenerate the cddm so much? */ - - /* generate highest level with displacements */ - cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - dispdm = multires_dm_create_local( - scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY); - cddm->release(cddm); - - /* copy the new locations of the base verts into the mesh */ - offset = dispdm->getNumVerts(dispdm) - me->totvert; - for (i = 0; i < me->totvert; i++) { - dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co); - } - - /* heuristic to produce a better-fitting base mesh */ - - cddm = CDDM_from_mesh(me); - pmap = cddm->getPolyMap(ob, cddm); - origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco"); - for (i = 0; i < me->totvert; i++) { - copy_v3_v3(origco[i], me->mvert[i].co); - } - - for (i = 0; i < me->totvert; i++) { - float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3]; - float dist; - int tot = 0; - - /* don't adjust verts not used by at least one poly */ - if (!pmap[i].count) { - continue; - } - - /* find center */ - for (j = 0; j < pmap[i].count; j++) { - const MPoly *p = &me->mpoly[pmap[i].indices[j]]; - - /* this double counts, not sure if that's bad or good */ - for (k = 0; k < p->totloop; k++) { - int vndx = me->mloop[p->loopstart + k].v; - if (vndx != i) { - add_v3_v3(center, origco[vndx]); - tot++; - } - } - } - mul_v3_fl(center, 1.0f / tot); - - /* find normal */ - for (j = 0; j < pmap[i].count; j++) { - const MPoly *p = &me->mpoly[pmap[i].indices[j]]; - MPoly fake_poly; - MLoop *fake_loops; - float(*fake_co)[3]; - float no[3]; - - /* set up poly, loops, and coords in order to call - * BKE_mesh_calc_poly_normal_coords() */ - fake_poly.totloop = p->totloop; - fake_poly.loopstart = 0; - fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops"); - fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co"); - - for (k = 0; k < p->totloop; k++) { - int vndx = me->mloop[p->loopstart + k].v; - - fake_loops[k].v = k; - - if (vndx == i) { - copy_v3_v3(fake_co[k], center); - } - else { - copy_v3_v3(fake_co[k], origco[vndx]); - } - } - - BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, (const float(*)[3])fake_co, no); - MEM_freeN(fake_loops); - MEM_freeN(fake_co); - - add_v3_v3(avg_no, no); - } - normalize_v3(avg_no); - - /* push vertex away from the plane */ - dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no); - copy_v3_v3(push, avg_no); - mul_v3_fl(push, dist); - add_v3_v3(me->mvert[i].co, push); - } - - MEM_freeN(origco); - cddm->release(cddm); - - /* Vertices were moved around, need to update normals after all the vertices are updated - * Probably this is possible to do in the loop above, but this is rather tricky because - * we don't know all needed vertices' coordinates there yet. - */ - BKE_mesh_calc_normals(me); - - /* subdivide the mesh to highest level without displacements */ - cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local(scene, - ob, - cddm, - totlvl, - 0, - 0, - mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - 0, - false, - SUBSURF_IGNORE_SIMPLIFY); - cddm->release(cddm); - - /* calc disps */ - multiresModifier_disp_run( - dispdm, me, NULL, CALC_DISPLACEMENTS, origdm->getGridData(origdm), totlvl); - - origdm->release(origdm); - dispdm->release(dispdm); -} - -static void multires_subdivide( +static void multires_subdivide_legacy( MultiresModifierData *mmd, Scene *scene, Object *ob, int totlvl, int updateblock, int simple) { Mesh *me = ob->data; @@ -1038,10 +889,10 @@ static void multires_subdivide( multires_set_tot_level(ob, mmd, totlvl); } -void multiresModifier_subdivide( +void multiresModifier_subdivide_legacy( MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) { - multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); + multires_subdivide_legacy(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); } static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3]) @@ -1293,7 +1144,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) me = ccgdm->multires.ob->data; mmd = ccgdm->multires.mmd; multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (mdisps) { @@ -1521,7 +1372,7 @@ DerivedMesh *multires_make_derived_from_derived( } multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); /*run displacement*/ multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); @@ -2277,7 +2128,8 @@ void multires_load_old(Object *ob, Mesh *me) multires_load_old_vcols(me); multires_load_old_face_flags(me); - /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */ + /* multiresModifier_subdivide_legacy (actually, multires_subdivide_legacy) expects polys, not + * tessfaces! */ BKE_mesh_convert_mfaces_to_mpolys(me); /* Add a multires modifier to the object */ @@ -2289,7 +2141,7 @@ void multires_load_old(Object *ob, Mesh *me) BLI_insertlinkbefore(&ob->modifiers, md, mmd); for (i = 0; i < me->mr->level_count - 1; i++) { - multiresModifier_subdivide(mmd, NULL, ob, 1, 0); + multiresModifier_subdivide_legacy(mmd, NULL, ob, 1, 0); } mmd->lvl = mmd->totlvl; @@ -2314,8 +2166,7 @@ void multires_load_old(Object *ob, Mesh *me) /* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ -void multiresModifier_sync_levels_ex(Scene *scene, - Object *ob_dst, +void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) { @@ -2324,7 +2175,7 @@ void multiresModifier_sync_levels_ex(Scene *scene, } if (mmd_src->totlvl > mmd_dst->totlvl) { - multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl); } else { multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); @@ -2346,7 +2197,7 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) } if (mmd_src && mmd_dst) { - multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst); + multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); } } @@ -2373,7 +2224,7 @@ static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph), } /* Make sure layer present. */ Mesh *mesh = (Mesh *)object->data; - CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + multiresModifier_ensure_external_read(mesh, mmd); if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { return; } @@ -2467,6 +2318,44 @@ void multires_topology_changed(Mesh *me) } } +/* Makes sure data from an external file is fully read. + * + * Since the multires data files only contain displacement vectors without knowledge about + * subdivision level some extra work is needed. Namely make is to all displacement grids have + * proper level and number of displacement vectors set. */ +void multires_ensure_external_read(struct Mesh *mesh, int top_level) +{ + if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) { + return; + } + + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + if (mdisps == NULL) { + mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); + } + + const int totloop = mesh->totloop; + + for (int i = 0; i < totloop; ++i) { + if (mdisps[i].level != top_level) { + MEM_SAFE_FREE(mdisps[i].disps); + } + + /* NOTE: CustomData_external_read will take care of allocation of displacement vectors if + * they are missing. */ + + const int totdisp = multires_grid_tot[top_level]; + mdisps[i].totdisp = totdisp; + mdisps[i].level = top_level; + } + + CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); +} +void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModifierData *mmd) +{ + multires_ensure_external_read(mesh, mmd->totlvl); +} + /***************** Multires interpolation stuff *****************/ /* Find per-corner coordinate with given per-face UV coord */ diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c new file mode 100644 index 00000000000..a29398b24a0 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -0,0 +1,236 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" + +#include "DEG_depsgraph_query.h" + +#include "multires_reshape.h" + +/* ================================================================================================ + * Reshape from object. + */ + +bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + const float (*vert_coords)[3], + const int num_vert_coords) +{ + MultiresReshapeContext reshape_context; + if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) { + return false; + } + multires_reshape_store_original_grids(&reshape_context); + multires_reshape_ensure_grids(object->data, reshape_context.top.level); + if (!multires_reshape_assign_final_coords_from_vertcos( + &reshape_context, vert_coords, num_vert_coords)) { + multires_reshape_context_free(&reshape_context); + return false; + } + multires_reshape_smooth_object_grids_with_details(&reshape_context); + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); + return true; +} + +/* Returns truth on success, false otherwise. + * + * This function might fail in cases like source and destination not having + * matched amount of vertices. */ +bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph, + struct MultiresModifierData *mmd, + struct Object *dst, + struct Object *src) +{ + struct Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + struct Object *src_eval = DEG_get_evaluated_object(depsgraph, src); + Mesh *src_mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, src_eval, &CD_MASK_BAREMESH); + + int num_deformed_verts; + float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(src_mesh_eval, &num_deformed_verts); + + const bool result = multiresModifier_reshapeFromVertcos( + depsgraph, dst, mmd, deformed_verts, num_deformed_verts); + + MEM_freeN(deformed_verts); + + return result; +} + +/* ================================================================================================ + * Reshape from modifier. + */ + +bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + struct ModifierData *deform_md) +{ + MultiresModifierData highest_mmd = *mmd; + highest_mmd.sculptlvl = highest_mmd.totlvl; + highest_mmd.lvl = highest_mmd.totlvl; + highest_mmd.renderlvl = highest_mmd.totlvl; + + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + + /* Create mesh for the multires, ignoring any further modifiers (leading + * deformation modifiers will be applied though). */ + Mesh *multires_mesh = BKE_multires_create_mesh(depsgraph, scene_eval, &highest_mmd, object); + int num_deformed_verts; + float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(multires_mesh, &num_deformed_verts); + + /* Apply deformation modifier on the multires, */ + const ModifierEvalContext modifier_ctx = { + .depsgraph = depsgraph, + .object = object, + .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, + }; + modwrap_deformVerts( + deform_md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert); + BKE_id_free(NULL, multires_mesh); + + /* Reshaping */ + bool result = multiresModifier_reshapeFromVertcos( + depsgraph, object, &highest_mmd, deformed_verts, num_deformed_verts); + + /* Cleanup */ + MEM_freeN(deformed_verts); + + return result; +} + +/* ================================================================================================ + * Reshape from grids. + */ + +bool multiresModifier_reshapeFromCCG(const int tot_level, + Mesh *coarse_mesh, + struct SubdivCCG *subdiv_ccg) +{ + MultiresReshapeContext reshape_context; + if (!multires_reshape_context_create_from_ccg( + &reshape_context, subdiv_ccg, coarse_mesh, tot_level)) { + return false; + } + + multires_ensure_external_read(coarse_mesh, reshape_context.top.level); + + multires_reshape_store_original_grids(&reshape_context); + multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level); + if (!multires_reshape_assign_final_coords_from_ccg(&reshape_context, subdiv_ccg)) { + multires_reshape_context_free(&reshape_context); + return false; + } + multires_reshape_smooth_object_grids_with_details(&reshape_context); + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); + return true; +} + +/* ================================================================================================ + * Subdivision. + */ + +void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd) +{ + const int top_level = mmd->totlvl + 1; + multiresModifier_subdivide_to_level(object, mmd, top_level); +} + +void multiresModifier_subdivide_to_level(struct Object *object, + struct MultiresModifierData *mmd, + const int top_level) +{ + if (top_level <= mmd->totlvl) { + return; + } + + Mesh *coarse_mesh = object->data; + MultiresReshapeContext reshape_context; + + /* There was no multires at all, all displacement is at 0. Can simply make sure all mdisps grids + * are allocated at a proper level and return. */ + const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); + if (!has_mdisps) { + CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + } + if (!has_mdisps || top_level == 1) { + multires_reshape_ensure_grids(coarse_mesh, top_level); + multires_set_tot_level(object, mmd, top_level); + return; + } + + multires_flush_sculpt_updates(object); + + if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) { + return; + } + multires_reshape_store_original_grids(&reshape_context); + multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level); + multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context); + multires_reshape_smooth_object_grids(&reshape_context); + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + multires_reshape_context_free(&reshape_context); + + multires_set_tot_level(object, mmd, top_level); +} + +/* ================================================================================================ + * Apply base. + */ + +void multiresModifier_base_apply(struct Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) +{ + multires_force_sculpt_rebuild(object); + + MultiresReshapeContext reshape_context; + if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) { + return; + } + + multires_reshape_assign_final_coords_from_mdisps(&reshape_context); + multires_reshape_apply_base_update_mesh_coords(&reshape_context); + multires_reshape_apply_base_refit_base_mesh(&reshape_context); + multires_reshape_apply_base_refine_subdiv(&reshape_context); + multires_reshape_object_grids_to_tangent_displacement(&reshape_context); + + multires_reshape_context_free(&reshape_context); +} diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h new file mode 100644 index 00000000000..9029d19ae88 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape.h @@ -0,0 +1,327 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifndef __BKE_INTERN_MULTIRES_RESHAPE_H__ +#define __BKE_INTERN_MULTIRES_RESHAPE_H__ + +#include "BLI_sys_types.h" + +struct Depsgraph; +struct GridPaintMask; +struct MDisps; +struct Mesh; +struct MultiresModifierData; +struct Object; +struct Subdiv; +struct SubdivCCG; + +typedef struct MultiresReshapeContext { + /* Base mesh from original object. + * NOTE: Does NOT include any leading modifiers in it. */ + struct Mesh *base_mesh; + + /* Subdivision surface created for multires modifier. + * + * The coarse mesh of this subdivision surface is a base mesh with all deformation modifiers + * leading multires applied on it. */ + struct Subdiv *subdiv; + bool need_free_subdiv; + + struct { + /* Level at which displacement is being assigned to. + * It will be propagated up from this level to top.level. */ + int level; + + /* Grid size for reshape.level. */ + int grid_size; + } reshape; + + struct { + /* Top level of the displacement grids. + * The displacement will be propagated up to this level. */ + int level; + + /* Grid size for top.level. */ + int grid_size; + } top; + + struct { + /* Copy of original displacement and painting masks. */ + struct MDisps *mdisps; + struct GridPaintMask *grid_paint_masks; + } orig; + + /* Number of grids which are required for base_mesh. */ + int num_grids; + + /* Destination displacement and mask. + * Points to a custom data on a destination mesh. */ + struct MDisps *mdisps; + struct GridPaintMask *grid_paint_masks; + + /* Indexed by face index, gives first grid index of the face. */ + int *face_start_grid_index; + + /* Indexed by grid index, contains face (poly) index in the base mesh from which the grid has + * been created (in other words, index of a poly which contains loop corresponding to the grid + * index). */ + int *grid_to_face_index; + + /* Indexed by ptex face index, gives first grid index of the ptex face. + * + * For non-quad base faces ptex face is created for every face corner, so it's similar to a + * grid in this case. In this case start grid index will be the only one for this ptex face. + * + * For quad base faces there is a single ptex face but 4 grids. So in this case there will be + * 4 grids for the ptex, starting at a value stored in this mapping. */ + int *ptex_start_grid_index; + + /* Indexed by base face index, returns first ptex face index corresponding + * to that base face. */ + int *face_ptex_offset; +} MultiresReshapeContext; + +/** + * Coordinate which identifies element of a grid. + * This is directly related on how #CD_MDISPS stores displacement. + */ +typedef struct GridCoord { + int grid_index; + float u, v; +} GridCoord; + +/** + * Coordinate within ptex, which is what OpenSubdiv API operates on. + */ +typedef struct PTexCoord { + int ptex_face_index; + float u, v; +} PTexCoord; + +/** + * Element of a grid data stored in the destination mesh. + * This is where reshaped coordinates and mask values will be written to. + */ +typedef struct ReshapeGridElement { + float *displacement; + float *mask; +} ReshapeGridElement; + +typedef struct ReshapeConstGridElement { + float displacement[3]; + float mask; +} ReshapeConstGridElement; + +/* -------------------------------------------------------------------- */ +/** \name Construct/destruct reshape context. + * \{ */ + +/* Create subdivision surface descriptor which is configured for surface evaluation at a given + * multires modifier. */ +struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph, + struct Object *object, + const struct MultiresModifierData *mmd); + +bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, + struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd); + +bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context, + struct SubdivCCG *subdiv_ccg, + struct Mesh *base_mesh, + int top_level); + +bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *reshape_context, + struct Object *object, + struct MultiresModifierData *mmd, + int top_level); + +void multires_reshape_context_free(MultiresReshapeContext *reshape_context); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Helper accessors. + * \{ */ + +/* For the given grid index get index of face it was created for. */ +int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, + int grid_index); + +/* For the given grid index get corner of a face it was created for. */ +int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index); + +bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index); + +/* For the given grid index get index of corresponding ptex face. */ +int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context, + int grid_index); + +/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */ +PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord); + +/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */ +GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context, + const PTexCoord *ptex_coord); + +/* Calculate tangent matrix which converts displacement to a object vector. + * Is calculated for the given surface derivatives at a given base face corner. */ +void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, + const int face_index, + const int corner, + const float dPdu[3], + const float dPdv[3], + float r_tangent_matrix[3][3]); + +/* Get grid elements which are to be reshaped at a given or ptex coordinate. + * The data is coming from final custom mdata layers. */ +ReshapeGridElement multires_reshape_grid_element_for_grid_coord( + const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord); +ReshapeGridElement multires_reshape_grid_element_for_ptex_coord( + const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord); + +/* Get original grid element for the given coordinate. */ +ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( + const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample limit surface of the base mesh. + * \{ */ + +/* Evaluate limit surface created from base mesh. + * This is the limit surface which defines tangent space for MDisps. */ +void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + float r_P[3], + float r_tangent_matrix[3][3]); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom data preparation. + * \{ */ + +/* Make sure custom data is allocated for the given level. */ +void multires_reshape_ensure_grids(struct Mesh *mesh, const int level); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Functions specific to reshaping from a set of vertices in a object position. + * \{ */ + +/* Returns truth if all coordinates were assigned. + * + * False will be returned if the number of vertex coordinates did not match required number of + * vertices at a reshape level. */ +bool multires_reshape_assign_final_coords_from_vertcos( + const MultiresReshapeContext *reshape_context, + const float (*vert_coords)[3], + const int num_vert_coords); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Functions specific to reshaping from CCG. + * \{ */ + +/* NOTE: Displacement grids to be at least at a reshape level. + * + * Return truth if all coordinates have been updated. */ +bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context, + struct SubdivCCG *subdiv_ccg); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Functions specific to reshaping from MDISPS. + * \{ */ + +/* Reads and writes to the current mesh CD_MDISPS. */ +void multires_reshape_assign_final_coords_from_mdisps( + const MultiresReshapeContext *reshape_context); + +/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */ +void multires_reshape_assign_final_coords_from_orig_mdisps( + const MultiresReshapeContext *reshape_context); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Displacement smooth. + * \{ */ + +/* Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for + * the reshape level. + * + * The result is grids which are defining mesh with a smooth surface and details starting from + * reshape level up to top level added back from original displacement grids. */ +void multires_reshape_smooth_object_grids_with_details( + const MultiresReshapeContext *reshape_context); + +/* Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for + * the reshape level. + * + * Makes it so surface on top level looks smooth. Details are not preserved + */ +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Displacement, space conversion. + * \{ */ + +/* Store original grid data, so then it's possible to calculate delta from it and add + * high-frequency content on top of reshaped grids. */ +void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context); + +void multires_reshape_object_grids_to_tangent_displacement( + const MultiresReshapeContext *reshape_context); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Apply base. + * \{ */ + +/* Update mesh coordinates to the final positions of displacement in object space. + * This is effectively desired position of base mesh vertices after canceling out displacement. + * + * NOTE: Expects that mesh's CD_MDISPS has been set to object space positions. */ +void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context); + +/* Perform better fitting of the base mesh so its subdivided version brings vertices to their + * desired locations. */ +void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context); + +/* Refine subdivision surface to the new positions of the base mesh. */ +void multires_reshape_apply_base_refine_subdiv(MultiresReshapeContext *reshape_context); + +/** \} */ + +#endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */ diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c new file mode 100644 index 00000000000..e05b5bb3179 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c @@ -0,0 +1,158 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "multires_reshape.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_subdiv_eval.h" + +void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context) +{ + Mesh *base_mesh = reshape_context->base_mesh; + const int grid_size = reshape_context->top.grid_size; + const int grid_index = grid_size * grid_size - 1; + for (int i = 0; i < base_mesh->totloop; ++i) { + MDisps *displacement_grid = &reshape_context->mdisps[i]; + const MLoop *loop = &base_mesh->mloop[i]; + MVert *vert = &base_mesh->mvert[loop->v]; + copy_v3_v3(vert->co, displacement_grid->disps[grid_index]); + } +} + +/* Assumes no is normalized; return value's sign is negative if v is on the other side of the + * plane. */ +static float v3_dist_from_plane(float v[3], float center[3], float no[3]) +{ + float s[3]; + sub_v3_v3v3(s, v, center); + return dot_v3v3(s, no); +} + +void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context) +{ + Mesh *base_mesh = reshape_context->base_mesh; + + MeshElemMap *pmap; + int *pmap_mem; + BKE_mesh_vert_poly_map_create(&pmap, + &pmap_mem, + base_mesh->mpoly, + base_mesh->mloop, + base_mesh->totvert, + base_mesh->totpoly, + base_mesh->totloop); + + float(*origco)[3] = MEM_calloc_arrayN( + base_mesh->totvert, 3 * sizeof(float), "multires apply base origco"); + for (int i = 0; i < base_mesh->totvert; i++) { + copy_v3_v3(origco[i], base_mesh->mvert[i].co); + } + + for (int i = 0; i < base_mesh->totvert; i++) { + float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3]; + + /* Don't adjust vertices not used by at least one poly. */ + if (!pmap[i].count) { + continue; + } + + /* Find center. */ + int tot = 0; + for (int j = 0; j < pmap[i].count; j++) { + const MPoly *p = &base_mesh->mpoly[pmap[i].indices[j]]; + + /* This double counts, not sure if that's bad or good. */ + for (int k = 0; k < p->totloop; k++) { + const int vndx = base_mesh->mloop[p->loopstart + k].v; + if (vndx != i) { + add_v3_v3(center, origco[vndx]); + tot++; + } + } + } + mul_v3_fl(center, 1.0f / tot); + + /* Find normal. */ + for (int j = 0; j < pmap[i].count; j++) { + const MPoly *p = &base_mesh->mpoly[pmap[i].indices[j]]; + MPoly fake_poly; + MLoop *fake_loops; + float(*fake_co)[3]; + float no[3]; + + /* Set up poly, loops, and coords in order to call BKE_mesh_calc_poly_normal_coords(). */ + fake_poly.totloop = p->totloop; + fake_poly.loopstart = 0; + fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops"); + fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co"); + + for (int k = 0; k < p->totloop; k++) { + const int vndx = base_mesh->mloop[p->loopstart + k].v; + + fake_loops[k].v = k; + + if (vndx == i) { + copy_v3_v3(fake_co[k], center); + } + else { + copy_v3_v3(fake_co[k], origco[vndx]); + } + } + + BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, (const float(*)[3])fake_co, no); + MEM_freeN(fake_loops); + MEM_freeN(fake_co); + + add_v3_v3(avg_no, no); + } + normalize_v3(avg_no); + + /* Push vertex away from the plane. */ + const float dist = v3_dist_from_plane(base_mesh->mvert[i].co, center, avg_no); + copy_v3_v3(push, avg_no); + mul_v3_fl(push, dist); + add_v3_v3(base_mesh->mvert[i].co, push); + } + + MEM_freeN(origco); + MEM_freeN(pmap); + MEM_freeN(pmap_mem); + + /* Vertices were moved around, need to update normals after all the vertices are updated + * Probably this is possible to do in the loop above, but this is rather tricky because + * we don't know all needed vertices' coordinates there yet. */ + BKE_mesh_calc_normals(base_mesh); +} + +void multires_reshape_apply_base_refine_subdiv(MultiresReshapeContext *reshape_context) +{ + BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL); +} diff --git a/source/blender/blenkernel/intern/multires_reshape_ccg.c b/source/blender/blenkernel/intern/multires_reshape_ccg.c new file mode 100644 index 00000000000..1f8c782ed46 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_ccg.c @@ -0,0 +1,72 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "multires_reshape.h" + +#include <string.h> + +#include "BLI_utildefines.h" + +#include "BKE_ccg.h" +#include "BKE_subdiv_ccg.h" + +bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context, + struct SubdivCCG *subdiv_ccg) +{ + CCGKey reshape_level_key; + BKE_subdiv_ccg_key(&reshape_level_key, subdiv_ccg, reshape_context->reshape.level); + + const int reshape_grid_size = reshape_context->reshape.grid_size; + const float reshape_grid_size_1_inv = 1.0f / (((float)reshape_grid_size) - 1.0f); + + int num_grids = subdiv_ccg->num_grids; + for (int grid_index = 0; grid_index < num_grids; ++grid_index) { + CCGElem *ccg_grid = subdiv_ccg->grids[grid_index]; + for (int y = 0; y < reshape_grid_size; ++y) { + const float v = (float)y * reshape_grid_size_1_inv; + for (int x = 0; x < reshape_grid_size; ++x) { + const float u = (float)x * reshape_grid_size_1_inv; + + GridCoord grid_coord; + grid_coord.grid_index = grid_index; + grid_coord.u = u; + grid_coord.v = v; + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord( + reshape_context, &grid_coord); + + BLI_assert(grid_element.displacement != NULL); + memcpy(grid_element.displacement, + CCG_grid_elem_co(&reshape_level_key, ccg_grid, x, y), + sizeof(float) * 3); + + if (reshape_level_key.has_mask) { + BLI_assert(grid_element.mask != NULL); + *grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y); + } + } + } + } + + return true; +} diff --git a/source/blender/blenkernel/intern/multires_reshape_legacy.c b/source/blender/blenkernel/intern/multires_reshape_legacy.c deleted file mode 100644 index 0a8248b25f1..00000000000 --- a/source/blender/blenkernel/intern/multires_reshape_legacy.c +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2018 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_scene_types.h" - -#include "BLI_utildefines.h" -#include "BLI_math_vector.h" -#include "BLI_task.h" - -#include "BKE_ccg.h" -#include "BKE_lib_id.h" -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_modifier.h" -#include "BKE_multires.h" -#include "BKE_subdiv.h" -#include "BKE_subdiv_ccg.h" -#include "BKE_subdiv_eval.h" -#include "BKE_subdiv_foreach.h" -#include "BKE_subdiv_mesh.h" - -#include "DEG_depsgraph_query.h" - -static void multires_reshape_init_mmd(MultiresModifierData *reshape_mmd, - const MultiresModifierData *mmd) -{ - *reshape_mmd = *mmd; -} - -static void multires_reshape_init_mmd_top_level(MultiresModifierData *reshape_mmd, - const MultiresModifierData *mmd) -{ - *reshape_mmd = *mmd; - reshape_mmd->lvl = reshape_mmd->totlvl; -} - -/* ============================================================================= - * General reshape implementation, reused by all particular cases. - */ - -typedef struct MultiresReshapeContext { - Subdiv *subdiv; - const Mesh *coarse_mesh; - MDisps *mdisps; - GridPaintMask *grid_paint_mask; - int top_grid_size; - int top_level; - /* Indexed by coarse face index, returns first ptex face index corresponding - * to that coarse face. */ - int *face_ptex_offset; -} MultiresReshapeContext; - -static void multires_reshape_allocate_displacement_grid(MDisps *displacement_grid, const int level) -{ - const int grid_size = BKE_subdiv_grid_size_from_level(level); - const int grid_area = grid_size * grid_size; - float(*disps)[3] = MEM_calloc_arrayN(grid_area, 3 * sizeof(float), "multires disps"); - if (displacement_grid->disps != NULL) { - MEM_freeN(displacement_grid->disps); - } - displacement_grid->disps = disps; - displacement_grid->totdisp = grid_area; - displacement_grid->level = level; -} - -static void multires_reshape_ensure_displacement_grid(MDisps *displacement_grid, const int level) -{ - if (displacement_grid->disps != NULL && displacement_grid->level == level) { - return; - } - multires_reshape_allocate_displacement_grid(displacement_grid, level); -} - -static void multires_reshape_ensure_displacement_grids(Mesh *mesh, const int grid_level) -{ - const int num_grids = mesh->totloop; - MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - multires_reshape_ensure_displacement_grid(&mdisps[grid_index], grid_level); - } -} - -static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level) -{ - GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); - if (grid_paint_masks == NULL) { - return; - } - const int num_grids = mesh->totloop; - const int grid_size = BKE_subdiv_grid_size_from_level(grid_level); - const int grid_area = grid_size * grid_size; - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index]; - if (grid_paint_mask->level == grid_level) { - continue; - } - grid_paint_mask->level = grid_level; - if (grid_paint_mask->data) { - MEM_freeN(grid_paint_mask->data); - } - grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data"); - } -} - -static void multires_reshape_ensure_grids(Mesh *mesh, const int grid_level) -{ - multires_reshape_ensure_displacement_grids(mesh, grid_level); - multires_reshape_ensure_mask_grids(mesh, grid_level); -} - -/* Convert normalized coordinate within a grid to a normalized coordinate within - * a ptex face. */ -static void multires_reshape_corner_coord_to_ptex(const MPoly *coarse_poly, - const int corner, - const float corner_u, - const float corner_v, - float *r_ptex_face_u, - float *r_ptex_face_v) -{ - if (coarse_poly->totloop == 4) { - float grid_u, grid_v; - BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v); - BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v); - } - else { - *r_ptex_face_u = corner_u; - *r_ptex_face_v = corner_v; - } -} - -/* NOTE: The tangent vectors are measured in ptex face normalized coordinates, - * which is different from grid tangent. */ -static void multires_reshape_sample_surface(Subdiv *subdiv, - const MPoly *coarse_poly, - const int corner, - const float corner_u, - const float corner_v, - const int ptex_face_index, - float r_P[3], - float r_dPdu[3], - float r_dPdv[3]) -{ - float ptex_face_u, ptex_face_v; - multires_reshape_corner_coord_to_ptex( - coarse_poly, corner, corner_u, corner_v, &ptex_face_u, &ptex_face_v); - BKE_subdiv_eval_limit_point_and_derivatives( - subdiv, ptex_face_index, ptex_face_u, ptex_face_v, r_P, r_dPdu, r_dPdv); -} - -static void multires_reshape_tangent_matrix_for_corner(const MPoly *coarse_poly, - const int coarse_corner, - const float dPdu[3], - const float dPdv[3], - float r_tangent_matrix[3][3]) -{ - /* For a quad faces we would need to flip the tangent, since they will use - * use different coordinates within displacement grid comparent to ptex - * face. */ - const bool is_quad = (coarse_poly->totloop == 4); - const int tangent_corner = is_quad ? coarse_corner : 0; - BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner); -} - -static void multires_reshape_vertex_from_final_data(MultiresReshapeContext *ctx, - const int ptex_face_index, - const float corner_u, - const float corner_v, - const int coarse_poly_index, - const int coarse_corner, - const float final_P[3], - const float final_mask) -{ - Subdiv *subdiv = ctx->subdiv; - const int grid_size = ctx->top_grid_size; - const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; - const int loop_index = coarse_poly->loopstart + coarse_corner; - /* Evaluate limit surface. */ - float P[3], dPdu[3], dPdv[3]; - multires_reshape_sample_surface( - subdiv, coarse_poly, coarse_corner, corner_u, corner_v, ptex_face_index, P, dPdu, dPdv); - /* Construct tangent matrix which matches orientation of the current - * displacement grid. */ - float tangent_matrix[3][3], inv_tangent_matrix[3][3]; - multires_reshape_tangent_matrix_for_corner( - coarse_poly, coarse_corner, dPdu, dPdv, tangent_matrix); - invert_m3_m3(inv_tangent_matrix, tangent_matrix); - /* Convert object coordinate to a tangent space of displacement grid. */ - float D[3]; - sub_v3_v3v3(D, final_P, P); - float tangent_D[3]; - mul_v3_m3v3(tangent_D, inv_tangent_matrix, D); - /* Calculate index of element within the grid. */ - float grid_u, grid_v; - BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v); - const int grid_x = (grid_u * (grid_size - 1) + 0.5f); - const int grid_y = (grid_v * (grid_size - 1) + 0.5f); - const int index = grid_y * grid_size + grid_x; - /* Write tangent displacement. */ - MDisps *displacement_grid = &ctx->mdisps[loop_index]; - copy_v3_v3(displacement_grid->disps[index], tangent_D); - /* Write mask grid. */ - if (ctx->grid_paint_mask != NULL) { - GridPaintMask *grid_paint_mask = &ctx->grid_paint_mask[loop_index]; - BLI_assert(grid_paint_mask->level == displacement_grid->level); - grid_paint_mask->data[index] = final_mask; - } -} - -/* ============================================================================= - * Helpers to propagate displacement to higher levels. - */ - -typedef struct MultiresPropagateData { - /* Number of displacement grids. */ - int num_grids; - /* Resolution level up to which displacement is known. */ - int reshape_level; - /* Resolution up to which propagation is happening, affecting all the - * levels in [reshape_level + 1, top_level]. */ - int top_level; - /* Grid sizes at the corresponding levels. */ - int reshape_grid_size; - int top_grid_size; - /* Keys to access CCG at different levels. */ - CCGKey reshape_level_key; - CCGKey top_level_key; - /* Original grid data, before any updates for reshape. - * Contains data at the reshape_level resolution level. */ - CCGElem **orig_grids_data; - /* Custom data layers from a coarse mesh. */ - MDisps *mdisps; - GridPaintMask *grid_paint_mask; -} MultiresPropagateData; - -static CCGElem **allocate_grids(CCGKey *key, int num_grids) -{ - CCGElem **grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "reshape grids*"); - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - grids[grid_index] = MEM_calloc_arrayN( - key->elem_size, key->grid_area, "reshape orig_grids_data elems"); - } - return grids; -} - -static void free_grids(CCGElem **grids, int num_grids) -{ - if (grids == NULL) { - return; - } - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - MEM_freeN(grids[grid_index]); - } - MEM_freeN(grids); -} - -/* Initialize element sizes and offsets. */ -static void multires_reshape_init_key_layers(CCGKey *key, const MultiresPropagateData *data) -{ - key->elem_size = 3 * sizeof(float); - if (data->grid_paint_mask != NULL) { - key->mask_offset = 3 * sizeof(float); - key->elem_size += sizeof(float); - key->has_mask = true; - } - else { - key->mask_offset = -1; - key->has_mask = false; - } - /* We never have normals in original grids. */ - key->normal_offset = -1; - key->has_normals = false; -} - -/* Initialize key used to access reshape grids at given level. */ -static void multires_reshape_init_level_key(CCGKey *key, - const MultiresPropagateData *data, - const int level) -{ - key->level = level; - /* Init layers. */ - multires_reshape_init_key_layers(key, data); - /* By default, only 3 floats for coordinate, */ - key->grid_size = BKE_subdiv_grid_size_from_level(key->level); - key->grid_area = key->grid_size * key->grid_size; - key->grid_bytes = key->elem_size * key->grid_area; -} - -static void multires_reshape_store_original_grids(MultiresPropagateData *data) -{ - const int num_grids = data->num_grids; - /* Original data to be backed up. */ - const MDisps *mdisps = data->mdisps; - const GridPaintMask *grid_paint_mask = data->grid_paint_mask; - /* Allocate grids for backup. */ - CCGKey *orig_key = &data->reshape_level_key; - CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids); - /* Fill in grids. */ - const int orig_grid_size = data->reshape_grid_size; - const int top_grid_size = data->top_grid_size; - const int skip = (top_grid_size - 1) / (orig_grid_size - 1); - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - CCGElem *orig_grid = orig_grids_data[grid_index]; - for (int y = 0; y < orig_grid_size; y++) { - const int top_y = y * skip; - for (int x = 0; x < orig_grid_size; x++) { - const int top_x = x * skip; - const int top_index = top_y * top_grid_size + top_x; - memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y), - mdisps[grid_index].disps[top_index], - sizeof(float) * 3); - if (orig_key->has_mask) { - *CCG_grid_elem_mask( - orig_key, orig_grid, x, y) = grid_paint_mask[grid_index].data[top_index]; - } - } - } - } - /* Store in the context. */ - data->orig_grids_data = orig_grids_data; -} - -static void multires_reshape_propagate_prepare(MultiresPropagateData *data, - Mesh *coarse_mesh, - const int reshape_level, - const int top_level) -{ - BLI_assert(reshape_level <= top_level); - memset(data, 0, sizeof(*data)); - data->num_grids = coarse_mesh->totloop; - data->reshape_level = reshape_level; - data->top_level = top_level; - if (reshape_level == top_level) { - /* Nothing to do, reshape will happen on the whole grid content. */ - return; - } - data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); - data->grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK); - data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level); - data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level); - /* Initialize keys to access CCG at different levels. */ - multires_reshape_init_level_key(&data->reshape_level_key, data, data->reshape_level); - multires_reshape_init_level_key(&data->top_level_key, data, data->top_level); - /* Make a copy of grids before reshaping, so we can calculate deltas - * later on. */ - multires_reshape_store_original_grids(data); -} - -static void multires_reshape_propagate_prepare_from_mmd(MultiresPropagateData *data, - struct Depsgraph *depsgraph, - Object *object, - const MultiresModifierData *mmd, - const int top_level, - const bool use_render_params) -{ - /* TODO(sergey): Find mode reliable way of getting current level. */ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Mesh *mesh = object->data; - const int level = multires_get_level(scene_eval, object, mmd, use_render_params, true); - multires_reshape_propagate_prepare(data, mesh, level, top_level); -} - -/* Calculate delta of changed reshape level data layers. Delta goes to a - * grids at top level (meaning, the result grids are only partially filled - * in). */ -static void multires_reshape_calculate_delta(MultiresPropagateData *data, - CCGElem **delta_grids_data) -{ - const int num_grids = data->num_grids; - /* At this point those custom data layers has updated data for the - * level we are propagating from. */ - const MDisps *mdisps = data->mdisps; - const GridPaintMask *grid_paint_mask = data->grid_paint_mask; - CCGKey *reshape_key = &data->reshape_level_key; - CCGKey *delta_level_key = &data->top_level_key; - /* Calculate delta. */ - const int top_grid_size = data->top_grid_size; - const int reshape_grid_size = data->reshape_grid_size; - const int delta_grid_size = data->top_grid_size; - const int skip = (top_grid_size - 1) / (reshape_grid_size - 1); - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index]; - CCGElem *delta_grid = delta_grids_data[grid_index]; - for (int y = 0; y < reshape_grid_size; y++) { - const int top_y = y * skip; - for (int x = 0; x < reshape_grid_size; x++) { - const int top_x = x * skip; - const int top_index = top_y * delta_grid_size + top_x; - sub_v3_v3v3(CCG_grid_elem_co(delta_level_key, delta_grid, top_x, top_y), - mdisps[grid_index].disps[top_index], - CCG_grid_elem_co(reshape_key, orig_grid, x, y)); - if (delta_level_key->has_mask) { - const float old_mask_value = *CCG_grid_elem_mask(reshape_key, orig_grid, x, y); - const float new_mask_value = grid_paint_mask[grid_index].data[top_index]; - *CCG_grid_elem_mask(delta_level_key, delta_grid, top_x, top_y) = new_mask_value - - old_mask_value; - } - } - } - } -} - -/* Makes it so delta is propagated onto all the higher levels, but is also - * that this delta is smoothed in a way that it does not cause artifacts on - * boundaries. */ - -typedef struct MultiresPropagateCornerData { - float coord_delta[3]; - float mask_delta; -} MultiresPropagateCornerData; - -BLI_INLINE void multires_reshape_propagate_init_patch_corners( - MultiresPropagateData *data, - CCGElem *delta_grid, - const int patch_x, - const int patch_y, - MultiresPropagateCornerData r_corners[4]) -{ - CCGKey *delta_level_key = &data->top_level_key; - const int orig_grid_size = data->reshape_grid_size; - const int top_grid_size = data->top_grid_size; - const int skip = (top_grid_size - 1) / (orig_grid_size - 1); - const int x = patch_x * skip; - const int y = patch_y * skip; - /* Store coordinate deltas. */ - copy_v3_v3(r_corners[0].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x, y)); - copy_v3_v3(r_corners[1].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y)); - copy_v3_v3(r_corners[2].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip)); - copy_v3_v3(r_corners[3].coord_delta, - CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y + skip)); - if (delta_level_key->has_mask) { - r_corners[0].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y); - r_corners[1].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x + skip, y); - r_corners[2].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y + skip); - r_corners[3].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x + skip, y + skip); - } -} - -BLI_INLINE void multires_reshape_propagate_interpolate_coord( - float delta[3], const MultiresPropagateCornerData corners[4], const float weights[4]) -{ - interp_v3_v3v3v3v3(delta, - corners[0].coord_delta, - corners[1].coord_delta, - corners[2].coord_delta, - corners[3].coord_delta, - weights); -} - -BLI_INLINE float multires_reshape_propagate_interpolate_mask( - const MultiresPropagateCornerData corners[4], const float weights[4]) -{ - return corners[0].mask_delta * weights[0] + corners[1].mask_delta * weights[1] + - corners[2].mask_delta * weights[2] + corners[3].mask_delta * weights[3]; -} - -BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch(MultiresPropagateData *data, - CCGElem *delta_grid, - const int patch_x, - const int patch_y) -{ - CCGKey *delta_level_key = &data->top_level_key; - const int orig_grid_size = data->reshape_grid_size; - const int top_grid_size = data->top_grid_size; - const int skip = (top_grid_size - 1) / (orig_grid_size - 1); - const float skip_inv = 1.0f / (float)skip; - MultiresPropagateCornerData corners[4]; - multires_reshape_propagate_init_patch_corners(data, delta_grid, patch_x, patch_y, corners); - const int start_x = patch_x * skip; - const int start_y = patch_y * skip; - for (int y = 0; y <= skip; y++) { - const float v = (float)y * skip_inv; - const int final_y = start_y + y; - for (int x = 0; x <= skip; x++) { - const float u = (float)x * skip_inv; - const int final_x = start_x + x; - const float linear_weights[4] = { - (1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v}; - multires_reshape_propagate_interpolate_coord( - CCG_grid_elem_co(delta_level_key, delta_grid, final_x, final_y), - corners, - linear_weights); - if (delta_level_key->has_mask) { - float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid, final_x, final_y); - *mask = multires_reshape_propagate_interpolate_mask(corners, linear_weights); - } - } - } -} - -BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid(MultiresPropagateData *data, - CCGElem *delta_grid) -{ - const int orig_grid_size = data->reshape_grid_size; - for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) { - for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) { - multires_reshape_propagate_and_smooth_delta_grid_patch(data, delta_grid, patch_x, patch_y); - } - } -} - -/* Entry point to propagate+smooth. */ -static void multires_reshape_propagate_and_smooth_delta(MultiresPropagateData *data, - CCGElem **delta_grids_data) -{ - const int num_grids = data->num_grids; - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - CCGElem *delta_grid = delta_grids_data[grid_index]; - multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid); - } -} - -/* Apply smoothed deltas on the actual data layers. */ -static void multires_reshape_propagate_apply_delta(MultiresPropagateData *data, - CCGElem **delta_grids_data) -{ - const int num_grids = data->num_grids; - /* At this point those custom data layers has updated data for the - * level we are propagating from. */ - MDisps *mdisps = data->mdisps; - GridPaintMask *grid_paint_mask = data->grid_paint_mask; - CCGKey *orig_key = &data->reshape_level_key; - CCGKey *delta_level_key = &data->top_level_key; - CCGElem **orig_grids_data = data->orig_grids_data; - const int orig_grid_size = data->reshape_grid_size; - const int top_grid_size = data->top_grid_size; - const int skip = (top_grid_size - 1) / (orig_grid_size - 1); - /* Restore grid values at the reshape level. Those values are to be changed - * to the accommodate for the smooth delta. */ - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - CCGElem *orig_grid = orig_grids_data[grid_index]; - for (int y = 0; y < orig_grid_size; y++) { - const int top_y = y * skip; - for (int x = 0; x < orig_grid_size; x++) { - const int top_x = x * skip; - const int top_index = top_y * top_grid_size + top_x; - copy_v3_v3(mdisps[grid_index].disps[top_index], - CCG_grid_elem_co(orig_key, orig_grid, x, y)); - if (grid_paint_mask != NULL) { - grid_paint_mask[grid_index].data[top_index] = *CCG_grid_elem_mask( - orig_key, orig_grid, x, y); - } - } - } - } - /* Add smoothed delta to all the levels. */ - for (int grid_index = 0; grid_index < num_grids; grid_index++) { - CCGElem *delta_grid = delta_grids_data[grid_index]; - for (int y = 0; y < top_grid_size; y++) { - for (int x = 0; x < top_grid_size; x++) { - const int top_index = y * top_grid_size + x; - add_v3_v3(mdisps[grid_index].disps[top_index], - CCG_grid_elem_co(delta_level_key, delta_grid, x, y)); - if (delta_level_key->has_mask) { - grid_paint_mask[grid_index].data[top_index] += *CCG_grid_elem_mask( - delta_level_key, delta_grid, x, y); - } - } - } - } -} - -static void multires_reshape_propagate(MultiresPropagateData *data) -{ - if (data->reshape_level == data->top_level) { - return; - } - const int num_grids = data->num_grids; - /* Calculate delta made at the reshape level. */ - CCGKey *delta_level_key = &data->top_level_key; - CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids); - multires_reshape_calculate_delta(data, delta_grids_data); - /* Propagate deltas to the higher levels. */ - multires_reshape_propagate_and_smooth_delta(data, delta_grids_data); - /* Finally, apply smoothed deltas. */ - multires_reshape_propagate_apply_delta(data, delta_grids_data); - /* Cleanup. */ - free_grids(delta_grids_data, num_grids); -} - -static void multires_reshape_propagate_free(MultiresPropagateData *data) -{ - free_grids(data->orig_grids_data, data->num_grids); -} - -/* ============================================================================= - * Reshape from deformed vertex coordinates. - */ - -typedef struct MultiresReshapeFromDeformedVertsContext { - MultiresReshapeContext reshape_ctx; - const float (*deformed_verts)[3]; - int num_deformed_verts; -} MultiresReshapeFromDeformedVertsContext; - -static bool multires_reshape_topology_info(const SubdivForeachContext *foreach_context, - const int num_vertices, - const int UNUSED(num_edges), - const int UNUSED(num_loops), - const int UNUSED(num_polygons)) -{ - MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; - if (num_vertices != ctx->num_deformed_verts) { - return false; - } - return true; -} - -/* Will run reshaping for all grid elements which are adjacent to the given - * one. This is the way to ensure continuity of displacement stored in the - * grids across the inner boundaries of the grids. */ -static void multires_reshape_neighour_boundary_vertices(MultiresReshapeContext *ctx, - const int UNUSED(ptex_face_index), - const float corner_u, - const float corner_v, - const int coarse_poly_index, - const int coarse_corner, - const float final_P[3], - const float final_mask) -{ - const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; - const int num_corners = coarse_poly->totloop; - const int start_ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; - const bool is_quad = (coarse_poly->totloop == 4); - if (corner_u == 1.0f && corner_v == 1.0f) { - for (int current_corner = 0; current_corner < num_corners; current_corner++) { - if (current_corner == coarse_corner) { - continue; - } - const int current_ptex_face_index = is_quad ? start_ptex_face_index : - start_ptex_face_index + current_corner; - multires_reshape_vertex_from_final_data(ctx, - current_ptex_face_index, - 1.0f, - 1.0f, - coarse_poly_index, - current_corner, - final_P, - final_mask); - } - } - else if (corner_u == 1.0f) { - const float next_corner_index = (coarse_corner + 1) % num_corners; - const float next_corner_u = corner_v; - const float next_corner_v = 1.0f; - const int next_ptex_face_index = is_quad ? start_ptex_face_index : - start_ptex_face_index + next_corner_index; - multires_reshape_vertex_from_final_data(ctx, - next_ptex_face_index, - next_corner_u, - next_corner_v, - coarse_poly_index, - next_corner_index, - final_P, - final_mask); - } - else if (corner_v == 1.0f) { - const float prev_corner_index = (coarse_corner + num_corners - 1) % num_corners; - const float prev_corner_u = 1.0f; - const float prev_corner_v = corner_u; - const int prev_ptex_face_index = is_quad ? start_ptex_face_index : - start_ptex_face_index + prev_corner_index; - multires_reshape_vertex_from_final_data(ctx, - prev_ptex_face_index, - prev_corner_u, - prev_corner_v, - coarse_poly_index, - prev_corner_index, - final_P, - final_mask); - } -} - -static void multires_reshape_vertex(MultiresReshapeFromDeformedVertsContext *ctx, - const int ptex_face_index, - const float u, - const float v, - const int coarse_poly_index, - const int coarse_corner, - const int subdiv_vertex_index) -{ - const float *final_P = ctx->deformed_verts[subdiv_vertex_index]; - const Mesh *coarse_mesh = ctx->reshape_ctx.coarse_mesh; - const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; - const bool is_quad = (coarse_poly->totloop == 4); - float corner_u, corner_v; - int actual_coarse_corner; - if (is_quad) { - actual_coarse_corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v); - } - else { - actual_coarse_corner = coarse_corner; - corner_u = u; - corner_v = v; - } - multires_reshape_vertex_from_final_data(&ctx->reshape_ctx, - ptex_face_index, - corner_u, - corner_v, - coarse_poly_index, - actual_coarse_corner, - final_P, - 0.0f); - multires_reshape_neighour_boundary_vertices(&ctx->reshape_ctx, - ptex_face_index, - corner_u, - corner_v, - coarse_poly_index, - actual_coarse_corner, - final_P, - 0.0f); -} - -static void multires_reshape_vertex_inner(const SubdivForeachContext *foreach_context, - void *UNUSED(tls_v), - const int ptex_face_index, - const float u, - const float v, - const int coarse_poly_index, - const int coarse_corner, - const int subdiv_vertex_index) -{ - MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; - multires_reshape_vertex( - ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index); -} - -static void multires_reshape_vertex_every_corner( - const struct SubdivForeachContext *foreach_context, - void *UNUSED(tls_v), - const int ptex_face_index, - const float u, - const float v, - const int UNUSED(coarse_vertex_index), - const int coarse_poly_index, - const int coarse_corner, - const int subdiv_vertex_index) -{ - MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; - multires_reshape_vertex( - ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index); -} - -static void multires_reshape_vertex_every_edge(const struct SubdivForeachContext *foreach_context, - void *UNUSED(tls_v), - const int ptex_face_index, - const float u, - const float v, - const int UNUSED(coarse_edge_index), - const int coarse_poly_index, - const int coarse_corner, - const int subdiv_vertex_index) -{ - MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; - multires_reshape_vertex( - ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index); -} - -static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph, - /*const*/ Object *object, - const MultiresModifierData *mmd) -{ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *object_eval = DEG_get_evaluated_object(depsgraph, object); - Mesh *deformed_mesh = mesh_get_eval_deform( - depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH); - 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, NULL)) { - BKE_subdiv_free(subdiv); - return NULL; - } - return subdiv; -} - -static bool multires_reshape_from_vertcos(struct Depsgraph *depsgraph, - Object *object, - const MultiresModifierData *mmd, - const float (*deformed_verts)[3], - const int num_deformed_verts, - const bool use_render_params) -{ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Mesh *coarse_mesh = object->data; - MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); - /* Pick maximum between multires level and displacement level. - * This is because mesh can be used by objects with multires at different - * levels. - * - * TODO(sergey): At this point it should be possible to always use - * mdisps->level. */ - const int top_level = max_ii(mmd->totlvl, mdisps->level); - /* Make sure displacement grids are ready. */ - multires_reshape_ensure_grids(coarse_mesh, top_level); - /* Initialize subdivision surface. */ - Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd); - if (subdiv == NULL) { - return false; - } - /* Construct context. */ - MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = { - .reshape_ctx = - { - .subdiv = subdiv, - .coarse_mesh = coarse_mesh, - .mdisps = mdisps, - .grid_paint_mask = NULL, - .top_grid_size = BKE_subdiv_grid_size_from_level(top_level), - .top_level = top_level, - .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv), - }, - .deformed_verts = deformed_verts, - .num_deformed_verts = num_deformed_verts, - }; - SubdivForeachContext foreach_context = { - .topology_info = multires_reshape_topology_info, - .vertex_inner = multires_reshape_vertex_inner, - .vertex_every_edge = multires_reshape_vertex_every_edge, - .vertex_every_corner = multires_reshape_vertex_every_corner, - .user_data = &reshape_deformed_verts_ctx, - }; - /* Initialize mesh rasterization settings. */ - SubdivToMeshSettings mesh_settings; - BKE_multires_subdiv_mesh_settings_init( - &mesh_settings, scene_eval, object, mmd, use_render_params, true); - /* Initialize propagation to higher levels. */ - MultiresPropagateData propagate_data; - multires_reshape_propagate_prepare_from_mmd( - &propagate_data, depsgraph, object, mmd, top_level, use_render_params); - /* Run all the callbacks. */ - BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh); - BKE_subdiv_free(subdiv); - /* Update higher levels if needed. */ - multires_reshape_propagate(&propagate_data); - multires_reshape_propagate_free(&propagate_data); - return true; -} - -/* ============================================================================= - * Reshape from object. - */ - -/* Returns truth on success, false otherwise. - * - * This function might fail in cases like source and destination not having - * matched amount of vertices. */ -bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph, - MultiresModifierData *mmd, - Object *dst, - Object *src) -{ - /* Would be cool to support this eventually, but it is very tricky to match - * vertices order even for meshes, when mixing meshes and other objects it's - * even more tricky. */ - if (src->type != OB_MESH) { - return false; - } - MultiresModifierData reshape_mmd; - multires_reshape_init_mmd(&reshape_mmd, mmd); - /* Get evaluated vertices locations to reshape to. */ - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Object *src_eval = DEG_get_evaluated_object(depsgraph, src); - Mesh *src_mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, src_eval, &CD_MASK_BAREMESH); - int num_deformed_verts; - float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(src_mesh_eval, &num_deformed_verts); - bool result = multires_reshape_from_vertcos( - depsgraph, dst, &reshape_mmd, deformed_verts, num_deformed_verts, false); - MEM_freeN(deformed_verts); - return result; -} - -/* ============================================================================= - * Reshape from modifier. - */ - -bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph, - MultiresModifierData *mmd, - Object *object, - ModifierData *md) -{ - MultiresModifierData highest_mmd; - /* It is possible that the current subdivision level of multires is lower - * that it's maximum possible one (i.e., viewport is set to a lower level - * for the performance purposes). But even then, we want all the multires - * levels to be reshaped. Most accurate way to do so is to ignore all - * simplifications and calculate deformation modifier for the highest - * possible multires level. - * Alternative would be propagate displacement from current level to a - * higher ones, but that is likely to cause artifacts. */ - multires_reshape_init_mmd_top_level(&highest_mmd, mmd); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - /* Perform sanity checks and early output. */ - if (multires_get_level(scene_eval, object, &highest_mmd, false, true) == 0) { - return false; - } - /* Create mesh for the multires, ignoring any further modifiers (leading - * deformation modifiers will be applied though). */ - Mesh *multires_mesh = BKE_multires_create_mesh(depsgraph, scene_eval, &highest_mmd, object); - int num_deformed_verts; - float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(multires_mesh, &num_deformed_verts); - /* Apply deformation modifier on the multires, */ - const ModifierEvalContext modifier_ctx = { - .depsgraph = depsgraph, - .object = object, - .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, - }; - modwrap_deformVerts(md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert); - BKE_id_free(NULL, multires_mesh); - /* Reshaping */ - bool result = multires_reshape_from_vertcos( - depsgraph, object, &highest_mmd, deformed_verts, num_deformed_verts, false); - /* Cleanup */ - MEM_freeN(deformed_verts); - return result; -} - -/* ============================================================================= - * Reshape from grids. - */ - -typedef struct ReshapeFromCCGTaskData { - MultiresReshapeContext reshape_ctx; - const CCGKey *key; - /*const*/ CCGElem **grids; -} ReshapeFromCCGTaskData; - -static void reshape_from_ccg_task(void *__restrict userdata, - const int coarse_poly_index, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - ReshapeFromCCGTaskData *data = userdata; - const CCGKey *key = data->key; - /*const*/ CCGElem **grids = data->grids; - const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh; - const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; - const int key_grid_size = key->grid_size; - const int key_grid_size_1 = key_grid_size - 1; - const int resolution = key_grid_size; - const float resolution_1_inv = 1.0f / (float)(resolution - 1); - const int start_ptex_face_index = data->reshape_ctx.face_ptex_offset[coarse_poly_index]; - const bool is_quad = (coarse_poly->totloop == 4); - for (int corner = 0; corner < coarse_poly->totloop; corner++) { - for (int y = 0; y < resolution; y++) { - const float corner_v = y * resolution_1_inv; - for (int x = 0; x < resolution; x++) { - const float corner_u = x * resolution_1_inv; - /* Quad faces consists of a single ptex face. */ - const int ptex_face_index = is_quad ? start_ptex_face_index : - start_ptex_face_index + corner; - float grid_u, grid_v; - BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v); - /*const*/ CCGElem *grid = grids[coarse_poly->loopstart + corner]; - /*const*/ CCGElem *grid_element = CCG_grid_elem( - key, grid, key_grid_size_1 * grid_u, key_grid_size_1 * grid_v); - const float *final_P = CCG_elem_co(key, grid_element); - float final_mask = 0.0f; - if (key->has_mask) { - final_mask = *CCG_elem_mask(key, grid_element); - } - multires_reshape_vertex_from_final_data(&data->reshape_ctx, - ptex_face_index, - corner_u, - corner_v, - coarse_poly_index, - corner, - final_P, - final_mask); - } - } - } -} - -bool multiresModifier_reshapeFromCCG(const int tot_level, Mesh *coarse_mesh, SubdivCCG *subdiv_ccg) -{ - CCGKey key; - BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); - /* Sanity checks. */ - if (coarse_mesh->totloop != subdiv_ccg->num_grids) { - /* Grids are supposed to eb created for each face-cornder (aka loop). */ - return false; - } - MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); - if (mdisps == NULL) { - /* Multires displacement has been removed before current changes were - * applies to all the levels. */ - return false; - } - GridPaintMask *grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK); - Subdiv *subdiv = subdiv_ccg->subdiv; - /* Pick maximum between multires level and displacement level. - * This is because mesh can be used by objects with multires at different - * levels. - * - * TODO(sergey): At this point it should be possible to always use - * mdisps->level. */ - const int top_level = max_ii(tot_level, mdisps->level); - /* Make sure displacement grids are ready. */ - multires_reshape_ensure_grids(coarse_mesh, top_level); - /* Construct context. */ - ReshapeFromCCGTaskData data = { - .reshape_ctx = - { - .subdiv = subdiv, - .coarse_mesh = coarse_mesh, - .mdisps = mdisps, - .grid_paint_mask = grid_paint_mask, - .top_grid_size = BKE_subdiv_grid_size_from_level(top_level), - .top_level = top_level, - .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv), - }, - .key = &key, - .grids = subdiv_ccg->grids, - }; - /* Initialize propagation to higher levels. */ - MultiresPropagateData propagate_data; - multires_reshape_propagate_prepare(&propagate_data, coarse_mesh, key.level, top_level); - /* Threaded grids iteration. */ - TaskParallelSettings parallel_range_settings; - BLI_parallel_range_settings_defaults(¶llel_range_settings); - BLI_task_parallel_range( - 0, coarse_mesh->totpoly, &data, reshape_from_ccg_task, ¶llel_range_settings); - /* Update higher levels if needed. */ - multires_reshape_propagate(&propagate_data); - multires_reshape_propagate_free(&propagate_data); - return true; -} diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c new file mode 100644 index 00000000000..0a9a17d7bd8 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -0,0 +1,1064 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "multires_reshape.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_task.h" + +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" + +#include "opensubdiv_converter_capi.h" +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_topology_refiner_capi.h" + +#include "subdiv_converter.h" + +typedef struct SurfacePoint { + float P[3]; + float tangent_matrix[3][3]; +} SurfacePoint; + +typedef struct SurfaceGrid { + SurfacePoint *points; +} SurfaceGrid; + +typedef struct Vertex { + /* All grid coordinates which the vertex corresponding to. + * For a vertices which are created from inner points of grids there is always one coordinate. */ + int num_grid_coords; + GridCoord *grid_coords; + + bool is_infinite_sharp; +} Vertex; + +typedef struct Corner { + const Vertex *vertex; + int grid_index; +} Corner; + +typedef struct Dace { + int start_corner_index; + int num_corners; +} Dace; + +typedef struct MultiresReshapeSmoothContext { + const MultiresReshapeContext *reshape_context; + + // Geometry at a reshape multires level. + struct { + int num_vertices; + Vertex *vertices; + + int num_corners; + Corner *corners; + + int num_faces; + Dace *faces; + } geometry; + + /* Subdivision surface created for geometry at a reshape level. */ + Subdiv *reshape_subdiv; + + SurfaceGrid *base_surface_grids; +} MultiresReshapeSmoothContext; + +/* ================================================================================================ + * Masks. + */ + +/* Interpolate mask grid at a reshape level. + * Will return 0 if there is no masks custom data layer. */ +static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_smooth_context, + const GridCoord *grid_coord) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + if (reshape_context->grid_paint_masks == NULL) { + return 0.0f; + } + + const GridPaintMask *grid = &reshape_context->orig.grid_paint_masks[grid_coord->grid_index]; + const int grid_size = BKE_subdiv_grid_size_from_level(grid->level); + const int grid_size_1 = grid_size - 1; + const float grid_size_1_inv = 1.0f / (float)(grid_size_1); + + const float x_f = grid_coord->u * grid_size_1; + const float y_f = grid_coord->v * grid_size_1; + + const int x_i = x_f; + const int y_i = y_f; + const int x_n_i = (x_i == grid_size - 1) ? (x_i) : (x_i + 1); + const int y_n_i = (y_i == grid_size - 1) ? (y_i) : (y_i + 1); + + const int corners[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}}; + float mask_elements[4]; + for (int i = 0; i < 4; ++i) { + GridCoord corner_grid_coord; + corner_grid_coord.grid_index = grid_coord->grid_index; + corner_grid_coord.u = corners[i][0] * grid_size_1_inv; + corner_grid_coord.v = corners[i][1] * grid_size_1_inv; + + ReshapeConstGridElement element = multires_reshape_orig_grid_element_for_grid_coord( + reshape_context, &corner_grid_coord); + mask_elements[i] = element.mask; + } + + const float u = x_f - x_i; + const float v = y_f - y_i; + const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v}; + + return mask_elements[0] * weights[0] + mask_elements[1] * weights[1] + + mask_elements[2] * weights[2] + mask_elements[3] * weights[3]; +} + +/* ================================================================================================ + * Surface. + */ + +static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + const int num_grids = reshape_context->num_grids; + const int grid_size = reshape_context->top.grid_size; + const int grid_area = grid_size * grid_size; + + SurfaceGrid *surface_grid = MEM_malloc_arrayN(num_grids, sizeof(SurfaceGrid), "delta grids"); + + for (int grid_index = 0; grid_index < num_grids; ++grid_index) { + surface_grid[grid_index].points = MEM_calloc_arrayN( + sizeof(SurfacePoint), grid_area, "delta grid dispalcement"); + } + + reshape_smooth_context->base_surface_grids = surface_grid; +} + +static void base_surface_grids_free(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + if (reshape_smooth_context->base_surface_grids == NULL) { + return; + } + + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + const int num_grids = reshape_context->num_grids; + for (int grid_index = 0; grid_index < num_grids; ++grid_index) { + MEM_freeN(reshape_smooth_context->base_surface_grids[grid_index].points); + } + MEM_freeN(reshape_smooth_context->base_surface_grids); +} + +static SurfacePoint *base_surface_grids_read( + const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + const int grid_index = grid_coord->grid_index; + const int grid_size = reshape_context->top.grid_size; + const int grid_x = lround(grid_coord->u * (grid_size - 1)); + const int grid_y = lround(grid_coord->v * (grid_size - 1)); + const int grid_element_index = grid_y * grid_size + grid_x; + + SurfaceGrid *surface_grid = &reshape_smooth_context->base_surface_grids[grid_index]; + return &surface_grid->points[grid_element_index]; +} + +static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape_smooth_context, + const GridCoord *grid_coord, + float P[3], + float tangent_matrix[3][3]) +{ + SurfacePoint *point = base_surface_grids_read(reshape_smooth_context, grid_coord); + copy_v3_v3(point->P, P); + copy_m3_m3(point->tangent_matrix, tangent_matrix); +} + +/* ================================================================================================ + * Evaluation of subdivision surface at a reshape level. + */ + +typedef void (*ForeachTopLevelGridCoordCallback)( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *ptex_coord, + const GridCoord *grid_coord, + void *userdata_v); + +typedef struct ForeachTopLevelGridCoordTaskData { + const MultiresReshapeSmoothContext *reshape_smooth_context; + + int inner_grid_size; + float inner_grid_size_1_inv; + + ForeachTopLevelGridCoordCallback callback; + void *callback_userdata_v; +} ForeachHighLevelCoordTaskData; + +/* Find grid index which given face was created for. */ +static int get_face_grid_index(const MultiresReshapeSmoothContext *reshape_smooth_context, + const Dace *face) +{ + const Corner *first_corner = &reshape_smooth_context->geometry.corners[face->start_corner_index]; + const int grid_index = first_corner->grid_index; + +#ifndef NDEBUG + for (int face_corner = 0; face_corner < face->num_corners; ++face_corner) { + const int corner_index = face->start_corner_index + face_corner; + const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index]; + BLI_assert(corner->grid_index == grid_index); + } +#endif + + return grid_index; +} + +static GridCoord *vertex_grid_coord_with_grid_index(const Vertex *vertex, const int grid_index) +{ + for (int i = 0; i < vertex->num_grid_coords; ++i) { + if (vertex->grid_coords[i].grid_index == grid_index) { + return &vertex->grid_coords[i]; + } + } + return NULL; +} + +/* Get grid coordinates which correspond to corners of the given face. + * All the grid coordinates will be from the same grid index. */ +static void grid_coords_from_face_vertices( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const Dace *face, + const GridCoord *grid_coords[]) +{ + BLI_assert(face->num_corners == 4); + + const int grid_index = get_face_grid_index(reshape_smooth_context, face); + BLI_assert(grid_index != -1); + + for (int i = 0; i < face->num_corners; ++i) { + const int corner_index = face->start_corner_index + i; + const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index]; + grid_coords[i] = vertex_grid_coord_with_grid_index(corner->vertex, grid_index); + BLI_assert(grid_coords[i] != NULL); + } +} + +static float lerp(float t, float a, float b) +{ + return (a + t * (b - a)); +} + +static void interpolate_grid_coord(GridCoord *result, + const GridCoord *face_grid_coords[4], + const float u, + const float v) +{ + /* + * v + * ^ + * | (3) -------- (2) + * | | | + * | | | + * | | | + * | | | + * | (0) -------- (1) + * *--------------------------> u + */ + + const float u01 = lerp(u, face_grid_coords[0]->u, face_grid_coords[1]->u); + const float u32 = lerp(u, face_grid_coords[3]->u, face_grid_coords[2]->u); + + const float v03 = lerp(v, face_grid_coords[0]->v, face_grid_coords[3]->v); + const float v12 = lerp(v, face_grid_coords[1]->v, face_grid_coords[2]->v); + + result->grid_index = face_grid_coords[0]->grid_index; + result->u = lerp(v, u01, u32); + result->v = lerp(u, v03, v12); +} + +static void foreach_toplevel_grid_coord_task(void *__restrict userdata_v, + const int face_index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ForeachHighLevelCoordTaskData *data = userdata_v; + + const MultiresReshapeSmoothContext *reshape_smooth_context = data->reshape_smooth_context; + const int inner_grid_size = data->inner_grid_size; + const float inner_grid_size_1_inv = data->inner_grid_size_1_inv; + + const Dace *face = &reshape_smooth_context->geometry.faces[face_index]; + const GridCoord *face_grid_coords[4]; + grid_coords_from_face_vertices(reshape_smooth_context, face, face_grid_coords); + + for (int y = 0; y < inner_grid_size; ++y) { + const float ptex_v = (float)y * inner_grid_size_1_inv; + for (int x = 0; x < inner_grid_size; ++x) { + const float ptex_u = (float)x * inner_grid_size_1_inv; + + PTexCoord ptex_coord; + ptex_coord.ptex_face_index = face_index; + ptex_coord.u = ptex_u; + ptex_coord.v = ptex_v; + + GridCoord grid_coord; + interpolate_grid_coord(&grid_coord, face_grid_coords, ptex_u, ptex_v); + + data->callback(reshape_smooth_context, &ptex_coord, &grid_coord, data->callback_userdata_v); + } + } +} + +static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *reshape_smooth_context, + ForeachTopLevelGridCoordCallback callback, + void *callback_userdata_v) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const int level_difference = (reshape_context->top.level - reshape_context->reshape.level); + + ForeachHighLevelCoordTaskData data; + data.reshape_smooth_context = reshape_smooth_context; + data.inner_grid_size = (1 << level_difference) + 1; + data.inner_grid_size_1_inv = 1.0f / (float)(data.inner_grid_size - 1); + data.callback = callback; + data.callback_userdata_v = callback_userdata_v; + + TaskParallelSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.min_iter_per_thread = 1; + + const int num_faces = reshape_smooth_context->geometry.num_faces; + BLI_task_parallel_range( + 0, num_faces, &data, foreach_toplevel_grid_coord_task, ¶llel_range_settings); +} + +/* ================================================================================================ + * Generation of a topology information for OpenSubdiv converter. + * + * Calculates vertices, their coordinates in the original grids, and connections of them so then + * it's easy to create OpenSubdiv's topology refiner. */ + +static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context, + const MultiresReshapeContext *reshape_context) +{ + reshape_smooth_context->reshape_context = reshape_context; + + reshape_smooth_context->geometry.num_vertices = 0; + reshape_smooth_context->geometry.vertices = NULL; + reshape_smooth_context->geometry.num_corners = 0; + reshape_smooth_context->geometry.corners = NULL; + + reshape_smooth_context->reshape_subdiv = NULL; + reshape_smooth_context->base_surface_grids = NULL; +} + +static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + if (reshape_smooth_context->geometry.vertices != NULL) { + for (int i = 0; i < reshape_smooth_context->geometry.num_vertices; ++i) { + MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices[i].grid_coords); + } + } + MEM_SAFE_FREE(reshape_smooth_context->geometry.vertices); + MEM_SAFE_FREE(reshape_smooth_context->geometry.corners); + MEM_SAFE_FREE(reshape_smooth_context->geometry.faces); +} + +static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + if (reshape_smooth_context->reshape_subdiv == NULL) { + return; + } + BKE_subdiv_free(reshape_smooth_context->reshape_subdiv); +} + +static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + context_free_geometry(reshape_smooth_context); + context_free_subdiv(reshape_smooth_context); + base_surface_grids_free(reshape_smooth_context); +} + +static bool foreach_topology_info(const SubdivForeachContext *foreach_context, + const int num_vertices, + const int UNUSED(num_edges), + const int num_loops, + const int num_polygons) +{ + MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + + /* NOTE: Calloc so the counters are re-set to 0 "for free". */ + reshape_smooth_context->geometry.num_vertices = num_vertices; + reshape_smooth_context->geometry.vertices = MEM_calloc_arrayN( + sizeof(Vertex), num_vertices, "smooth vertices"); + + reshape_smooth_context->geometry.num_corners = num_loops; + reshape_smooth_context->geometry.corners = MEM_malloc_arrayN( + sizeof(Corner), num_loops, "smooth corners"); + + reshape_smooth_context->geometry.num_faces = num_polygons; + reshape_smooth_context->geometry.faces = MEM_malloc_arrayN( + sizeof(Dace), num_polygons, "smooth faces"); + + return true; +} + +static void foreach_single_vertex(const SubdivForeachContext *foreach_context, + const GridCoord *grid_coord, + const int subdiv_vertex_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + + BLI_assert(subdiv_vertex_index < reshape_smooth_context->geometry.num_vertices); + + Vertex *vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index]; + + vertex->grid_coords = MEM_reallocN(vertex->grid_coords, + sizeof(Vertex) * (vertex->num_grid_coords + 1)); + vertex->grid_coords[vertex->num_grid_coords] = *grid_coord; + ++vertex->num_grid_coords; +} + +/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */ +static void foreach_vertex(const SubdivForeachContext *foreach_context, + const PTexCoord *ptex_coord, + const int subdiv_vertex_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + const GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord); + const int face_index = multires_reshape_grid_to_face_index(reshape_context, + grid_coord.grid_index); + + const Mesh *base_mesh = reshape_context->base_mesh; + const MPoly *base_poly = &base_mesh->mpoly[face_index]; + const int num_corners = base_poly->totloop; + const int start_grid_index = reshape_context->face_start_grid_index[face_index]; + const int corner = grid_coord.grid_index - start_grid_index; + + if (grid_coord.u == 0.0f && grid_coord.v == 0.0f) { + for (int current_corner = 0; current_corner < num_corners; ++current_corner) { + GridCoord corner_grid_coord = grid_coord; + corner_grid_coord.grid_index = start_grid_index + current_corner; + foreach_single_vertex(foreach_context, &corner_grid_coord, subdiv_vertex_index); + } + return; + } + + foreach_single_vertex(foreach_context, &grid_coord, subdiv_vertex_index); + + if (grid_coord.u == 0.0f) { + GridCoord prev_grid_coord; + prev_grid_coord.grid_index = start_grid_index + ((corner + num_corners - 1) % num_corners); + prev_grid_coord.u = grid_coord.v; + prev_grid_coord.v = 0.0f; + + foreach_single_vertex(foreach_context, &prev_grid_coord, subdiv_vertex_index); + } + + if (grid_coord.v == 0.0f) { + GridCoord next_grid_coord; + next_grid_coord.grid_index = start_grid_index + ((corner + 1) % num_corners); + next_grid_coord.u = 0.0f; + next_grid_coord.v = grid_coord.u; + + foreach_single_vertex(foreach_context, &next_grid_coord, subdiv_vertex_index); + } +} + +static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_vertex_index), + const int UNUSED(coarse_face_index), + const int UNUSED(coarse_face_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_edge_index), + const int UNUSED(coarse_face_index), + const int UNUSED(coarse_face_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +static void foreach_loop(const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int UNUSED(ptex_face_index), + const float UNUSED(ptex_face_u), + const float UNUSED(ptex_face_v), + const int UNUSED(coarse_loop_index), + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_loop_index, + const int subdiv_vertex_index, + const int UNUSED(subdiv_edge_index)) +{ + MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + BLI_assert(subdiv_loop_index < reshape_smooth_context->geometry.num_corners); + + Corner *corner = &reshape_smooth_context->geometry.corners[subdiv_loop_index]; + corner->vertex = &reshape_smooth_context->geometry.vertices[subdiv_vertex_index]; + + const int first_grid_index = reshape_context->face_start_grid_index[coarse_poly_index]; + corner->grid_index = first_grid_index + coarse_corner; +} + +static void foreach_poly(const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int UNUSED(coarse_poly_index), + const int subdiv_poly_index, + const int start_loop_index, + const int num_loops) +{ + MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + + BLI_assert(subdiv_poly_index < reshape_smooth_context->geometry.num_faces); + + Dace *face = &reshape_smooth_context->geometry.faces[subdiv_poly_index]; + face->start_corner_index = start_loop_index; + face->num_corners = num_loops; +} + +static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int UNUSED(coarse_edge_index), + const float UNUSED(u), + const int vertex_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; + Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index]; + + if (vertex->num_grid_coords != 0) { + vertex->is_infinite_sharp = true; + } +} + +static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + SubdivForeachContext foreach_context = { + .topology_info = foreach_topology_info, + .vertex_inner = foreach_vertex_inner, + .vertex_every_corner = foreach_vertex_every_corner, + .vertex_every_edge = foreach_vertex_every_edge, + .loop = foreach_loop, + .poly = foreach_poly, + .vertex_of_loose_edge = foreach_vertex_of_loose_edge, + .user_data = reshape_smooth_context, + }; + + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << reshape_context->reshape.level) + 1; + mesh_settings.use_optimal_display = false; + + /* TODO(sergey): Tell the foreach() to ignore loose vertices. */ + BKE_subdiv_foreach_subdiv_geometry( + reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh); +} + +/* ================================================================================================ + * Generation of OpenSubdiv evaluator for topology created form reshape level. + */ + +static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter)) +{ + return OSD_SCHEME_CATMARK; +} + +static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation( + const struct OpenSubdiv_Converter *converter) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const SubdivSettings *settings = &reshape_context->subdiv->settings; + + return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(settings); +} + +static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation( + const OpenSubdiv_Converter *converter) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const SubdivSettings *settings = &reshape_context->subdiv->settings; + + return BKE_subdiv_converter_fvar_linear_from_settings(settings); +} + +static bool specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter)) +{ + return false; +} + +static int get_num_faces(const OpenSubdiv_Converter *converter) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + + return reshape_smooth_context->geometry.num_faces; +} + +static int get_num_vertices(const OpenSubdiv_Converter *converter) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + + return reshape_smooth_context->geometry.num_vertices; +} + +static int get_num_face_vertices(const OpenSubdiv_Converter *converter, int face_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + const Dace *face = &reshape_smooth_context->geometry.faces[face_index]; + + return face->num_corners; +} + +static void get_face_vertices(const OpenSubdiv_Converter *converter, + int face_index, + int *face_vertices) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + const Dace *face = &reshape_smooth_context->geometry.faces[face_index]; + + for (int i = 0; i < face->num_corners; ++i) { + const int corner_index = face->start_corner_index + i; + const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index]; + face_vertices[i] = corner->vertex - reshape_smooth_context->geometry.vertices; + } +} + +static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index) +{ + const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data; + Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index]; + + return vertex->is_infinite_sharp; +} + +static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_context, + OpenSubdiv_Converter *converter) +{ + converter->getSchemeType = get_scheme_type; + converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation; + converter->getFVarLinearInterpolation = get_fvar_linear_interpolation; + converter->specifiesFullTopology = specifies_full_topology; + + converter->getNumFaces = get_num_faces; + converter->getNumEdges = NULL; + converter->getNumVertices = get_num_vertices; + + converter->getNumFaceVertices = get_num_face_vertices; + converter->getFaceVertices = get_face_vertices; + converter->getFaceEdges = NULL; + + converter->getEdgeVertices = NULL; + converter->getNumEdgeFaces = NULL; + converter->getEdgeFaces = NULL; + converter->getEdgeSharpness = NULL; + + converter->getNumVertexEdges = NULL; + converter->getVertexEdges = NULL; + converter->getNumVertexFaces = NULL; + converter->getVertexFaces = NULL; + converter->isInfiniteSharpVertex = is_infinite_sharp_vertex; + converter->getVertexSharpness = NULL; + + converter->getNumUVLayers = NULL; + converter->precalcUVLayer = NULL; + converter->finishUVLayer = NULL; + converter->getNumUVCoordinates = NULL; + converter->getFaceCornerUVIndex = NULL; + + converter->freeUserData = NULL; + + converter->user_data = (void *)reshape_smooth_context; +} + +/* Create subdiv descriptor created for topology at a reshape level, */ +static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_context) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const SubdivSettings *settings = &reshape_context->subdiv->settings; + + OpenSubdiv_Converter converter; + converter_init(reshape_smooth_context, &converter); + + Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter); + BKE_subdiv_eval_begin(reshape_subdiv); + + reshape_smooth_context->reshape_subdiv = reshape_subdiv; + + BKE_subdiv_converter_free(&converter); +} + +/* Callback to provide coarse position for subdivision surface topology at a reshape level. */ +typedef void(ReshapeSubdivCoarsePositionCb)( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const Vertex *vertex, + float r_P[3]); + +/* Refine subdivision surface topology at a reshape level for new coarse verticies positions. */ +static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context, + ReshapeSubdivCoarsePositionCb coarse_position_cb) +{ + Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv; + + /* TODO(sergey): For non-trivial coarse_position_cb we should multi-thread this loop. */ + + const int num_vertices = reshape_smooth_context->geometry.num_vertices; + for (int i = 0; i < num_vertices; ++i) { + const Vertex *vertex = &reshape_smooth_context->geometry.vertices[i]; + float P[3]; + coarse_position_cb(reshape_smooth_context, vertex, P); + reshape_subdiv->evaluator->setCoarsePositions(reshape_subdiv->evaluator, P, i, 1); + } + reshape_subdiv->evaluator->refine(reshape_subdiv->evaluator); +} + +BLI_INLINE const GridCoord *reshape_subdiv_refine_vertex_grid_coord(const Vertex *vertex) +{ + if (vertex->num_grid_coords == 0) { + /* This is a loose vertex, the coordinate is not important. */ + /* TODO(sergey): Once the subdiv_foreach() supports properly ignoring loose elements this + * should become an assert instead. */ + return NULL; + } + /* NOTE: All grid coordinates will point to the same object position, so can be simple and use + * first grid coordinate. */ + return &vertex->grid_coords[0]; +} + +/* Version of reshape_subdiv_refine() which uses coarse position from original grids. */ +static void reshape_subdiv_refine_orig_P( + const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3]) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex); + + /* Check whether this is a loose vertex. */ + if (grid_coord == NULL) { + zero_v3(r_P); + return; + } + + float limit_P[3]; + float tangent_matrix[3][3]; + multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, limit_P, tangent_matrix); + + const ReshapeConstGridElement orig_grid_element = + multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord); + + float D[3]; + mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement); + + add_v3_v3v3(r_P, limit_P, D); +} +static void reshape_subdiv_refine_orig(const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_orig_P); +} + +/* Version of reshape_subdiv_refine() which uses coarse position from final grids. */ +static void reshape_subdiv_refine_final_P( + const MultiresReshapeSmoothContext *reshape_smooth_context, const Vertex *vertex, float r_P[3]) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + const GridCoord *grid_coord = reshape_subdiv_refine_vertex_grid_coord(vertex); + + /* Check whether this is a loose vertex. */ + if (grid_coord == NULL) { + zero_v3(r_P); + return; + } + + const ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord( + reshape_context, grid_coord); + + /* NOTE: At this point in reshape/propagate pipeline grid displacement is actually storing object + * vertices coordinates. */ + copy_v3_v3(r_P, grid_element.displacement); +} +static void reshape_subdiv_refine_final(const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + reshape_subdiv_refine(reshape_smooth_context, reshape_subdiv_refine_final_P); +} + +static void reshape_subdiv_evaluate_limit_at_grid( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *ptex_coord, + const GridCoord *grid_coord, + float limit_P[3], + float r_tangent_matrix[3][3]) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + float dPdu[3], dPdv[3]; + BKE_subdiv_eval_limit_point_and_derivatives(reshape_smooth_context->reshape_subdiv, + ptex_coord->ptex_face_index, + ptex_coord->u, + ptex_coord->v, + limit_P, + dPdu, + dPdv); + + const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index); + BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner); +} + +/* ================================================================================================ + * Evaluation of base surface. + */ + +static void evaluate_base_surface_grids_callback( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *ptex_coord, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + float limit_P[3]; + float tangent_matrix[3][3]; + reshape_subdiv_evaluate_limit_at_grid( + reshape_smooth_context, ptex_coord, grid_coord, limit_P, tangent_matrix); + + base_surface_grids_write(reshape_smooth_context, grid_coord, limit_P, tangent_matrix); +} + +static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_base_surface_grids_callback, NULL); +} + +/* ================================================================================================ + * Evaluation of new surface. + */ + +/* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid + * coordinate. */ +static void evaluate_final_original_point( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const GridCoord *grid_coord, + float r_orig_final_P[3]) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + /* Element of an original MDISPS grid) */ + const ReshapeConstGridElement orig_grid_element = + multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord); + + /* Limit surface of the base mesh. */ + float base_mesh_limit_P[3]; + float base_mesh_tangent_matrix[3][3]; + multires_reshape_evaluate_limit_at_grid( + reshape_context, grid_coord, base_mesh_limit_P, base_mesh_tangent_matrix); + + /* Convert original displacement from tangent space to object space. */ + float orig_displacement[3]; + mul_v3_m3v3(orig_displacement, base_mesh_tangent_matrix, orig_grid_element.displacement); + + /* Final point = limit surface + displacement. */ + add_v3_v3v3(r_orig_final_P, base_mesh_limit_P, orig_displacement); +} + +static void evaluate_higher_grid_positions_with_details_callback( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *ptex_coord, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + + /* Position of the original veretx at top level. */ + float orig_final_P[3]; + evaluate_final_original_point(reshape_smooth_context, grid_coord, orig_final_P); + + /* Original surface point on sculpt level (sculpt level before edits in sculpt mode). */ + const SurfacePoint *orig_sculpt_point = base_surface_grids_read(reshape_smooth_context, + grid_coord); + + /* Difference between original top level and original sculpt level in object space. */ + float original_detail_delta[3]; + sub_v3_v3v3(original_detail_delta, orig_final_P, orig_sculpt_point->P); + + /* Difference between original top level and original sculpt level in tangent space of original + * sculpt level. */ + float original_detail_delta_tangent[3]; + float original_sculpt_tangent_matrix_inv[3][3]; + invert_m3_m3(original_sculpt_tangent_matrix_inv, orig_sculpt_point->tangent_matrix); + mul_v3_m3v3( + original_detail_delta_tangent, original_sculpt_tangent_matrix_inv, original_detail_delta); + + /* Limit surface of smoothed (subdivided) edited sculpt level. */ + float smooth_limit_P[3]; + float smooth_tangent_matrix[3][3]; + reshape_subdiv_evaluate_limit_at_grid( + reshape_smooth_context, ptex_coord, grid_coord, smooth_limit_P, smooth_tangent_matrix); + + /* Add original detail to the smoothed surface. */ + float smooth_delta[3]; + mul_v3_m3v3(smooth_delta, smooth_tangent_matrix, original_detail_delta_tangent); + + /* Grid element of the result. + * + * NOTE: Displacement is storing object space coordinate. */ + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, + grid_coord); + + add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta); +} +static void evaluate_higher_grid_positions_with_details( + const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + foreach_toplevel_grid_coord( + reshape_smooth_context, evaluate_higher_grid_positions_with_details_callback, NULL); +} + +static void evaluate_higher_grid_positions_callback( + const MultiresReshapeSmoothContext *reshape_smooth_context, + const PTexCoord *ptex_coord, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context; + Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv; + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, + grid_coord); + + /* Surface. */ + + float P[3]; + BKE_subdiv_eval_limit_point( + reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P); + + copy_v3_v3(grid_element.displacement, P); + + /* Masks. */ + if (grid_element.mask != NULL) { + *grid_element.mask = interpolate_masks_grid(reshape_smooth_context, grid_coord); + } +} + +static void evaluate_higher_grid_positions( + const MultiresReshapeSmoothContext *reshape_smooth_context) +{ + foreach_toplevel_grid_coord( + reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL); +} +/* ================================================================================================ + * Entry point. + */ + +void multires_reshape_smooth_object_grids_with_details( + const MultiresReshapeContext *reshape_context) +{ + const int level_difference = (reshape_context->top.level - reshape_context->reshape.level); + if (level_difference == 0) { + /* Early output. */ + return; + } + + MultiresReshapeSmoothContext reshape_smooth_context; + context_init(&reshape_smooth_context, reshape_context); + + geometry_create(&reshape_smooth_context); + + reshape_subdiv_create(&reshape_smooth_context); + + base_surface_grids_allocate(&reshape_smooth_context); + reshape_subdiv_refine_orig(&reshape_smooth_context); + evaluate_base_surface_grids(&reshape_smooth_context); + + reshape_subdiv_refine_final(&reshape_smooth_context); + evaluate_higher_grid_positions_with_details(&reshape_smooth_context); + + context_free(&reshape_smooth_context); +} + +void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context) +{ + const int level_difference = (reshape_context->top.level - reshape_context->reshape.level); + if (level_difference == 0) { + /* Early output. */ + return; + } + + MultiresReshapeSmoothContext reshape_smooth_context; + context_init(&reshape_smooth_context, reshape_context); + + geometry_create(&reshape_smooth_context); + + reshape_subdiv_create(&reshape_smooth_context); + + reshape_subdiv_refine_final(&reshape_smooth_context); + evaluate_higher_grid_positions(&reshape_smooth_context); + + context_free(&reshape_smooth_context); +} diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c new file mode 100644 index 00000000000..f9271e37672 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -0,0 +1,739 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "multires_reshape.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BLI_task.h" + +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" + +#include "DEG_depsgraph_query.h" + +/* -------------------------------------------------------------------- */ +/** \name Construct/destruct reshape context. + * \{ */ + +/* Create subdivision surface descriptor which is configured for surface evaluation at a given + * multires modifier. */ +Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph, + /*const*/ Object *object, + const MultiresModifierData *mmd) +{ + Mesh *coarse_mesh; + + if (depsgraph != NULL) { + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + coarse_mesh = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH); + } + else { + coarse_mesh = (Mesh *)object->data; + } + + SubdivSettings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); + Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, coarse_mesh); + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) { + BKE_subdiv_free(subdiv); + return NULL; + } + return subdiv; +} + +static void context_zero(MultiresReshapeContext *reshape_context) +{ + memset(reshape_context, 0, sizeof(*reshape_context)); +} + +static void context_init_lookup(MultiresReshapeContext *reshape_context) +{ + const Mesh *base_mesh = reshape_context->base_mesh; + const MPoly *mpoly = base_mesh->mpoly; + const int num_faces = base_mesh->totpoly; + + reshape_context->face_start_grid_index = MEM_malloc_arrayN( + sizeof(int), num_faces, "face_start_grid_index"); + int num_grids = 0; + int num_ptex_faces = 0; + for (int face_index = 0; face_index < num_faces; ++face_index) { + const int num_corners = mpoly[face_index].totloop; + reshape_context->face_start_grid_index[face_index] = num_grids; + num_grids += num_corners; + num_ptex_faces += (num_corners == 4) ? 1 : num_corners; + } + + reshape_context->grid_to_face_index = MEM_malloc_arrayN( + sizeof(int), num_grids, "grid_to_face_index"); + reshape_context->ptex_start_grid_index = MEM_malloc_arrayN( + sizeof(int), num_ptex_faces, "ptex_start_grid_index"); + for (int face_index = 0, grid_index = 0, ptex_index = 0; face_index < num_faces; ++face_index) { + const int num_corners = mpoly[face_index].totloop; + const int num_face_ptex_faces = (num_corners == 4) ? 1 : num_corners; + for (int i = 0; i < num_face_ptex_faces; ++i) { + reshape_context->ptex_start_grid_index[ptex_index + i] = grid_index + i; + } + for (int corner = 0; corner < num_corners; ++corner, ++grid_index) { + reshape_context->grid_to_face_index[grid_index] = face_index; + } + ptex_index += num_face_ptex_faces; + } + + /* Store number of grids, which will be used for sanity checks. */ + reshape_context->num_grids = num_grids; +} + +static void context_init_grid_pointers(MultiresReshapeContext *reshape_context) +{ + Mesh *base_mesh = reshape_context->base_mesh; + reshape_context->mdisps = CustomData_get_layer(&base_mesh->ldata, CD_MDISPS); + reshape_context->grid_paint_masks = CustomData_get_layer(&base_mesh->ldata, CD_GRID_PAINT_MASK); +} + +static void context_init_commoon(MultiresReshapeContext *reshape_context) +{ + BLI_assert(reshape_context->subdiv != NULL); + BLI_assert(reshape_context->base_mesh != NULL); + + reshape_context->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(reshape_context->subdiv), + + context_init_lookup(reshape_context); + context_init_grid_pointers(reshape_context); +} + +static bool context_is_valid(MultiresReshapeContext *reshape_context) +{ + if (reshape_context->mdisps == NULL) { + /* Multires displacement has been removed before current changes were applies. */ + return false; + } + return true; +} + +static bool context_verify_or_free(MultiresReshapeContext *reshape_context) +{ + const bool is_valid = context_is_valid(reshape_context); + if (!is_valid) { + multires_reshape_context_free(reshape_context); + } + return is_valid; +} + +bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context, + Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) +{ + context_zero(reshape_context); + + const bool use_render_params = false; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *base_mesh = (Mesh *)object->data; + + reshape_context->base_mesh = base_mesh; + + reshape_context->subdiv = multires_reshape_create_subdiv(depsgraph, object, mmd); + reshape_context->need_free_subdiv = true; + + reshape_context->reshape.level = multires_get_level( + scene_eval, object, mmd, use_render_params, true); + reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level( + reshape_context->reshape.level); + + reshape_context->top.level = mmd->totlvl; + reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + + context_init_commoon(reshape_context); + + return context_verify_or_free(reshape_context); +} + +bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context, + SubdivCCG *subdiv_ccg, + Mesh *base_mesh, + int top_level) +{ + context_zero(reshape_context); + + reshape_context->base_mesh = base_mesh; + + reshape_context->subdiv = subdiv_ccg->subdiv; + reshape_context->need_free_subdiv = false; + + reshape_context->reshape.level = subdiv_ccg->level; + reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level( + reshape_context->reshape.level); + + reshape_context->top.level = top_level; + reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + + context_init_commoon(reshape_context); + + return context_verify_or_free(reshape_context); +} + +bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *reshape_context, + struct Object *object, + struct MultiresModifierData *mmd, + int top_level) +{ + context_zero(reshape_context); + + Mesh *base_mesh = (Mesh *)object->data; + + reshape_context->base_mesh = base_mesh; + + reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd); + reshape_context->need_free_subdiv = true; + + reshape_context->reshape.level = mmd->totlvl; + reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level( + reshape_context->reshape.level); + + reshape_context->top.level = top_level; + reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level); + + context_init_commoon(reshape_context); + + return context_verify_or_free(reshape_context); +} + +static void free_original_grids(MultiresReshapeContext *reshape_context) +{ + MDisps *orig_mdisps = reshape_context->orig.mdisps; + GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks; + + if (orig_mdisps == NULL && orig_grid_paint_masks == NULL) { + return; + } + + const int num_grids = reshape_context->num_grids; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + if (orig_mdisps != NULL) { + MDisps *orig_grid = &orig_mdisps[grid_index]; + MEM_SAFE_FREE(orig_grid->disps); + } + if (orig_grid_paint_masks != NULL) { + GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index]; + MEM_SAFE_FREE(orig_paint_mask_grid->data); + } + } + + MEM_SAFE_FREE(orig_mdisps); + MEM_SAFE_FREE(orig_grid_paint_masks); +} + +void multires_reshape_context_free(MultiresReshapeContext *reshape_context) +{ + if (reshape_context->need_free_subdiv) { + BKE_subdiv_free(reshape_context->subdiv); + } + + free_original_grids(reshape_context); + + MEM_freeN(reshape_context->face_start_grid_index); + MEM_freeN(reshape_context->ptex_start_grid_index); + MEM_freeN(reshape_context->grid_to_face_index); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Helper accessors. + * \{ */ + +/* For the given grid index get index of face it was created for. */ +int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context, + int grid_index) +{ + BLI_assert(grid_index >= 0); + BLI_assert(grid_index < reshape_context->num_grids); + + /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using + * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */ + + return reshape_context->grid_to_face_index[grid_index]; +} + +/* For the given grid index get corner of a face it was created for. */ +int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index) +{ + BLI_assert(grid_index >= 0); + BLI_assert(grid_index < reshape_context->num_grids); + + /* TODO(sergey): Optimization: when SubdivCCG is known we can calculate face index using + * SubdivCCG::grid_faces and SubdivCCG::faces, saving memory used by grid_to_face_index. */ + + const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index); + return grid_index - reshape_context->face_start_grid_index[face_index]; +} + +bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index) +{ + const MPoly *coarse_poly = &reshape_context->base_mesh->mpoly[face_index]; + return (coarse_poly->totloop == 4); +} + +/* For the given grid index get index of corresponding ptex face. */ +int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context, + int grid_index) +{ + const int face_index = multires_reshape_grid_to_face_index(reshape_context, grid_index); + const int corner = multires_reshape_grid_to_corner(reshape_context, grid_index); + const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index); + return reshape_context->face_ptex_offset[face_index] + (is_quad ? 0 : corner); +} + +/* Convert normalized coordinate within a grid to a normalized coordinate within a ptex face. */ +PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord) +{ + PTexCoord ptex_coord; + + ptex_coord.ptex_face_index = multires_reshape_grid_to_ptex_index(reshape_context, + grid_coord->grid_index); + + float corner_u, corner_v; + BKE_subdiv_grid_uv_to_ptex_face_uv(grid_coord->u, grid_coord->v, &corner_u, &corner_v); + + const int face_index = multires_reshape_grid_to_face_index(reshape_context, + grid_coord->grid_index); + const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index); + if (multires_reshape_is_quad_face(reshape_context, face_index)) { + float grid_u, grid_v; + BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v); + BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v); + } + else { + ptex_coord.u = corner_u; + ptex_coord.v = corner_v; + } + + return ptex_coord; +} + +/* Convert a normalized coordinate within a ptex face to a normalized coordinate within a grid. */ +GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context, + const PTexCoord *ptex_coord) +{ + GridCoord grid_coord; + + const int start_grid_index = reshape_context->ptex_start_grid_index[ptex_coord->ptex_face_index]; + const int face_index = reshape_context->grid_to_face_index[start_grid_index]; + + int corner_delta; + if (multires_reshape_is_quad_face(reshape_context, face_index)) { + corner_delta = BKE_subdiv_rotate_quad_to_corner( + ptex_coord->u, ptex_coord->v, &grid_coord.u, &grid_coord.v); + } + else { + corner_delta = 0; + grid_coord.u = ptex_coord->u; + grid_coord.v = ptex_coord->v; + } + grid_coord.grid_index = start_grid_index + corner_delta; + + BKE_subdiv_ptex_face_uv_to_grid_uv(grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v); + + return grid_coord; +} + +void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context, + const int face_index, + const int corner, + const float dPdu[3], + const float dPdv[3], + float r_tangent_matrix[3][3]) +{ + /* For a quad faces we would need to flip the tangent, since they will use + * use different coordinates within displacement grid compared to the ptex face. */ + const bool is_quad = multires_reshape_is_quad_face(reshape_context, face_index); + const int tangent_corner = is_quad ? corner : 0; + BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner); +} + +ReshapeGridElement multires_reshape_grid_element_for_grid_coord( + const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord) +{ + ReshapeGridElement grid_element = {NULL, NULL}; + + const int grid_size = reshape_context->top.grid_size; + const int grid_x = lround(grid_coord->u * (grid_size - 1)); + const int grid_y = lround(grid_coord->v * (grid_size - 1)); + const int grid_element_index = grid_y * grid_size + grid_x; + + if (reshape_context->mdisps != NULL) { + MDisps *displacement_grid = &reshape_context->mdisps[grid_coord->grid_index]; + grid_element.displacement = displacement_grid->disps[grid_element_index]; + } + + if (reshape_context->grid_paint_masks != NULL) { + GridPaintMask *grid_paint_mask = &reshape_context->grid_paint_masks[grid_coord->grid_index]; + grid_element.mask = &grid_paint_mask->data[grid_element_index]; + } + + return grid_element; +} + +ReshapeGridElement multires_reshape_grid_element_for_ptex_coord( + const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord) +{ + GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord); + return multires_reshape_grid_element_for_grid_coord(reshape_context, &grid_coord); +} + +ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord( + const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord) +{ + ReshapeConstGridElement grid_element = {{0.0f, 0.0f, 0.0f}, 0.0f}; + + const MDisps *mdisps = reshape_context->orig.mdisps; + if (mdisps != NULL) { + const MDisps *displacement_grid = &mdisps[grid_coord->grid_index]; + if (displacement_grid->disps != NULL) { + const int grid_size = BKE_subdiv_grid_size_from_level(displacement_grid->level); + const int grid_x = lround(grid_coord->u * (grid_size - 1)); + const int grid_y = lround(grid_coord->v * (grid_size - 1)); + const int grid_element_index = grid_y * grid_size + grid_x; + copy_v3_v3(grid_element.displacement, displacement_grid->disps[grid_element_index]); + } + } + + const GridPaintMask *grid_paint_masks = reshape_context->orig.grid_paint_masks; + if (grid_paint_masks != NULL) { + const GridPaintMask *paint_mask_grid = &grid_paint_masks[grid_coord->grid_index]; + if (paint_mask_grid->data != NULL) { + const int grid_size = BKE_subdiv_grid_size_from_level(paint_mask_grid->level); + const int grid_x = lround(grid_coord->u * (grid_size - 1)); + const int grid_y = lround(grid_coord->v * (grid_size - 1)); + const int grid_element_index = grid_y * grid_size + grid_x; + grid_element.mask = paint_mask_grid->data[grid_element_index]; + } + } + + return grid_element; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample limit surface of the base mesh. + * \{ */ + +void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + float r_P[3], + float r_tangent_matrix[3][3]) +{ + float dPdu[3], dPdv[3]; + const PTexCoord ptex_coord = multires_reshape_grid_coord_to_ptex(reshape_context, grid_coord); + Subdiv *subdiv = reshape_context->subdiv; + BKE_subdiv_eval_limit_point_and_derivatives( + subdiv, ptex_coord.ptex_face_index, ptex_coord.u, ptex_coord.v, r_P, dPdu, dPdv); + + const int face_index = multires_reshape_grid_to_face_index(reshape_context, + grid_coord->grid_index); + const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index); + multires_reshape_tangent_matrix_for_corner( + reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Custom data preparation. + * \{ */ + +static void allocate_displacement_grid(MDisps *displacement_grid, const int level) +{ + const int grid_size = BKE_subdiv_grid_size_from_level(level); + const int grid_area = grid_size * grid_size; + float(*disps)[3] = MEM_calloc_arrayN(grid_area, 3 * sizeof(float), "multires disps"); + if (displacement_grid->disps != NULL) { + MEM_freeN(displacement_grid->disps); + } + /* TODO(sergey): Preserve data on the old level. */ + displacement_grid->disps = disps; + displacement_grid->totdisp = grid_area; + displacement_grid->level = level; +} + +static void ensure_displacement_grid(MDisps *displacement_grid, const int level) +{ + if (displacement_grid->disps != NULL && displacement_grid->level >= level) { + return; + } + allocate_displacement_grid(displacement_grid, level); +} + +static void ensure_displacement_grids(Mesh *mesh, const int grid_level) +{ + const int num_grids = mesh->totloop; + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + ensure_displacement_grid(&mdisps[grid_index], grid_level); + } +} + +static void ensure_mask_grids(Mesh *mesh, const int level) +{ + GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); + if (grid_paint_masks == NULL) { + return; + } + const int num_grids = mesh->totloop; + const int grid_size = BKE_subdiv_grid_size_from_level(level); + const int grid_area = grid_size * grid_size; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index]; + if (grid_paint_mask->level >= level) { + continue; + } + grid_paint_mask->level = level; + if (grid_paint_mask->data) { + MEM_freeN(grid_paint_mask->data); + } + /* TODO(sergey): Preserve data on the old level. */ + grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data"); + } +} + +void multires_reshape_ensure_grids(Mesh *mesh, const int level) +{ + ensure_displacement_grids(mesh, level); + ensure_mask_grids(mesh, level); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Displacement, space conversion. + * \{ */ + +void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context) +{ + const MDisps *mdisps = reshape_context->mdisps; + const GridPaintMask *grid_paint_masks = reshape_context->grid_paint_masks; + + MDisps *orig_mdisps = MEM_dupallocN(mdisps); + GridPaintMask *orig_grid_paint_masks = NULL; + if (grid_paint_masks != NULL) { + orig_grid_paint_masks = MEM_dupallocN(grid_paint_masks); + } + + const int num_grids = reshape_context->num_grids; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MDisps *orig_grid = &orig_mdisps[grid_index]; + /* Ignore possibly invalid/non-allocated original grids. They will be replaced with 0 original + * data when accessed during reshape process. + * Reshape process will ensure all grids are on top level, but that happens on separate set of + * grids which eventually replaces original one. */ + if (orig_grid->disps != NULL) { + orig_grid->disps = MEM_dupallocN(orig_grid->disps); + } + if (orig_grid_paint_masks != NULL) { + GridPaintMask *orig_paint_mask_grid = &orig_grid_paint_masks[grid_index]; + if (orig_paint_mask_grid->data != NULL) { + orig_paint_mask_grid->data = MEM_dupallocN(orig_paint_mask_grid->data); + } + } + } + + reshape_context->orig.mdisps = orig_mdisps; + reshape_context->orig.grid_paint_masks = orig_grid_paint_masks; +} + +typedef void (*ForeachGridCoordinateCallback)(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + void *userdata_v); + +typedef struct ForeachGridCoordinateTaskData { + const MultiresReshapeContext *reshape_context; + + int grid_size; + float grid_size_1_inv; + + ForeachGridCoordinateCallback callback; + void *callback_userdata_v; +} ForeachGridCoordinateTaskData; + +static void foreach_grid_face_coordinate_task(void *__restrict userdata_v, + const int face_index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ForeachGridCoordinateTaskData *data = userdata_v; + + const MultiresReshapeContext *reshape_context = data->reshape_context; + + const Mesh *base_mesh = data->reshape_context->base_mesh; + const MPoly *mpoly = base_mesh->mpoly; + const int grid_size = data->grid_size; + const float grid_size_1_inv = 1.0f / (((float)grid_size) - 1.0f); + + const int num_corners = mpoly[face_index].totloop; + int grid_index = reshape_context->face_start_grid_index[face_index]; + for (int corner = 0; corner < num_corners; ++corner, ++grid_index) { + for (int y = 0; y < grid_size; ++y) { + const float v = (float)y * grid_size_1_inv; + for (int x = 0; x < grid_size; ++x) { + const float u = (float)x * grid_size_1_inv; + + GridCoord grid_coord; + grid_coord.grid_index = grid_index; + grid_coord.u = u; + grid_coord.v = v; + + data->callback(data->reshape_context, &grid_coord, data->callback_userdata_v); + } + } + } +} + +/* Run given callback for every grid coordinate at a given level. */ +static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_context, + const int level, + ForeachGridCoordinateCallback callback, + void *userdata_v) +{ + ForeachGridCoordinateTaskData data; + data.reshape_context = reshape_context; + data.grid_size = BKE_subdiv_grid_size_from_level(level); + data.grid_size_1_inv = 1.0f / (((float)data.grid_size) - 1.0f); + data.callback = callback; + data.callback_userdata_v = userdata_v; + + TaskParallelSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.min_iter_per_thread = 1; + + const Mesh *base_mesh = reshape_context->base_mesh; + const int num_faces = base_mesh->totpoly; + BLI_task_parallel_range( + 0, num_faces, &data, foreach_grid_face_coordinate_task, ¶llel_range_settings); +} + +static void object_grid_element_to_tangent_displacement( + const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + float P[3]; + float tangent_matrix[3][3]; + multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix); + + float inv_tangent_matrix[3][3]; + invert_m3_m3(inv_tangent_matrix, tangent_matrix); + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, + grid_coord); + + float D[3]; + sub_v3_v3v3(D, grid_element.displacement, P); + + float tangent_D[3]; + mul_v3_m3v3(tangent_D, inv_tangent_matrix, D); + + copy_v3_v3(grid_element.displacement, tangent_D); +} + +void multires_reshape_object_grids_to_tangent_displacement( + const MultiresReshapeContext *reshape_context) +{ + foreach_grid_coordinate(reshape_context, + reshape_context->top.level, + object_grid_element_to_tangent_displacement, + NULL); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name MDISPS. + * \{ */ + +/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to + * own file. */ + +static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + float P[3]; + float tangent_matrix[3][3]; + multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix); + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, + grid_coord); + float D[3]; + mul_v3_m3v3(D, tangent_matrix, grid_element.displacement); + + add_v3_v3v3(grid_element.displacement, P, D); +} + +void multires_reshape_assign_final_coords_from_mdisps( + const MultiresReshapeContext *reshape_context) +{ + foreach_grid_coordinate( + reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, NULL); +} + +static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *reshape_context, + const GridCoord *grid_coord, + void *UNUSED(userdata_v)) +{ + float P[3]; + float tangent_matrix[3][3]; + multires_reshape_evaluate_limit_at_grid(reshape_context, grid_coord, P, tangent_matrix); + + const ReshapeConstGridElement orig_grid_element = + multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord); + + float D[3]; + mul_v3_m3v3(D, tangent_matrix, orig_grid_element.displacement); + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context, + grid_coord); + add_v3_v3v3(grid_element.displacement, P, D); +} + +void multires_reshape_assign_final_coords_from_orig_mdisps( + const MultiresReshapeContext *reshape_context) +{ + foreach_grid_coordinate( + reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c new file mode 100644 index 00000000000..5aff0b3caa2 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c @@ -0,0 +1,212 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "multires_reshape.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" + +typedef struct MultiresReshapeAssignVertcosContext { + const MultiresReshapeContext *reshape_context; + + const float (*vert_coords)[3]; + const int num_vert_coords; +} MultiresReshapeAssignVertcosContext; + +/** + * Set single displacement grid value at a reshape level to a corresponding vertex coordinate. + * This function will be called for every side of a boundary grid points for inner coordinates. + */ +static void multires_reshape_vertcos_foreach_single_vertex( + const SubdivForeachContext *foreach_context, + const GridCoord *grid_coord, + const int subdiv_vertex_index) +{ + MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data; + const float *coordinate = reshape_vertcos_context->vert_coords[subdiv_vertex_index]; + + ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord( + reshape_vertcos_context->reshape_context, grid_coord); + BLI_assert(grid_element.displacement != NULL); + copy_v3_v3(grid_element.displacement, coordinate); +} + +/* TODO(sergey): De-duplicate with similar function in multires_reshape_smooth.c */ +static void multires_reshape_vertcos_foreach_vertex(const SubdivForeachContext *foreach_context, + const PTexCoord *ptex_coord, + const int subdiv_vertex_index) +{ + const MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data; + const MultiresReshapeContext *reshape_context = reshape_vertcos_context->reshape_context; + + const GridCoord grid_coord = multires_reshape_ptex_coord_to_grid(reshape_context, ptex_coord); + const int face_index = multires_reshape_grid_to_face_index(reshape_context, + grid_coord.grid_index); + + const Mesh *base_mesh = reshape_context->base_mesh; + const MPoly *base_poly = &base_mesh->mpoly[face_index]; + const int num_corners = base_poly->totloop; + const int start_grid_index = reshape_context->face_start_grid_index[face_index]; + const int corner = grid_coord.grid_index - start_grid_index; + + if (grid_coord.u == 0.0f && grid_coord.v == 0.0f) { + for (int current_corner = 0; current_corner < num_corners; ++current_corner) { + GridCoord corner_grid_coord = grid_coord; + corner_grid_coord.grid_index = start_grid_index + current_corner; + multires_reshape_vertcos_foreach_single_vertex( + foreach_context, &corner_grid_coord, subdiv_vertex_index); + } + return; + } + + multires_reshape_vertcos_foreach_single_vertex( + foreach_context, &grid_coord, subdiv_vertex_index); + + if (grid_coord.u == 0.0f) { + GridCoord prev_grid_coord; + prev_grid_coord.grid_index = start_grid_index + ((corner + num_corners - 1) % num_corners); + prev_grid_coord.u = grid_coord.v; + prev_grid_coord.v = 0.0f; + + multires_reshape_vertcos_foreach_single_vertex( + foreach_context, &prev_grid_coord, subdiv_vertex_index); + } + + if (grid_coord.v == 0.0f) { + GridCoord next_grid_coord; + next_grid_coord.grid_index = start_grid_index + ((corner + 1) % num_corners); + next_grid_coord.u = 0.0f; + next_grid_coord.v = grid_coord.u; + + multires_reshape_vertcos_foreach_single_vertex( + foreach_context, &next_grid_coord, subdiv_vertex_index); + } +} + +/* SubdivForeachContext::topology_info() */ +static bool multires_reshape_vertcos_foreach_topology_info( + const SubdivForeachContext *foreach_context, + const int num_vertices, + const int UNUSED(num_edges), + const int UNUSED(num_loops), + const int UNUSED(num_polygons)) +{ + MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data; + if (num_vertices != reshape_vertcos_context->num_vert_coords) { + return false; + } + return true; +} + +/* SubdivForeachContext::vertex_inner() */ +static void multires_reshape_vertcos_foreach_vertex_inner( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_face_index), + const int UNUSED(coarse_face_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +/* SubdivForeachContext::vertex_every_corner() */ +static void multires_reshape_vertcos_foreach_vertex_every_corner( + const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_vertex_index), + const int UNUSED(coarse_face_index), + const int UNUSED(coarse_face_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +/* SubdivForeachContext::vertex_every_edge() */ +static void multires_reshape_vertcos_foreach_vertex_every_edge( + const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float ptex_face_u, + const float ptex_face_v, + const int UNUSED(coarse_edge_index), + const int UNUSED(coarse_face_index), + const int UNUSED(coarse_face_corner), + const int subdiv_vertex_index) +{ + const PTexCoord ptex_coord = { + .ptex_face_index = ptex_face_index, + .u = ptex_face_u, + .v = ptex_face_v, + }; + multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index); +} + +/* Set displacement grids values at a reshape level to a object coordinates of the the given + * source. */ +bool multires_reshape_assign_final_coords_from_vertcos( + const MultiresReshapeContext *reshape_context, + const float (*vert_coords)[3], + const int num_vert_coords) +{ + MultiresReshapeAssignVertcosContext reshape_vertcos_context = { + .reshape_context = reshape_context, + .vert_coords = vert_coords, + .num_vert_coords = num_vert_coords, + }; + + SubdivForeachContext foreach_context = { + .topology_info = multires_reshape_vertcos_foreach_topology_info, + .vertex_inner = multires_reshape_vertcos_foreach_vertex_inner, + .vertex_every_edge = multires_reshape_vertcos_foreach_vertex_every_edge, + .vertex_every_corner = multires_reshape_vertcos_foreach_vertex_every_corner, + .user_data = &reshape_vertcos_context, + }; + + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << reshape_context->reshape.level) + 1; + mesh_settings.use_optimal_display = false; + + return BKE_subdiv_foreach_subdiv_geometry( + reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh); +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 41f7531ed85..d7247518f9e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -524,7 +524,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) return true; } -void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src) +void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; BKE_object_free_modifiers(ob_dst, 0); @@ -562,7 +562,7 @@ void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct if (md->type == eModifierType_Multires) { /* Has to be done after mod creation, but *before* we actually copy its settings! */ multiresModifier_sync_levels_ex( - scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); + ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); } modifier_copyData(md, nmd); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 6ca14ec9197..98638b6c865 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -740,7 +740,7 @@ bool BKE_scene_object_find(Scene *scene, Object *ob) return false; } -Object *BKE_scene_object_find_by_name(Scene *scene, const char *name) +Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name) { for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { @@ -999,10 +999,10 @@ bool BKE_scene_camera_switch_update(Scene *scene) return false; } -char *BKE_scene_find_marker_name(Scene *scene, int frame) +const char *BKE_scene_find_marker_name(const Scene *scene, int frame) { - ListBase *markers = &scene->markers; - TimeMarker *m1, *m2; + const ListBase *markers = &scene->markers; + const TimeMarker *m1, *m2; /* search through markers for match */ for (m1 = markers->first, m2 = markers->last; m1 && m2; m1 = m1->next, m2 = m2->prev) { @@ -1024,9 +1024,9 @@ char *BKE_scene_find_marker_name(Scene *scene, int frame) /* return the current marker for this frame, * we can have more than 1 marker per frame, this just returns the first :/ */ -char *BKE_scene_find_last_marker_name(Scene *scene, int frame) +const char *BKE_scene_find_last_marker_name(const Scene *scene, int frame) { - TimeMarker *marker, *best_marker = NULL; + const TimeMarker *marker, *best_marker = NULL; int best_frame = -MAXFRAME * 2; for (marker = scene->markers.first; marker; marker = marker->next) { if (marker->frame == frame) { diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index 0846c6c90a6..aa4066b643f 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -682,7 +682,6 @@ void BKE_sequencer_cache_put( key->nfra = cfra - seq->start; key->type = type; key->cost = cost; - key->cache_owner = cache; key->link_prev = NULL; key->link_next = NULL; key->is_temp_cache = true; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index ea53726a94d..827cccc6bd6 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -4603,10 +4603,10 @@ void BKE_sequence_sound_init(Scene *scene, Sequence *seq) } } -Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame) +const Sequence *BKE_sequencer_foreground_frame_get(const Scene *scene, int frame) { - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq, *best_seq = NULL; + const Editing *ed = scene->ed; + const Sequence *seq, *best_seq = NULL; int best_machine = -1; if (!ed) { diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index df7597b7f01..47b02654104 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -135,7 +135,7 @@ static int sound_cfra; static char **audio_device_names = NULL; #endif -BLI_INLINE void sound_verify_evaluated_id(ID *id) +BLI_INLINE void sound_verify_evaluated_id(const ID *id) { UNUSED_VARS_NDEBUG(id); /* This is a bit tricky and not quite reliable, but good enough check. @@ -504,7 +504,7 @@ void BKE_sound_load(Main *bmain, bSound *sound) sound_load_audio(bmain, sound, true); } -AUD_Device *BKE_sound_mixdown(Scene *scene, AUD_DeviceSpecs specs, int start, float volume) +AUD_Device *BKE_sound_mixdown(const Scene *scene, AUD_DeviceSpecs specs, int start, float volume) { sound_verify_evaluated_id(&scene->id); return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS); diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c index 1f78cf4eb3b..50b2b3c7c46 100644 --- a/source/blender/blenkernel/intern/subdiv_displacement_multires.c +++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c @@ -47,6 +47,7 @@ typedef struct MultiresDisplacementData { int grid_size; /* Mesh is used to read external displacement. */ Mesh *mesh; + const MultiresModifierData *mmd; const MPoly *mpoly; const MDisps *mdisps; /* Indexed by ptex face index, contains polygon/corner which corresponds @@ -328,9 +329,7 @@ static int displacement_get_face_corner(MultiresDisplacementData *data, static void initialize(SubdivDisplacement *displacement) { MultiresDisplacementData *data = displacement->user_data; - Mesh *mesh = data->mesh; - /* Make sure external displacement is read. */ - CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + multiresModifier_ensure_external_read(data->mesh, data->mmd); data->is_initialized = true; } @@ -421,6 +420,7 @@ static void displacement_init_data(SubdivDisplacement *displacement, data->subdiv = subdiv; data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl); data->mesh = mesh; + data->mmd = mmd; data->mpoly = mesh->mpoly; data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c index 0f56fc5ec21..347e2843423 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.c +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -1772,6 +1772,21 @@ static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ct } } +static void subdiv_foreach_mark_non_loose_geometry(SubdivForeachTaskContext *ctx) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MLoop *coarse_mloop = coarse_mesh->mloop; + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner]; + BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e); + BLI_BITMAP_ENABLE(ctx->coarse_vertices_used_map, loop->v); + } + } +} + static void subdiv_foreach_single_thread_tasks(SubdivForeachTaskContext *ctx) { /* NOTE: In theory, we can try to skip allocation of TLS here, but in @@ -1785,6 +1800,15 @@ static void subdiv_foreach_single_thread_tasks(SubdivForeachTaskContext *ctx) /* Run callbacks which are supposed to be run once per shared geometry. */ subdiv_foreach_single_geometry_vertices(ctx, tls); subdiv_foreach_tls_free(ctx, tls); + + const SubdivForeachContext *foreach_context = ctx->foreach_context; + const bool is_loose_geometry_tagged = (foreach_context->vertex_every_edge != NULL && + foreach_context->vertex_every_corner != NULL); + const bool is_loose_geometry_tags_needed = (foreach_context->vertex_loose != NULL || + foreach_context->vertex_of_loose_edge != NULL); + if (is_loose_geometry_tagged && is_loose_geometry_tags_needed) { + subdiv_foreach_mark_non_loose_geometry(ctx); + } } static void subdiv_foreach_task(void *__restrict userdata, diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 19425a0d80b..4635db98514 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -43,7 +43,7 @@ /* ********************** general blender movie support ***************************** */ static int start_stub(void *UNUSED(context_v), - Scene *UNUSED(scene), + const Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty), @@ -85,7 +85,7 @@ static void context_free_stub(void *UNUSED(context_v)) /* callbacks */ static int start_avi(void *context_v, - Scene *scene, + const Scene *scene, RenderData *rd, int rectx, int recty, @@ -102,7 +102,7 @@ static int append_avi(void *context_v, int recty, const char *suffix, ReportList *reports); -static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix); +static void filepath_avi(char *string, const RenderData *rd, bool preview, const char *suffix); static void *context_create_avi(void); static void context_free_avi(void *context_v); #endif /* WITH_AVI */ @@ -158,7 +158,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) #ifdef WITH_AVI -static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix) +static void filepath_avi(char *string, const RenderData *rd, bool preview, const char *suffix) { int sfra, efra; @@ -196,7 +196,7 @@ static void filepath_avi(char *string, RenderData *rd, bool preview, const char } static int start_avi(void *context_v, - Scene *UNUSED(scene), + const Scene *UNUSED(scene), RenderData *rd, int rectx, int recty, @@ -316,7 +316,7 @@ static void context_free_avi(void *context_v) #endif /* WITH_AVI */ /* similar to BKE_image_path_from_imformat() */ -void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix) +void BKE_movie_filepath_get(char *string, const RenderData *rd, bool preview, const char *suffix) { bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype); if (mh && mh->get_movie_path) { diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index deb9592b4f9..7e5d99617e4 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -114,8 +114,11 @@ typedef struct FFMpegContext { static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value); static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value); static void ffmpeg_set_expert_options(RenderData *rd); -static void ffmpeg_filepath_get( - FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix); +static void ffmpeg_filepath_get(FFMpegContext *context, + char *string, + const struct RenderData *rd, + bool preview, + const char *suffix); /* Delete a picture buffer */ @@ -338,7 +341,7 @@ static const char **get_file_extensions(int format) /* Write a frame to the output file */ static int write_video_frame( - FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports) + FFMpegContext *context, const RenderData *rd, int cfra, AVFrame *frame, ReportList *reports) { int got_output; int ret, success = 1; @@ -1217,7 +1220,7 @@ static void flush_ffmpeg(FFMpegContext *context) /* Get the output filename-- similar to the other output formats */ static void ffmpeg_filepath_get( - FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix) + FFMpegContext *context, char *string, const RenderData *rd, bool preview, const char *suffix) { char autosplit[20]; @@ -1282,13 +1285,13 @@ static void ffmpeg_filepath_get( BLI_path_suffix(string, FILE_MAX, suffix, ""); } -void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix) +void BKE_ffmpeg_filepath_get(char *string, const RenderData *rd, bool preview, const char *suffix) { ffmpeg_filepath_get(NULL, string, rd, preview, suffix); } int BKE_ffmpeg_start(void *context_v, - struct Scene *scene, + const struct Scene *scene, RenderData *rd, int rectx, int recty, @@ -1846,7 +1849,7 @@ void BKE_ffmpeg_codec_settings_verify(RenderData *rd) ffmpeg_set_expert_options(rd); } -bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd) +bool BKE_ffmpeg_alpha_channel_is_supported(const RenderData *rd) { int codec = rd->ffcodecdata.codec; diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index bf4b90db14f..fa50bf202a8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -5743,7 +5743,7 @@ static float ff_quad_form_factor(float *p, float *n, float *q0, float *q1, float static __m128 sse_approx_acos(__m128 x) { - /* needs a better approximation than taylor expansion of acos, since that + /* needs a better approximation than Taylor expansion of acos, since that * gives big errors for near 1.0 values, sqrt(2 * x) * acos(1 - x) should work * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */ diff --git a/source/blender/blenlib/intern/voronoi_2d.c b/source/blender/blenlib/intern/voronoi_2d.c index eb718c5e8c6..6bd9a16cd55 100644 --- a/source/blender/blenlib/intern/voronoi_2d.c +++ b/source/blender/blenlib/intern/voronoi_2d.c @@ -766,24 +766,25 @@ static int voronoi_addTriangulationPoint(const float coord[2], return (*triangulated_points_total) - 1; } -static void voronoi_addTriangle(int v1, int v2, int v3, int (**triangles)[3], int *triangles_total) +static void voronoi_addTriangle( + int v1, int v2, int v3, int (**r_triangles)[3], int *r_triangles_total) { int *triangle; - if (*triangles) { - *triangles = MEM_reallocN(*triangles, sizeof(int[3]) * (*triangles_total + 1)); + if (*r_triangles) { + *r_triangles = MEM_reallocN(*r_triangles, sizeof(int[3]) * (*r_triangles_total + 1)); } else { - *triangles = MEM_callocN(sizeof(int[3]), "trianglulation triangles"); + *r_triangles = MEM_callocN(sizeof(int[3]), "trianglulation triangles"); } - triangle = (int *)&(*triangles)[(*triangles_total)]; + triangle = (int *)&(*r_triangles)[(*r_triangles_total)]; triangle[0] = v1; triangle[1] = v2; triangle[2] = v3; - (*triangles_total)++; + (*r_triangles_total)++; } void BLI_voronoi_triangulate(const VoronoiSite *sites, diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3059caf83f1..0fbc9c661f3 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1891,9 +1891,11 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain) if (ima->cache) { oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0); } - for (a = 0; a < TEXTARGET_COUNT; a++) { - if (ima->gputexture[a] != NULL) { - oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0); + for (int eye = 0; eye < 2; eye++) { + for (a = 0; a < TEXTARGET_COUNT; a++) { + if (ima->gputexture[a][eye] != NULL) { + oldnewmap_insert(fd->imamap, ima->gputexture[a][eye], ima->gputexture[a][eye], 0); + } } } if (ima->rr) { @@ -1937,8 +1939,10 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain) if (ima->cache == NULL) { ima->gpuflag = 0; ima->gpuframenr = INT_MAX; - for (i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i] = NULL; + for (int eye = 0; eye < 2; eye++) { + for (i = 0; i < TEXTARGET_COUNT; i++) { + ima->gputexture[i][eye] = NULL; + } } ima->rr = NULL; } @@ -1946,8 +1950,10 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain) slot->render = newimaadr(fd, slot->render); } - for (i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]); + for (int eye = 0; eye < 2; eye++) { + for (i = 0; i < TEXTARGET_COUNT; i++) { + ima->gputexture[i][eye] = newimaadr(fd, ima->gputexture[i][eye]); + } } ima->rr = newimaadr(fd, ima->rr); } @@ -4140,14 +4146,18 @@ static void direct_link_image(FileData *fd, Image *ima) if (!ima->cache) { ima->gpuflag = 0; ima->gpuframenr = INT_MAX; - for (int i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i] = NULL; + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima->gputexture[i][eye] = NULL; + } } ima->rr = NULL; } else { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]); + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima->gputexture[i][eye] = newimaadr(fd, ima->gputexture[i][eye]); + } } ima->rr = newimaadr(fd, ima->rr); } @@ -5774,8 +5784,8 @@ static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb) BKE_curvemapping_initialize(gpmd->curve_thickness); } } - else if (md->type == eGpencilModifierType_Vertexcolor) { - VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md; + else if (md->type == eGpencilModifierType_Tint) { + TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; gpmd->colorband = newdataadr(fd, gpmd->colorband); gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity); if (gpmd->curve_intensity) { @@ -5799,14 +5809,6 @@ static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb) BKE_curvemapping_initialize(gpmd->curve_intensity); } } - else if (md->type == eGpencilModifierType_Tint) { - TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; - gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity); - if (gpmd->curve_intensity) { - direct_link_curvemapping(fd, gpmd->curve_intensity); - BKE_curvemapping_initialize(gpmd->curve_intensity); - } - } else if (md->type == eGpencilModifierType_Opacity) { OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 0ce32d234a8..e561b4a07f7 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1070,8 +1070,8 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa callback(gpmd->curve_intensity); } } - else if (md->type == eGpencilModifierType_Vertexcolor) { - VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md; + else if (md->type == eGpencilModifierType_Tint) { + TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; if (gpmd->curve_intensity) { callback(gpmd->curve_intensity); @@ -1098,13 +1098,6 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa callback(gpmd->curve_intensity); } } - else if (md->type == eGpencilModifierType_Tint) { - TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; - - if (gpmd->curve_intensity) { - callback(gpmd->curve_intensity); - } - } } } @@ -2548,7 +2541,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) V3D_SHOW_MODE_SHADE_OVERRIDE = (1 << 15), }; View3D *v3d = (View3D *)sl; - float alpha = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 1.0f; + float alpha = (v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) ? 0.0f : 1.0f; v3d->overlay.texture_paint_mode_opacity = alpha; v3d->overlay.vertex_paint_mode_opacity = alpha; v3d->overlay.weight_paint_mode_opacity = alpha; @@ -4653,10 +4646,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } case eGpencilModifierType_Noise: { NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md; - mmd->factor /= 25.0f; - mmd->factor_thickness = mmd->factor; - mmd->factor_strength = mmd->factor; - mmd->factor_uvs = mmd->factor; + float factor = mmd->factor / 25.0f; + mmd->factor = (mmd->flag & GP_NOISE_MOD_LOCATION) ? factor : 0.0f; + mmd->factor_thickness = (mmd->flag & GP_NOISE_MOD_STRENGTH) ? factor : 0.0f; + mmd->factor_strength = (mmd->flag & GP_NOISE_MOD_THICKNESS) ? factor : 0.0f; + mmd->factor_uvs = (mmd->flag & GP_NOISE_MOD_UV) ? factor : 0.0f; + mmd->noise_scale = (mmd->flag & GP_NOISE_FULL_STROKE) ? 0.0f : 1.0f; if (mmd->curve_intensity == NULL) { @@ -4730,16 +4725,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } break; } - case eGpencilModifierType_Vertexcolor: { - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - if (mmd->curve_intensity == NULL) { - mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - if (mmd->curve_intensity) { - BKE_curvemapping_initialize(mmd->curve_intensity); - } - } - break; - } default: break; } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index f0127330b1b..53c63ef980b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -627,7 +627,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) BKE_id_delete(bmain, brush); } - /* Rename and fix materials. */ + /* Rename and fix materials and enable default object lights on. */ if (app_template && STREQ(app_template, "2D_Animation")) { Material *ma = NULL; rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke"); @@ -654,6 +654,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) if (ma != NULL) { ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; } + + Object *ob = BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2); + if (ob && ob->type == OB_GPENCIL) { + ob->dtx |= OB_USE_GPENCIL_LIGHTS; + } } /* Reset all grease pencil brushes. */ diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 2fefa56fbe5..205106d7820 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -192,6 +192,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->space_node.grid_levels = U_theme_default.space_node.grid_levels; } + if (!USER_VERSION_ATLEAST(283, 9)) { + FROM_DEFAULT_V4_UCHAR(space_info.info_warning); + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index a9c5008062b..a92404b2372 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1844,8 +1844,8 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase) write_curvemapping(wd, gpmd->curfalloff); } } - else if (md->type == eGpencilModifierType_Vertexcolor) { - VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md; + else if (md->type == eGpencilModifierType_Tint) { + TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; if (gpmd->colorband) { writestruct(wd, DATA, ColorBand, 1, gpmd->colorband); } @@ -1871,12 +1871,6 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase) write_curvemapping(wd, gpmd->curve_intensity); } } - else if (md->type == eGpencilModifierType_Tint) { - TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; - if (gpmd->curve_intensity) { - write_curvemapping(wd, gpmd->curve_intensity); - } - } } } diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index c3667c364bc..55403cc35d3 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -89,7 +89,7 @@ bool BLT_lang_is_ime_supported(void); * NOTE: We translate BLT_I18NCONTEXT_DEFAULT as BLT_I18NCONTEXT_DEFAULT_BPY in Python, * as we can't use "natural" None value in rna string properties... :/ * The void string "" is also interpreted as BLT_I18NCONTEXT_DEFAULT. - * For perf reason, we only use the first char to detect this context, + * For performance reason, we only use the first char to detect this context, * so other contexts should never start with the same char! */ #define BLT_I18NCONTEXT_DEFAULT NULL diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index d14b7a51a94..b4e78453226 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -788,7 +788,7 @@ void BM_log_redo(BMesh *bm, BMLog *log) /* Currently at the beginning of the undo stack, move to first entry */ entry = log->entries.first; } - else if (entry && entry->next) { + else if (entry->next) { /* Move to next undo entry */ entry = entry->next; } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 6fc53da4940..1ab318a8946 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3164,7 +3164,7 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme) } else { /* The opposite side as the first direction because we're moving the other way. */ - edgehalf->leftv->is_profile_start = !toward_bv ^ right_highest; + edgehalf->leftv->is_profile_start = (!toward_bv) ^ right_highest; } /* The next jump will in the opposite direction relative to the BevVert. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index c512300200e..442b4aa406a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -321,7 +321,7 @@ void DepsgraphNodeBuilder::begin_build() for (IDNode *id_node : graph_->id_nodes) { /* It is possible that the ID does not need to have CoW version in which case id_cow is the * same as id_orig. Additionally, such ID might have been removed, which makes the check - * for whether id_cow is expanded to access freed memory. In orderr to deal with this we + * for whether id_cow is expanded to access freed memory. In order to deal with this we * check whether CoW is needed based on a scalar value which does not lead to access of * possibly deleted memory. * Additionally, this saves some space in the map by skipping mapping for datablocks which diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 35a45cc97f4..9447c365c48 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -777,6 +777,8 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake) if (!lbake->resource_only) { BLI_mutex_unlock(lbake->mutex); } + + EEVEE_volumes_free_smoke_textures(); } /* Cache as in draw cache not light cache. */ diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 61ca2317572..1e08741db26 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -786,8 +786,8 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved if (pinfo->do_grid_update) { scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID; } - /* If we update grid we need to update the cubemaps too. - * So always refresh cubemaps. */ + /* If we update grid we need to update the cube-maps too. + * So always refresh cube-maps. */ scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; /* Tag the lightcache to auto update. */ scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_AUTO; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 0f084ba306b..52fb8b3cced 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -125,7 +125,7 @@ extern struct DrawEngineType draw_engine_eevee_type; } \ ((void)0) -BLI_INLINE bool eevee_hdri_preview_overlay_enabled(View3D *v3d) +BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) { /* Only show the HDRI Preview in Shading Preview in the Viewport. */ if (v3d == NULL || v3d->shading.type != OB_MATERIAL) { diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 8c1c72a3c20..41f8dddf0fb 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -178,8 +178,6 @@ void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const float *viewport_size = DRW_viewport_size_get(); - BLI_listbase_clear(&e_data.smoke_domains); - const int tile_size = scene_eval->eevee.volumetric_tile_size; /* Find Froxel Texture resolution. */ diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index bef49efd3f9..f78826b2980 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -183,7 +183,7 @@ static void external_draw_scene_do(void *vedata) Scene *scene = draw_ctx->scene; RegionView3D *rv3d = draw_ctx->rv3d; ARegion *region = draw_ctx->region; - RenderEngineType *type; + const RenderEngineType *type; DRW_state_reset_ex(DRW_STATE_DEFAULT & ~DRW_STATE_DEPTH_LESS_EQUAL); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 4b6059f1474..e7914a1b86c 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -33,16 +33,16 @@ extern DrawEngineType draw_engine_gpencil_type; struct GPENCIL_Data; struct GPENCIL_StorageList; +struct GPUBatch; +struct GPUVertBuf; +struct GPUVertFormat; +struct GpencilBatchCache; struct MaterialGPencilStyle; struct Object; struct RenderEngine; struct RenderLayer; -struct bGPDstroke; struct View3D; -struct GpencilBatchCache; -struct GPUBatch; -struct GPUVertBuf; -struct GPUVertFormat; +struct bGPDstroke; /* used to convert pixel scale. */ #define GPENCIL_PIXEL_FACTOR 2000.0f diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c index 8536c642cb6..f81c51f0883 100644 --- a/source/blender/draw/engines/overlay/overlay_image.c +++ b/source/blender/draw/engines/overlay/overlay_image.c @@ -117,6 +117,9 @@ static void camera_background_images_stereo_setup(Scene *scene, /* show only left or right camera */ iuser->multiview_eye = v3d->stereo3d_camera; } + else { + iuser->multiview_eye = v3d->multiview_eye; + } BKE_image_multiview_index(ima, iuser); } @@ -366,7 +369,9 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob) * see: T59347 */ int size[2] = {0}; if (ima != NULL) { - tex = GPU_texture_from_blender(ima, ob->iuser, NULL, GL_TEXTURE_2D); + ImageUser iuser = *ob->iuser; + camera_background_images_stereo_setup(draw_ctx->scene, draw_ctx->v3d, ima, &iuser); + tex = GPU_texture_from_blender(ima, &iuser, NULL, GL_TEXTURE_2D); if (tex) { size[0] = GPU_texture_orig_width(tex); size[1] = GPU_texture_orig_height(tex); diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 0ab67d620ee..bc052e60009 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -203,7 +203,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. * But this is a workaround for a missing update tagging from operators. */ if (scene->display.shading.type != wpd->shading.type || - XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) { + (v3d && (XRAY_ENABLED(v3d) != XRAY_ENABLED(&scene->display)))) { wpd->view_updated = true; } diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index b91ca7cf070..742489c7311 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -212,8 +212,10 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, DRW_shgroup_hair_create_sub(ob, psys, md, grp); } -/* Decide what colortype to draw the object with. - * In some cases it can be overwritten by workbench_material_setup(). */ +/** + * Decide what color-type to draw the object with. + * In some cases it can be overwritten by #workbench_material_setup(). + */ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, Object *ob, bool *r_sculpt_pbvh, @@ -527,6 +529,8 @@ void workbench_draw_finish(void *ved) { WORKBENCH_Data *vedata = ved; workbench_volume_draw_finish(vedata); + /* Reset default view. */ + DRW_view_set_active(NULL); } static void workbench_engine_free(void) diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 8ed7bb25336..6c767102803 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -78,10 +78,10 @@ struct rcti; typedef struct DRWCallBuffer DRWCallBuffer; typedef struct DRWInterface DRWInterface; typedef struct DRWPass DRWPass; +typedef struct DRWShaderLibrary DRWShaderLibrary; typedef struct DRWShadingGroup DRWShadingGroup; typedef struct DRWUniform DRWUniform; typedef struct DRWView DRWView; -typedef struct DRWShaderLibrary DRWShaderLibrary; /* TODO Put it somewhere else? */ typedef struct BoundSphere { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 6d81d82a6cf..d718522bdb4 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1120,7 +1120,7 @@ static void use_drw_engine(DrawEngineType *engine) /* Gather all draw engines needed and store them in DST.enabled_engines * That also define the rendering order of engines */ -static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype) +static void drw_engines_enable_from_engine(const RenderEngineType *engine_type, eDrawType drawtype) { switch (drawtype) { case OB_WIRE: diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 7b08f44921f..7f9a6f578b7 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -558,13 +558,12 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const ch if (index > -1) { lib->libs[index] = lib_code; BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME); + lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code); } else { printf("Error: Too many libraries. Cannot add %s.\n", lib_name); BLI_assert(0); } - - lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code); } /* Return an allocN'ed string containing the shader code with its dependencies prepended. diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index ebde475a075..24ffc60453b 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -71,6 +71,7 @@ #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -916,7 +917,8 @@ static bool acf_group_setting_valid(bAnimContext *ac, /* for now, all settings are supported, though some are only conditionally */ switch (setting) { /* unsupported */ - case ACHANNEL_SETTING_SOLO: /* Only available in NLA Editor for tracks */ + case ACHANNEL_SETTING_SOLO: /* Only available in NLA Editor for tracks */ + case ACHANNEL_SETTING_PINNED: /* Only for NLA actions */ return false; /* conditionally supported */ @@ -1963,6 +1965,25 @@ static int acf_dsskey_icon(bAnimListElem *UNUSED(ale)) return ICON_SHAPEKEY_DATA; } +/* check if some setting exists for this channel */ +static bool acf_dsskey_setting_valid(bAnimContext *ac, + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) +{ + switch (setting) { + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; + + /* mute is only supported for NLA */ + case ACHANNEL_SETTING_MUTE: + return ((ac) && (ac->spacetype == SPACE_NLA)); + + default: + return false; + } +} + /* get the appropriate flag(s) for the setting when it is valid */ static int acf_dsskey_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, @@ -2029,9 +2050,9 @@ static bAnimChannelType ACF_DSSKEY = { acf_generic_idblock_name_prop, /* name prop */ acf_dsskey_icon, /* icon */ - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsskey_setting_flag, /* flag for setting */ - acf_dsskey_setting_ptr, /* pointer for setting */ + acf_dsskey_setting_valid, /* has setting */ + acf_dsskey_setting_flag, /* flag for setting */ + acf_dsskey_setting_ptr, /* pointer for setting */ }; /* World Expander ------------------------------------------- */ @@ -3155,6 +3176,8 @@ static bool acf_gpl_setting_valid(bAnimContext *UNUSED(ac), /* unsupported */ case ACHANNEL_SETTING_EXPAND: /* gpencil layers are more like F-Curves than groups */ case ACHANNEL_SETTING_SOLO: /* nla editor only */ + case ACHANNEL_SETTING_MOD_OFF: + case ACHANNEL_SETTING_PINNED: /* nla actions only */ return false; /* always available */ @@ -3335,6 +3358,9 @@ static bool acf_masklay_setting_valid(bAnimContext *UNUSED(ac), case ACHANNEL_SETTING_EXPAND: /* mask layers are more like F-Curves than groups */ case ACHANNEL_SETTING_VISIBLE: /* graph editor only */ case ACHANNEL_SETTING_SOLO: /* nla editor only */ + case ACHANNEL_SETTING_MOD_OFF: + case ACHANNEL_SETTING_PINNED: /* nla actions only */ + case ACHANNEL_SETTING_MUTE: return false; /* always available */ @@ -4112,10 +4138,6 @@ void ANIM_channel_draw( /* just skip - drawn as widget now */ offset += ICON_WIDTH; } - else if (ale->type == ANIMTYPE_GPLAYER) { - /* just skip - drawn as a widget */ - offset += ICON_WIDTH; - } } /* step 5) draw name ............................................... */ @@ -4163,8 +4185,16 @@ void ANIM_channel_draw( } /* step 6) draw backdrops behind mute+protection toggles + (sliders) ....................... */ - /* reset offset - now goes from RHS of panel */ - offset = 0; + /* - Reset offset - now goes from RHS of panel. + * - Exception for graph editor, which needs extra space for the scroll bar. + */ + if (ac->spacetype == SPACE_GRAPH && + ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_GROUP)) { + offset = V2D_SCROLL_WIDTH; + } + else { + offset = 0; + } /* TODO: when drawing sliders, make those draw instead of these toggles if not enough space */ @@ -4207,10 +4237,17 @@ void ANIM_channel_draw( if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { offset += ICON_WIDTH; } + + /* grease pencil visibility... */ if (ale->type == ANIMTYPE_GPLAYER) { offset += ICON_WIDTH; } + /* modifiers toggle... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) { + offset += ICON_WIDTH; + } + /* pinned... */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED)) { offset += ICON_WIDTH; @@ -4957,8 +4994,7 @@ void ANIM_channel_draw_widgets(const bContext *C, /* modifiers disable */ if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) { - /* hack: extra spacing, to avoid touching the mute toggle */ - offset -= ICON_WIDTH * 1.2f; + offset -= ICON_WIDTH; draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_MOD_OFF); } @@ -5073,37 +5109,19 @@ void ANIM_channel_draw_widgets(const bContext *C, else if (ale->type == ANIMTYPE_GPLAYER) { bGPdata *gpd = (bGPdata *)ale->id; if ((gpd != NULL) && ((gpd->flag & GP_DATA_ANNOTATIONS) == 0)) { - /* Add some offset to make it more pleasing to the eye. */ - offset += SLIDER_WIDTH / 2.1f; + /* Reset slider offset, in order to add special gp icons. */ + offset += SLIDER_WIDTH; char *gp_rna_path = NULL; bGPDlayer *gpl = (bGPDlayer *)ale->data; - const short width = SLIDER_WIDTH / 5; /* Create the RNA pointers. */ RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr); RNA_id_pointer_create(ale->id, &id_ptr); int icon; - /* Layer opacity. */ - UI_block_emboss_set(block, UI_EMBOSS); - prop = RNA_struct_find_property(&ptr, "opacity"); - gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); - if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) { - uiDefAutoButR(block, - &ptr, - prop, - array_index, - "", - ICON_NONE, - offset, - ymid, - width * 3, - channel_height); - } - MEM_freeN(gp_rna_path); - /* Mask Layer. */ + offset -= ICON_WIDTH; UI_block_emboss_set(block, UI_EMBOSS_NONE); prop = RNA_struct_find_property(&ptr, "use_mask_layer"); gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); @@ -5121,14 +5139,15 @@ void ANIM_channel_draw_widgets(const bContext *C, array_index, "", icon, - offset + (width * 3), + offset, ymid, - width, + ICON_WIDTH, channel_height); } MEM_freeN(gp_rna_path); /* Layer onion skinning switch. */ + offset -= ICON_WIDTH; prop = RNA_struct_find_property(&ptr, "use_onion_skinning"); gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) { @@ -5140,7 +5159,27 @@ void ANIM_channel_draw_widgets(const bContext *C, array_index, "", icon, - offset + (width * 4), + offset, + ymid, + ICON_WIDTH, + channel_height); + } + MEM_freeN(gp_rna_path); + + /* Layer opacity. */ + const short width = SLIDER_WIDTH * 0.6; + offset -= width; + UI_block_emboss_set(block, UI_EMBOSS); + prop = RNA_struct_find_property(&ptr, "opacity"); + gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); + if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) { + uiDefAutoButR(block, + &ptr, + prop, + array_index, + "", + ICON_NONE, + offset, ymid, width, channel_height); diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 98fcb9c5ce5..439b8071deb 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -368,9 +368,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) if (ale->update & ANIM_UPDATE_ORDER) { ale->update &= ~ANIM_UPDATE_ORDER; if (gpl) { - /* While correct & we could enable it: 'posttrans_gpd_clean' currently - * both sorts and removes doubles, so this is not necessary here. */ - // gpencil_sort_frames(gpl); + BKE_gpencil_layer_frames_sort(gpl, NULL); } } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 4b0a4bcf46b..8dfc9cd8d1a 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1715,22 +1715,33 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, /* loop over layers as the conditions are acceptable (top-Down order) */ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { /* only if selected */ - if (ANIMCHANNEL_SELOK(SEL_GPL(gpl))) { - /* only if editable */ - if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { - /* active... */ - if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) { - /* skip layer if the name doesn't match the filter string */ - if ((ads) && (ads->searchstr[0] != '\0')) { - if (name_matches_dopesheet_filter(ads, gpl->info) == false) { - continue; - } - } - /* add to list */ - ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL); - } - } + if (!ANIMCHANNEL_SELOK(SEL_GPL(gpl))) { + continue; + } + + /* only if editable */ + if ((filter_mode & ANIMFILTER_FOREDIT) && !EDITABLE_GPL(gpl)) { + continue; + } + + /* active... */ + if ((filter_mode & ANIMFILTER_ACTIVE) && (gpl->flag & GP_LAYER_ACTIVE) == 0) { + continue; } + + /* skip layer if the name doesn't match the filter string */ + if (ads != NULL && ads->searchstr[0] != '\0' && + name_matches_dopesheet_filter(ads, gpl->info) == false) { + continue; + } + + /* Skip empty layers. */ + if (BLI_listbase_is_empty(&gpl->frames)) { + continue; + } + + /* add to list */ + ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL); } return items; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 22a42d56fcd..c290a2ac70a 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -2709,7 +2709,7 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) /* ******************************************* */ /* AUTO KEYFRAME */ -bool autokeyframe_cfra_can_key(Scene *scene, ID *id) +bool autokeyframe_cfra_can_key(const Scene *scene, ID *id) { float cfra = (float)CFRA; // XXX for now, this will do diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 721953f41c8..6f9769f9785 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -673,7 +673,7 @@ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id) /* Getters for Active/Indices ----------------------------- */ /* Get the active Keying Set for the Scene provided */ -KeyingSet *ANIM_scene_get_active_keyingset(Scene *scene) +KeyingSet *ANIM_scene_get_active_keyingset(const Scene *scene) { /* if no scene, we've got no hope of finding the Keying Set */ if (scene == NULL) { @@ -728,7 +728,7 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks) } /* Get Keying Set to use for Auto-Keyframing some transforms */ -KeyingSet *ANIM_get_keyingset_for_autokeying(Scene *scene, const char *transformKSName) +KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName) { /* get KeyingSet to use * - use the active KeyingSet if defined (and user wants to use it for all autokeying), diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index d1352c66f75..1b147663a7e 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -609,6 +609,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.gpencil_draw.draw brush.gpencil_draw.erase brush.gpencil_draw.fill + brush.gpencil_draw.tint brush.paint_texture.airbrush brush.paint_texture.clone brush.paint_texture.draw @@ -622,6 +623,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.paint_vertex.average brush.paint_vertex.blur brush.paint_vertex.draw + brush.paint_vertex.replace brush.paint_vertex.smear brush.paint_weight.average brush.paint_weight.blur @@ -638,8 +640,11 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.sculpt.blob brush.sculpt.clay brush.sculpt.clay_strips + brush.sculpt.clay_thumb + brush.sculpt.cloth brush.sculpt.crease brush.sculpt.draw + brush.sculpt.draw_face_sets brush.sculpt.draw_sharp brush.sculpt.elastic_deform brush.sculpt.fill @@ -703,6 +708,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.gpencil.sculpt_twist ops.gpencil.sculpt_weight ops.gpencil.stroke_cutter + ops.gpencil.transform_fill ops.mesh.bevel ops.mesh.bisect ops.mesh.dupli_extrude_cursor @@ -776,6 +782,7 @@ if(WITH_BLENDER) # images data_to_c_simple(../../../../release/datafiles/splash.png SRC) data_to_c_simple(../../../../release/datafiles/splash_2x.png SRC) + data_to_c_simple(../../../../release/datafiles/alert_icons.png SRC) # XXX These are handy, but give nasty "false changes" in svn :/ # svg_to_png(../../../../release/datafiles/blender_icons.svg # ../../../../release/datafiles/blender_icons16.png diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 512e1ec6270..4083169d65c 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -58,8 +58,8 @@ set(SRC gpencil_undo.c gpencil_utils.c gpencil_uv.c - gpencil_vertex_paint.c gpencil_vertex_ops.c + gpencil_vertex_paint.c gpencil_weight_paint.c gpencil_intern.h diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 9b33e999a25..e5d332a86de 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -3179,7 +3179,7 @@ void GPENCIL_OT_color_unlock_all(wmOperatorType *ot) /* ***************** Select all strokes using color ************************ */ -static int gpencil_color_select_exec(bContext *C, wmOperator *op) +static int gpencil_select_material_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3249,15 +3249,15 @@ static int gpencil_color_select_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GPENCIL_OT_color_select(wmOperatorType *ot) +void GPENCIL_OT_select_material(wmOperatorType *ot) { /* identifiers */ - ot->name = "Select Color"; - ot->idname = "GPENCIL_OT_color_select"; - ot->description = "Select all Grease Pencil strokes using current color"; + ot->name = "Select Material"; + ot->idname = "GPENCIL_OT_select_material"; + ot->description = "Select/Deselect all Grease Pencil strokes using current material"; /* callbacks */ - ot->exec = gpencil_color_select_exec; + ot->exec = gpencil_select_material_exec; ot->poll = gpencil_active_color_poll; /* flags */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 2d36e426835..a12fd81e032 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -407,7 +407,7 @@ void GPENCIL_OT_select_less(struct wmOperatorType *ot); void GPENCIL_OT_select_first(struct wmOperatorType *ot); void GPENCIL_OT_select_last(struct wmOperatorType *ot); void GPENCIL_OT_select_alternate(struct wmOperatorType *ot); -void GPENCIL_OT_select_color(struct wmOperatorType *ot); +void GPENCIL_OT_select_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_duplicate(struct wmOperatorType *ot); void GPENCIL_OT_delete(struct wmOperatorType *ot); @@ -552,7 +552,7 @@ void GPENCIL_OT_color_hide(struct wmOperatorType *ot); void GPENCIL_OT_color_reveal(struct wmOperatorType *ot); void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot); void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot); -void GPENCIL_OT_color_select(struct wmOperatorType *ot); +void GPENCIL_OT_select_material(struct wmOperatorType *ot); void GPENCIL_OT_set_active_material(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 275075c38db..233bebfc9b6 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -544,7 +544,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_select_first); WM_operatortype_append(GPENCIL_OT_select_last); WM_operatortype_append(GPENCIL_OT_select_alternate); - WM_operatortype_append(GPENCIL_OT_select_color); + WM_operatortype_append(GPENCIL_OT_select_vertex_color); WM_operatortype_append(GPENCIL_OT_duplicate); WM_operatortype_append(GPENCIL_OT_delete); @@ -653,7 +653,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_color_reveal); WM_operatortype_append(GPENCIL_OT_color_lock_all); WM_operatortype_append(GPENCIL_OT_color_unlock_all); - WM_operatortype_append(GPENCIL_OT_color_select); + WM_operatortype_append(GPENCIL_OT_select_material); /* Editing (Time) --------------- */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 46788eba370..e7586d95d29 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1653,9 +1653,6 @@ static void gp_session_validatebuffer(tGPsdata *p) /* reset flags */ gpd->runtime.sbuffer_sflag = 0; - /* reset region */ - gpd->runtime.ar = NULL; - /* reset inittime */ p->inittime = 0.0; @@ -1884,7 +1881,6 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) /* setup active color */ /* region where paint was originated */ - p->gpd->runtime.ar = CTX_wm_region(C); int totcol = p->ob->totcol; gp_init_colors(p); diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 96522d1750c..66c0131cd61 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1157,8 +1157,6 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) /* set GP datablock */ tgpi->gpd = gpd; - /* region where paint was originated */ - tgpi->gpd->runtime.ar = tgpi->region; /* if brush doesn't exist, create a new set (fix damaged files from old versions) */ if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 26b68707d55..133891cda13 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -1655,7 +1655,50 @@ void GPENCIL_OT_select(wmOperatorType *ot) } /* Select by Vertex Color. */ -static bool gpencil_select_color_poll(bContext *C) +/* Helper to create a hash of colors. */ +static void gpencil_selected_hue_table(bContext *C, + Object *ob, + const int threshold, + GHash *hue_table) +{ + const float range = pow(10, 5 - threshold); + float hsv[3]; + + /* Extract all colors. */ + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + if ((gps->flag & GP_STROKE_SELECT) == 0) { + continue; + } + + /* Read all points to get all colors selected. */ + bGPDspoint *pt; + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (((pt->flag & GP_SPOINT_SELECT) == 0) || (pt->vert_color[3] == 0.0f)) { + continue; + } + /* Round Hue value. */ + rgb_to_hsv_compat_v(pt->vert_color, hsv); + uint key = truncf(hsv[0] * range); + if (!BLI_ghash_haskey(hue_table, POINTER_FROM_INT(key))) { + BLI_ghash_insert(hue_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key)); + } + } + } + } + } + CTX_DATA_END; +} + +static bool gpencil_select_vertex_color_poll(bContext *C) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); @@ -1678,38 +1721,46 @@ static bool gpencil_select_color_poll(bContext *C) return false; } -static int gpencil_select_color_exec(bContext *C, wmOperator *op) +static int gpencil_select_vertex_color_exec(bContext *C, wmOperator *op) { - const float threshold = RNA_float_get(op->ptr, "threshold"); - ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + + const float threshold = RNA_int_get(op->ptr, "threshold"); + const int selectmode = gpencil_select_mode_from_vertex(ts->gpencil_selectmode_vertex); bGPdata *gpd = (bGPdata *)ob->data; - if (!GPENCIL_VERTEX_MODE(gpd)) { - return OPERATOR_CANCELLED; - } + const float range = pow(10, 5 - threshold); - Paint *paint = &ts->gp_vertexpaint->paint; - Brush *brush = paint->brush; bool done = false; - float hsv_brush[3], hsv_stroke[3]; - rgb_to_hsv_compat_v(brush->rgb, hsv_brush); + /* Create a hash table with all selected colors. */ + GHash *hue_table = BLI_ghash_int_new(__func__); + gpencil_selected_hue_table(C, ob, threshold, hue_table); + if (BLI_ghash_len(hue_table) == 0) { + BKE_report(op->reports, RPT_ERROR, "Select before some Vertex to use as a filter color"); + BLI_ghash_free(hue_table, NULL, NULL); + + return OPERATOR_CANCELLED; + } - /* Select any visible stroke that uses this color */ + /* Select any visible stroke that uses any of these colors. */ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { bGPDspoint *pt; int i; bool gps_selected = false; /* Check all stroke points. */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->vert_color[3] < 0.03f) { + if (pt->vert_color[3] == 0.0f) { continue; } - rgb_to_hsv_compat_v(pt->vert_color, hsv_stroke); - /* Only check Hue to get full value and saturation ranges. */ - if (compare_ff(hsv_stroke[0], hsv_brush[0], threshold)) { + /* Only check Hue to get value and saturation full ranges. */ + float hsv[3]; + /* Round Hue value. */ + rgb_to_hsv_compat_v(pt->vert_color, hsv); + uint key = truncf(hsv[0] * range); + + if (BLI_ghash_haskey(hue_table, POINTER_FROM_INT(key))) { pt->flag |= GP_SPOINT_SELECT; gps_selected = true; } @@ -1718,6 +1769,15 @@ static int gpencil_select_color_exec(bContext *C, wmOperator *op) if (gps_selected) { gps->flag |= GP_STROKE_SELECT; done = true; + + /* Extend stroke selection. */ + if (selectmode == GP_SELECTMODE_STROKE) { + bGPDspoint *pt1 = NULL; + + for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) { + pt1->flag |= GP_SPOINT_SELECT; + } + } } } CTX_DATA_END; @@ -1733,27 +1793,41 @@ static int gpencil_select_color_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); } + /* Free memory. */ + if (hue_table != NULL) { + BLI_ghash_free(hue_table, NULL, NULL); + } + return OPERATOR_FINISHED; } -void GPENCIL_OT_select_color(wmOperatorType *ot) +void GPENCIL_OT_select_vertex_color(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Select Color"; - ot->idname = "GPENCIL_OT_select_color"; - ot->description = "Select all strokes with same color"; + ot->name = "Select Vertex Color"; + ot->idname = "GPENCIL_OT_select_vertex_color"; + ot->description = "Select all points with similar vertex color of current selected"; /* callbacks */ - ot->exec = gpencil_select_color_exec; - ot->poll = gpencil_select_color_poll; + ot->exec = gpencil_select_vertex_color_exec; + ot->poll = gpencil_select_vertex_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - prop = RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f); + prop = RNA_def_int( + ot->srna, + "threshold", + 0, + 0, + 5, + "Threshold", + "Tolerance of the selection. Higher values select a wider range of similar colors", + 0, + 5); /* avoid re-using last var */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index a975af1c19a..7fe6f374766 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -2583,10 +2583,9 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, bGPDspoint pt_dummy, pt_dummy_ps; float boundbox_min[2] = {0.0f}; float boundbox_max[2] = {0.0f}; - float zerov3[3]; /* Check we have something to use (only for old files). */ - if (equals_v3v3(zerov3, gps->boundbox_min)) { + if (is_zero_v3(gps->boundbox_min)) { BKE_gpencil_stroke_boundingbox_calc(gps); } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index c730d1b493e..45dc22bafba 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -104,6 +104,7 @@ typedef struct tGP_BrushVertexpaintData { bGPdata *gpd; Brush *brush; + float linear_color[3]; eGPDvertex_brush_Flag flag; eGP_Vertex_SelectMaskFlag mask; @@ -444,7 +445,7 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, /* Premult. */ mul_v3_fl(pt->vert_color, pt->vert_color[3]); /* "Alpha over" blending. */ - interp_v3_v3v3(pt->vert_color, pt->vert_color, brush->rgb, inf); + interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf); pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf; /* Un-premult. */ if (pt->vert_color[3] > 0.0f) { @@ -463,7 +464,7 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, /* Premult. */ mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]); /* "Alpha over" blending. */ - interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, brush->rgb, inf_fill); + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill); gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill; /* Un-premult. */ if (gps->vert_color_fill[3] > 0.0f) { @@ -483,19 +484,15 @@ static bool brush_replace_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, /* Apply color to Stroke point. */ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { - copy_v3_v3(pt->vert_color, brush->rgb); - /* If not mix color, full replace. */ - if (pt->vert_color[3] == 0.0f) { - pt->vert_color[3] = 1.0f; + if (pt->vert_color[3] > 0.0f) { + copy_v3_v3(pt->vert_color, gso->linear_color); } } /* Apply color to Fill area (all with same color and factor). */ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { - copy_v3_v3(gps->vert_color_fill, brush->rgb); - /* If not mix color, full replace. */ - if (gps->vert_color_fill[3] == 0.0f) { - gps->vert_color_fill[3] = 1.0f; + if (gps->vert_color_fill[3] > 0.0f) { + copy_v3_v3(gps->vert_color_fill, gso->linear_color); } } @@ -731,6 +728,7 @@ static bool gp_vertexpaint_brush_init(bContext *C, wmOperator *op) op->customdata = gso; gso->brush = paint->brush; + srgb_to_linearrgb_v3_v3(gso->linear_color, gso->brush->rgb); BKE_curvemapping_initialize(gso->brush->curve); gso->is_painting = false; diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index c1f5eddd8df..a2ad343da37 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -48,6 +48,9 @@ extern char datatoc_blender_icons32_png[]; extern int datatoc_prvicons_png_size; extern char datatoc_prvicons_png[]; +extern int datatoc_alert_icons_png_size; +extern char datatoc_alert_icons_png[]; + extern int datatoc_splash_png_size; extern char datatoc_splash_png[]; diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 06af48cd476..a523e924e54 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -30,6 +30,7 @@ extern "C" { struct ARegion; struct FileSelectParams; +struct Scene; struct ScrArea; struct SpaceFile; struct bContext; @@ -133,9 +134,13 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y); void ED_operatormacros_file(void); -void ED_fileselect_clear(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile); +void ED_fileselect_clear(struct wmWindowManager *wm, + struct Scene *owner_scene, + struct SpaceFile *sfile); -void ED_fileselect_exit(struct wmWindowManager *wm, struct ScrArea *sa, struct SpaceFile *sfile); +void ED_fileselect_exit(struct wmWindowManager *wm, + struct Scene *owner_scene, + struct SpaceFile *sfile); void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 8dd162ea538..66aa301f08c 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -33,13 +33,13 @@ struct ListBase; struct PointerRNA; struct Brush; +struct GP_SpaceConversion; struct bGPDframe; struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; struct tGPspoint; -struct GP_SpaceConversion; struct ARegion; struct Depsgraph; @@ -47,8 +47,8 @@ struct Main; struct RegionView3D; struct ReportList; struct Scene; -struct ToolSettings; struct ScrArea; +struct ToolSettings; struct View3D; struct ViewLayer; struct bContext; diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 2f81e28b496..6cac3e60531 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -259,13 +259,13 @@ void ANIM_keyingset_infos_exit(void); /* -------- */ /* Get the active KeyingSet for the given scene */ -struct KeyingSet *ANIM_scene_get_active_keyingset(struct Scene *scene); +struct KeyingSet *ANIM_scene_get_active_keyingset(const struct Scene *scene); /* Get the index of the Keying Set provided, for the given Scene */ int ANIM_scene_get_keyingset_index(struct Scene *scene, struct KeyingSet *ks); /* Get Keying Set to use for Auto-Keyframing some transforms */ -struct KeyingSet *ANIM_get_keyingset_for_autokeying(struct Scene *scene, +struct KeyingSet *ANIM_get_keyingset_for_autokeying(const struct Scene *scene, const char *tranformKSName); /* Dynamically populate an enum of Keying Sets */ @@ -442,7 +442,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch (U.autokey_flag & AUTOKEY_FLAG_##flag)) /* auto-keyframing feature - checks for whether anything should be done for the current frame */ -bool autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id); +bool autokeyframe_cfra_can_key(const struct Scene *scene, struct ID *id); /* ************ Keyframe Checking ******************** */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 1dd40f27fbb..0785b0e97f7 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -431,6 +431,7 @@ int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int s bool ED_region_overlap_isect_x(const ARegion *region, const int event_x); bool ED_region_overlap_isect_y(const ARegion *region, const int event_y); bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]); +bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]); bool ED_region_overlap_isect_x_with_margin(const ARegion *region, const int event_x, const int margin); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 7b9e4cfe7bf..f882d6be9a2 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -581,7 +581,7 @@ void ED_draw_object_facemap(struct Depsgraph *depsgraph, const float col[4], const int facemap); -struct RenderEngineType *ED_view3d_engine_type(struct Scene *scene, int drawtype); +struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype); bool ED_view3d_context_activate(struct bContext *C); void ED_view3d_draw_setup_view(struct wmWindow *win, @@ -598,7 +598,7 @@ struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]); void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *region, bool do_clip); void ED_view3d_update_viewmat(struct Depsgraph *depsgraph, - struct Scene *scene, + const struct Scene *scene, struct View3D *v3d, struct ARegion *region, float viewmat[4][4], @@ -648,7 +648,7 @@ bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d); -bool ED_view3d_camera_autokey(struct Scene *scene, +bool ED_view3d_camera_autokey(const struct Scene *scene, struct ID *id_key, struct bContext *C, const bool do_rotate, @@ -670,9 +670,9 @@ bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d, const float dist_co[3], const float dist_min); -float ED_scene_grid_scale(struct Scene *scene, const char **grid_unit); -float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit); -void ED_view3d_grid_steps(struct Scene *scene, +float ED_scene_grid_scale(const struct Scene *scene, const char **grid_unit); +float ED_view3d_grid_scale(const struct Scene *scene, struct View3D *v3d, const char **grid_unit); +void ED_view3d_grid_steps(const struct Scene *scene, struct View3D *v3d, struct RegionView3D *rv3d, float *r_grid_steps); @@ -681,7 +681,7 @@ float ED_view3d_grid_view_scale(struct Scene *scene, struct RegionView3D *rv3d, const char **grid_unit); -void ED_scene_draw_fps(struct Scene *scene, int xoffset, int *yoffset); +void ED_scene_draw_fps(const struct Scene *scene, int xoffset, int *yoffset); /* view matrix properties utilities */ /* unused */ @@ -708,7 +708,7 @@ void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrAr /* view3d_draw_legacy.c */ /* Try avoid using these more move out of legacy. */ -void ED_view3d_draw_bgpic_test(struct Scene *scene, +void ED_view3d_draw_bgpic_test(const struct Scene *scene, struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h index f69d8367dca..539a4d13ccd 100644 --- a/source/blender/editors/include/ED_view3d_offscreen.h +++ b/source/blender/editors/include/ED_view3d_offscreen.h @@ -34,16 +34,16 @@ extern "C" { #endif /* ********* exports for space_view3d/ module for offscreen rendering ********** */ -struct Depsgraph; -struct Scene; -struct View3D; struct ARegion; +struct Depsgraph; struct GPUOffScreen; struct GPUViewport; +struct Scene; +struct View3D; struct View3DShading; void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph, - struct Scene *scene, + const struct Scene *scene, eDrawType drawtype, struct View3D *v3d, struct ARegion *region, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index dba95c5106e..3e416cd8057 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1124,7 +1124,9 @@ uiBut *uiDefIconButO_ptr(uiBlock *block, short width, short height, const char *tip); - +uiBut *uiDefButImage( + uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]); +uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height); uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, @@ -1805,7 +1807,7 @@ uiLayout *UI_block_layout(uiBlock *block, int size, int em, int padding, - struct uiStyle *style); + const struct uiStyle *style); void UI_block_layout_set_current(uiBlock *block, uiLayout *layout); void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y); @@ -2431,8 +2433,8 @@ int UI_fontstyle_height_max(const struct uiFontStyle *fs); void UI_draw_icon_tri(float x, float y, char dir, const float[4]); -struct uiStyle *UI_style_get(void); /* use for fonts etc */ -struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */ +const struct uiStyle *UI_style_get(void); /* use for fonts etc */ +const struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */ /* linker workaround ack! */ void UI_template_fix_linking(void); diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 6bf0cb8952d..a304c76bc9d 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -52,6 +52,17 @@ typedef struct IconFile { #define PREVIEW_DEFAULT_HEIGHT 128 +typedef enum eAlertIcon { + ALERT_ICON_WARNING = 0, + ALERT_ICON_QUESTION = 1, + ALERT_ICON_ERROR = 2, + ALERT_ICON_INFO = 3, + ALERT_ICON_BLENDER = 4, + ALERT_ICON_MAX, +} eAlertIcon; + +struct ImBuf *UI_alert_image(eAlertIcon icon); + /* * Resizable Icons for Blender */ diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index ecdae3ead6b..ff9719d4674 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -250,13 +250,17 @@ char UI_view2d_rect_in_scrollers(const struct ARegion *region, const struct rcti *rect); /* cached text drawing in v2d, to allow pixel-aligned draw as post process */ -void UI_view2d_text_cache_add( - struct View2D *v2d, float x, float y, const char *str, size_t str_len, const char col[4]); +void UI_view2d_text_cache_add(struct View2D *v2d, + float x, + float y, + const char *str, + size_t str_len, + const unsigned char col[4]); void UI_view2d_text_cache_add_rectf(struct View2D *v2d, const struct rctf *rect_view, const char *str, size_t str_len, - const char col[4]); + const unsigned char col[4]); void UI_view2d_text_cache_draw(struct ARegion *region); /* operators */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index a0a3d0a3b85..3d8c0da78ea 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -366,7 +366,7 @@ void UI_block_translate(uiBlock *block, int x, int y) static void ui_block_bounds_calc_text(uiBlock *block, float offset) { - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); uiBut *bt, *init_col_bt, *col_bt; int i = 0, j, x1addval = offset; @@ -4439,6 +4439,48 @@ uiBut *uiDefBut(uiBlock *block, return but; } +uiBut *uiDefButImage( + uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]) +{ + uiBut *but = ui_def_but( + block, UI_BTYPE_IMAGE, 0, "", x, y, width, height, imbuf, 0, 0, 0, 0, ""); + if (color) { + copy_v4_v4_uchar(but->col, color); + } + else { + but->col[0] = 255; + but->col[1] = 255; + but->col[2] = 255; + but->col[3] = 255; + } + ui_but_update(but); + return but; +} + +uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height) +{ + struct ImBuf *ibuf = UI_alert_image(icon); + + if (icon == ALERT_ICON_BLENDER) { + return uiDefButImage(block, ibuf, x, y, width, height, NULL); + } + else { + uchar icon_color[4]; + ThemeColorID color_id = TH_INFO_WARNING; + if (icon == ALERT_ICON_ERROR) { + color_id = TH_INFO_ERROR; + } + else if (icon == ALERT_ICON_INFO) { + color_id = TH_INFO_INFO; + } + else if (icon == ALERT_ICON_QUESTION) { + color_id = TH_INFO_PROPERTY; + } + UI_GetThemeColorType4ubv(color_id, SPACE_INFO, icon_color); + return uiDefButImage(block, ibuf, x, y, width, height, icon_color); + } +} + /** * if \a _x_ is a power of two (only one bit) return the power, * otherwise return -1. diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index c9a46e00520..f6da9663daf 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -169,7 +169,7 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *region, void *arg) wmKeyMapItem *kmi; PointerRNA ptr; uiLayout *layout; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); @@ -225,7 +225,7 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg) wmKeyMapItem *kmi; PointerRNA ptr; uiLayout *layout; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); int kmi_id; IDProperty *prop; const char *idname = shortcut_get_operator_property(C, but, &prop); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index e8e74e77425..2800d808889 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -707,9 +707,6 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), return; } - float facx = 1.0f; - float facy = 1.0f; - int w = BLI_rcti_size_x(rect); int h = BLI_rcti_size_y(rect); @@ -722,10 +719,18 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), # endif GPU_blend(true); + /* Combine with premultiplied alpha. */ + GPU_blend_set_func_separate(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); if (w != ibuf->x || h != ibuf->y) { - facx = (float)w / (float)ibuf->x; - facy = (float)h / (float)ibuf->y; + /* We scale the bitmap, rather than have OGL do a worse job. */ + IMB_scaleImBuf(ibuf, w, h); + } + + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + if (but->col[3] != 0) { + /* Optionally use uiBut's col to recolor the image. */ + rgba_uchar_to_float(col, but->col); } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); @@ -738,11 +743,14 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect, - facx, - facy, - NULL); + 1.0f, + 1.0f, + col); GPU_blend(false); + /* Reset default. */ + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); # if 0 // restore scissortest diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 833631f871d..f4dd114c312 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -58,6 +58,7 @@ #include "BKE_unit.h" #include "BKE_paint.h" #include "BKE_curveprofile.h" +#include "BKE_movieclip.h" #include "IMB_colormanagement.h" @@ -2847,10 +2848,9 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) */ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, const float x) { - uiStyle *style = UI_style_get(); // XXX pass on as arg - uiFontStyle *fstyle = &style->widget; + /* XXX pass on as arg. */ + uiFontStyle fstyle = UI_style_get()->widget; const float aspect = but->block->aspect; - const short fstyle_points_prev = fstyle->points; float startx = but->rect.xmin; float starty_dummy = 0.0f; @@ -2860,13 +2860,13 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy); - ui_fontscale(&fstyle->points, aspect); + ui_fontscale(&fstyle.points, aspect); - UI_fontstyle_set(fstyle); + UI_fontstyle_set(&fstyle); - if (fstyle->kerning == 1) { + if (fstyle.kerning == 1) { /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + BLF_enable(fstyle.uifont_id, BLF_KERNING_DEFAULT); } ui_but_text_password_hide(password_str, but, false); @@ -2888,7 +2888,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con while (i > 0) { if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &i)) { /* 0.25 == scale factor for less sensitivity */ - if (BLF_width(fstyle->uifont_id, str + i, (str_last - str) - i) > (startx - x) * 0.25f) { + if (BLF_width(fstyle.uifont_id, str + i, (str_last - str) - i) > (startx - x) * 0.25f) { break; } } @@ -2912,7 +2912,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con but->pos = pos_prev = ((str_last - str) - but->ofs); while (true) { - cdist = startx + BLF_width(fstyle->uifont_id, str + but->ofs, (str_last - str) - but->ofs); + cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs); /* check if position is found */ if (cdist < x) { @@ -2944,13 +2944,11 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con } } - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + if (fstyle.kerning == 1) { + BLF_disable(fstyle.uifont_id, BLF_KERNING_DEFAULT); } ui_but_text_password_hide(password_str, but, true); - - fstyle->points = fstyle_points_prev; } static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, const float x) @@ -7339,8 +7337,10 @@ static bool ui_numedit_but_TRACKPREVIEW( } if (!scopes->track_locked) { - if (scopes->marker->framenr != scopes->framenr) { - scopes->marker = BKE_tracking_marker_ensure(scopes->track, scopes->framenr); + const MovieClip *clip = CTX_data_edit_movieclip(C); + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scopes->framenr); + if (scopes->marker->framenr != clip_framenr) { + scopes->marker = BKE_tracking_marker_ensure(scopes->track, clip_framenr); } scopes->marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 3e07023e52d..a37b49f5b6e 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -177,6 +177,30 @@ static const IconType icontypes[] = { # include "UI_icons.h" }; +/* ********** Alert Icons ********** */ + +# define ALERT_IMG_SIZE 256 + +ImBuf *UI_alert_image(eAlertIcon icon) +{ +# ifdef WITH_HEADLESS + return NULL +# else + ImBuf *ibuf; + icon = MIN2(icon, ALERT_ICON_MAX - 1); + const int left = icon * ALERT_IMG_SIZE; + const rcti crop = {left, left + ALERT_IMG_SIZE - 1, 0, ALERT_IMG_SIZE - 1}; + ibuf = IMB_ibImageFromMemory((const uchar *)datatoc_alert_icons_png, + datatoc_alert_icons_png_size, + IB_rect, + NULL, + "alert_icon"); + IMB_rect_crop(ibuf, &crop); + IMB_premultiply_alpha(ibuf); + return ibuf; +# endif +} + /* **************************************************** */ static DrawInfo *def_internal_icon( diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index a2e239884a3..e2b4e8f2958 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -839,7 +839,7 @@ const struct uiWidgetColors *ui_tooltip_get_theme(void); void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4]); void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow); -void ui_draw_tooltip_background(struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect); +void ui_draw_tooltip_background(const struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect); extern void ui_draw_but( const struct bContext *C, ARegion *region, struct uiStyle *style, uiBut *but, rcti *rect); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 1aa2670942f..64ff9d02cdc 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -91,7 +91,7 @@ typedef struct uiLayoutRoot { uiMenuHandleFunc handlefunc; void *argv; - uiStyle *style; + const uiStyle *style; uiBlock *block; uiLayout *layout; } uiLayoutRoot; @@ -499,7 +499,7 @@ static void ui_item_array(uiLayout *layout, bool compact, bool show_text) { - uiStyle *style = layout->root->style; + const uiStyle *style = layout->root->style; uiBut *but; PropertyType type; PropertySubType subtype; @@ -3707,7 +3707,7 @@ static void ui_litem_layout_root(uiLayout *litem) /* box layout */ static void ui_litem_estimate_box(uiLayout *litem) { - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; ui_litem_estimate_column(litem, true); @@ -3722,7 +3722,7 @@ static void ui_litem_estimate_box(uiLayout *litem) static void ui_litem_layout_box(uiLayout *litem) { uiLayoutItemBx *box = (uiLayoutItemBx *)litem; - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; uiBut *but; int w, h; @@ -3767,7 +3767,7 @@ static void ui_litem_layout_box(uiLayout *litem) /* multi-column layout, automatically flowing to the next */ static void ui_litem_estimate_column_flow(uiLayout *litem) { - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; uiItem *item; int col, x, y, emh, emy, miny, itemw, itemh, maxw = 0; @@ -3832,7 +3832,7 @@ static void ui_litem_estimate_column_flow(uiLayout *litem) static void ui_litem_layout_column_flow(uiLayout *litem) { - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; uiItem *item; int col, x, y, w, emh, emy, miny, itemw, itemh; @@ -4071,7 +4071,7 @@ static void ui_litem_grid_flow_compute(ListBase *items, static void ui_litem_estimate_grid_flow(uiLayout *litem) { - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem; const int space_x = style->columnspace; @@ -4199,7 +4199,7 @@ static void ui_litem_estimate_grid_flow(uiLayout *litem) static void ui_litem_layout_grid_flow(uiLayout *litem) { int i; - uiStyle *style = litem->root->style; + const uiStyle *style = litem->root->style; uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem; uiItem *item; @@ -5092,8 +5092,15 @@ static void ui_layout_add_padding_button(uiLayoutRoot *root) } } -uiLayout *UI_block_layout( - uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, uiStyle *style) +uiLayout *UI_block_layout(uiBlock *block, + int dir, + int type, + int x, + int y, + int size, + int em, + int padding, + const uiStyle *style) { uiLayout *layout; uiLayoutRoot *root; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 70d64ff26ab..1f5855aed9e 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -434,7 +434,7 @@ void UI_panel_end( static void ui_offset_panel_block(uiBlock *block) { - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); /* compute bounds and offset */ ui_block_bounds_calc(block); @@ -1938,7 +1938,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) // #define USE_FLAT_INACTIVE const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); View2D *v2d = ®ion->v2d; - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; short fstyle_points = fstyle->points; diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index f75f4c054a3..062a8383061 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -104,13 +104,12 @@ static float ui_pie_menu_title_width(const char *name, int icon) uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event) { - uiStyle *style; + const uiStyle *style = UI_style_get_dpi(); uiPieMenu *pie; short event_type; wmWindow *win = CTX_wm_window(C); - style = UI_style_get_dpi(); pie = MEM_callocN(sizeof(*pie), "pie menu"); pie->block_radial = UI_block_begin(C, NULL, __func__, UI_EMBOSS); diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index 1d066b6bbb1..9ceb864b278 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -310,7 +310,7 @@ uiPopupBlockHandle *ui_popup_menu_create( bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg) { wmWindow *window = CTX_wm_window(C); - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); uiPopupBlockHandle *handle; uiPopupMenu *pup; @@ -380,7 +380,7 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, const char *block_name, int icon) { - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); uiPopupMenu *pup = MEM_callocN(sizeof(uiPopupMenu), "popup menu"); uiBut *but; diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 4e4854c8209..d3cd1ebd837 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -94,7 +94,7 @@ static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext) { BLI_assert(pup->ui_size_x != 0); - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS); UI_block_flag_enable(pup->block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER); diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 4481ad54d1a..89eb0658d5e 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -498,7 +498,7 @@ static void ui_searchbox_region_free_cb(ARegion *region) ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but) { wmWindow *win = CTX_wm_window(C); - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); static ARegionType type; ARegion *region; uiSearchboxData *data; diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index c18c78c22a6..02c69e5cef6 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -1158,7 +1158,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, wmWindow *win = CTX_wm_window(C); const int winx = WM_window_pixels_x(win); const int winy = WM_window_pixels_y(win); - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); static ARegionType type; ARegion *region; int fonth, fontw; diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 192571044b9..fa1f222d27f 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -351,7 +351,7 @@ void UI_fontstyle_draw_simple_backdrop(const uiFontStyle *fs, /* ************** helpers ************************ */ /* XXX: read a style configure */ -uiStyle *UI_style_get(void) +const uiStyle *UI_style_get(void) { #if 0 uiStyle *style = NULL; @@ -364,9 +364,9 @@ uiStyle *UI_style_get(void) } /* for drawing, scaled with DPI setting */ -uiStyle *UI_style_get_dpi(void) +const uiStyle *UI_style_get_dpi(void) { - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); static uiStyle _style; _style = *style; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b752a1a1429..f11e3a1f5f0 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -591,11 +591,9 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) DEG_relations_tag_update(bmain); } else { - if (id) { - Main *bmain = CTX_data_main(C); - id_single_user(C, id, &template_ui->ptr, template_ui->prop); - DEG_relations_tag_update(bmain); - } + Main *bmain = CTX_data_main(C); + id_single_user(C, id, &template_ui->ptr, template_ui->prop); + DEG_relations_tag_update(bmain); } } break; @@ -1137,7 +1135,7 @@ static void template_ID_tabs(bContext *C, const int but_height = UI_UNIT_Y * 1.1; uiBlock *block = uiLayoutGetBlock(layout); - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); ListBase ordered; BKE_id_ordered_list(&ordered, template->idlb); @@ -3049,7 +3047,7 @@ static void colorband_tools_dofunc(bContext *C, void *coba_v, int event) static uiBlock *colorband_tools_func(bContext *C, ARegion *region, void *coba_v) { - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); ColorBand *coba = coba_v; uiBlock *block; short yco = 0, menuwidth = 10 * UI_UNIT_X; @@ -7135,7 +7133,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) uiLayout *ui_abs; uiBlock *block; uiBut *but; - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); int width; int icon; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 31a1c150b12..b61d54e6cff 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -4990,22 +4990,37 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol, if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv(wcol->inner); + + const bool is_down = (direction == UI_DIR_DOWN); + const int sign = is_down ? 1 : -1; + float y = is_down ? rect->ymax : rect->ymin; + GPU_blend(true); immBegin(GPU_PRIM_TRIS, 3); - if (direction == UI_DIR_DOWN) { - const float y = rect->ymax; - immVertex2f(pos, cent_x - unit_half, y); - immVertex2f(pos, cent_x + unit_half, y); - immVertex2f(pos, cent_x, y + unit_half); - } - else { - const float y = rect->ymin; - immVertex2f(pos, cent_x - unit_half, y); - immVertex2f(pos, cent_x + unit_half, y); - immVertex2f(pos, cent_x, y - unit_half); - } + immUniformColor4ub(UNPACK3(wcol->outline), 166); + immVertex2f(pos, cent_x - unit_half, y); + immVertex2f(pos, cent_x + unit_half, y); + immVertex2f(pos, cent_x, y + sign * unit_half); immEnd(); + + y = y - sign * round(U.pixelsize * 1.41); + + GPU_blend(false); + immBegin(GPU_PRIM_TRIS, 3); + immUniformColor4ub(0, 0, 0, 0); + immVertex2f(pos, cent_x - unit_half, y); + immVertex2f(pos, cent_x + unit_half, y); + immVertex2f(pos, cent_x, y + sign * unit_half); + immEnd(); + + GPU_blend(true); + immBegin(GPU_PRIM_TRIS, 3); + immUniformColor4ubv(wcol->inner); + immVertex2f(pos, cent_x - unit_half, y); + immVertex2f(pos, cent_x + unit_half, y); + immVertex2f(pos, cent_x, y + sign * unit_half); + immEnd(); + immUnbindProgram(); } @@ -5235,7 +5250,7 @@ void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow) ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, NULL); } -void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect) +void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect) { uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP); wt->state(wt, 0, 0); diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index af32143df33..ad2e32149d8 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -243,7 +243,7 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) { bool tot_changed = false, do_init; - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); do_init = (v2d->flag & V2D_IS_INITIALISED) == 0; @@ -2146,7 +2146,7 @@ static MemArena *g_v2d_strings_arena = NULL; static View2DString *g_v2d_strings = NULL; void UI_view2d_text_cache_add( - View2D *v2d, float x, float y, const char *str, size_t str_len, const char col[4]) + View2D *v2d, float x, float y, const char *str, size_t str_len, const uchar col[4]) { int mval[2]; @@ -2177,7 +2177,7 @@ void UI_view2d_text_cache_add( /* no clip (yet) */ void UI_view2d_text_cache_add_rectf( - View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const char col[4]) + View2D *v2d, const rctf *rect_view, const char *str, size_t str_len, const uchar col[4]) { rcti rect; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 7eea9e6a697..2c9803d1dd3 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -2155,7 +2155,7 @@ static void VIEW2D_OT_scroller_activate(wmOperatorType *ot) static int reset_exec(bContext *C, wmOperator *UNUSED(op)) { - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; int winx, winy; diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 1c4bc33240a..cd91aa1e491 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -80,6 +80,9 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); + ED_object_sculptmode_exit(C, depsgraph); + BKE_sculpt_mask_layers_ensure(ob, NULL); Mesh *mesh = ob->data; @@ -209,6 +212,11 @@ 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); + /* Remove the Face Sets as they need to be recreated when entering Sculpt Mode in the new object. + * TODO(pablodobarro): In the future we can try to preserve them from the original mesh. */ + Mesh *new_ob_mesh = new_ob->data; + CustomData_free_layers(&new_ob_mesh->pdata, CD_SCULPT_FACE_SETS, new_ob_mesh->totpoly); + if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) { BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob); } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a4546780dd9..3a1781b941a 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3382,11 +3382,9 @@ static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op) if (use_add) { /* In add mode, we add relative shape key offset. */ - if (kb) { - const float *rco = CustomData_bmesh_get_n( - &em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative); - sub_v3_v3v3(co, co, rco); - } + const float *rco = CustomData_bmesh_get_n( + &em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative); + sub_v3_v3v3(co, co, rco); madd_v3_v3fl(eve->co, co, blend); } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index edc2f15813c..f06b6a4db2a 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -282,7 +282,9 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain, ED_object_posemode_exit_ex(bmain, ob); } } - else if ((ob->type == OB_GPENCIL) && ((ob->mode & OB_MODE_OBJECT) == 0)) { + else if (ob->type == OB_GPENCIL) { + /* Accounted for above. */ + BLI_assert((ob->mode & OB_MODE_OBJECT) == 0); if (only_test) { return true; } diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index bac40b35102..31c4f96693c 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -686,7 +686,7 @@ static int modifier_apply_obdata( } if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) { - if (!multiresModifier_reshapeFromDeformModifier(depsgraph, mmd, ob, md_eval)) { + if (!multiresModifier_reshapeFromDeformModifier(depsgraph, ob, mmd, md_eval)) { BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply"); return 0; } @@ -1375,26 +1375,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot) static int multires_subdivide_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); + Object *object = ED_object_active_context(C); MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( - op, ob, eModifierType_Multires); + op, object, eModifierType_Multires); if (!mmd) { return OPERATOR_CANCELLED; } - multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple); + multiresModifier_subdivide(object, mmd); ED_object_iter_other( - CTX_data_main(C), ob, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); + CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); - if (ob->mode & OB_MODE_SCULPT) { + if (object->mode & OB_MODE_SCULPT) { /* ensure that grid paint mask layer is created */ - BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_mask_layers_ensure(object, mmd); } return OPERATOR_FINISHED; @@ -1614,19 +1613,19 @@ void OBJECT_OT_multires_external_pack(wmOperatorType *ot) /********************* multires apply base ***********************/ static int multires_base_apply_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *ob = ED_object_active_context(C); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *object = ED_object_active_context(C); MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( - op, ob, eModifierType_Multires); + op, object, eModifierType_Multires); if (!mmd) { return OPERATOR_CANCELLED; } - multiresModifier_base_apply(mmd, scene, ob); + multiresModifier_base_apply(depsgraph, object, mmd); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index c7bba43758f..29bf9e88853 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1586,7 +1586,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE); break; case MAKE_LINKS_MODIFIERS: - BKE_object_link_modifiers(scene, ob_dst, ob_src); + BKE_object_link_modifiers(ob_dst, ob_src); DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); break; diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 8d268be5a78..631cd961e66 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -207,7 +207,6 @@ typedef enum eSymmetryAxes { typedef struct QuadriFlowJob { /* from wmJob */ struct Object *owner; - struct Main *bmain; short *stop, *do_update; float *progress; @@ -318,13 +317,13 @@ 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) +static Mesh *remesh_symmetry_bisect(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); + mesh_bisect = BKE_mesh_copy_for_eval(mesh, false); int axis; float plane_co[3], plane_no[3]; @@ -342,12 +341,12 @@ static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symme mesh_bisect = BKE_mesh_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(NULL, mesh_bisect_temp); } } } - BKE_id_free(bmain, mesh); + BKE_id_free(NULL, mesh); return mesh_bisect; } @@ -405,10 +404,10 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update /* 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); + bisect_mesh = BKE_mesh_copy_for_eval(mesh, false); /* Bisect the input mesh using the paint symmetry settings */ - bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes); + bisect_mesh = remesh_symmetry_bisect(bisect_mesh, qj->symmetry_axes); new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain( bisect_mesh, @@ -424,7 +423,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update quadriflow_update_job, (void *)qj); - BKE_id_free(qj->bmain, bisect_mesh); + BKE_id_free(NULL, bisect_mesh); if (new_mesh == NULL) { *do_update = true; @@ -501,7 +500,6 @@ 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"); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index cff7052ca58..a083675ca01 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2351,7 +2351,7 @@ static void ed_panel_draw(const bContext *C, int em, bool vertical) { - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); /* draw panel */ uiBlock *block = UI_block_begin(C, region, pt->idname, UI_EMBOSS); @@ -2734,7 +2734,7 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *region) void ED_region_header_layout(const bContext *C, ARegion *region) { - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); uiBlock *block; uiLayout *layout; HeaderType *ht; @@ -2960,7 +2960,7 @@ void ED_region_info_draw_multiline(ARegion *region, const bool full_redraw) { const int header_height = UI_UNIT_Y; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); int fontid = style->widget.uifont_id; int scissor[4]; int num_lines = 0; @@ -3175,7 +3175,6 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const ctx.fontid = fontid; ctx.xmin = xmin; ctx.ymin = ymin; - ctx.vertical_offset = vertical_offset; ctx.current_y = ofs_y; ctx.vertical_offset = vertical_offset; IMB_metadata_foreach(ibuf, metadata_custom_draw_fields, &ctx); @@ -3266,7 +3265,7 @@ void ED_region_image_metadata_draw( { float box_y; rctf rect; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); if (!ibuf->metadata) { return; @@ -3521,7 +3520,7 @@ void ED_region_cache_draw_background(ARegion *region) void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y) { - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); int fontid = style->widget.uifont_id; char numstr[32]; float font_dims[2] = {0.0f, 0.0f}; diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c index f8a6b301911..2cccd9a2ba5 100644 --- a/source/blender/editors/screen/area_query.c +++ b/source/blender/editors/screen/area_query.c @@ -61,6 +61,18 @@ bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]) ED_region_overlap_isect_y(region, event_xy[1])); } +bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]) +{ + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (ED_region_is_overlap(area->spacetype, region->regiontype)) { + if (ED_region_overlap_isect_xy(region, event_xy)) { + return true; + } + } + } + return false; +} + bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar_gutter) { *r_ar_gutter = region->winrct; diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index f497b80e0f4..de9e70f8e06 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -59,8 +59,8 @@ set(SRC paint_vertex_weight_ops.c paint_vertex_weight_utils.c sculpt.c - sculpt_multiplane_scrape.c sculpt_cloth.c + sculpt_multiplane_scrape.c sculpt_pose.c sculpt_undo.c sculpt_uv.c diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5a830a90092..79c4becd405 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -356,9 +356,6 @@ static void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_se if (ss->face_sets[vert_map->indices[j]] > 0) { ss->face_sets[vert_map->indices[j]] = abs(face_set); } - else { - ss->face_sets[vert_map->indices[j]] = -abs(face_set); - } } } break; case PBVH_BMESH: @@ -628,6 +625,10 @@ static bool sculpt_vertex_is_boundary(SculptSession *ss, const int index) return false; } + if (!SCULPT_vertex_all_face_sets_visible_get(ss, index)) { + return false; + } + for (int i = 0; i < vert_map->count; i++) { const MPoly *p = &ss->mpoly[vert_map->indices[i]]; unsigned f_adj_v[2]; @@ -836,7 +837,7 @@ void SCULPT_floodfill_execute( sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni) { const int to_v = ni.index; - if (flood->visited_vertices[to_v] == 0) { + if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) { flood->visited_vertices[to_v] = 1; if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { @@ -1633,17 +1634,11 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a #define EDGE_DISTANCE_INF -1 -static float *sculpt_boundary_edges_automasking_init(Sculpt *sd, - Object *ob, +static float *sculpt_boundary_edges_automasking_init(Object *ob, + int propagation_steps, float *automask_factor) { SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - const int propagation_steps = brush->automasking_boundary_edges_propagation_steps; - - if (!sculpt_automasking_enabled(ss, brush)) { - return NULL; - } if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { BLI_assert(!"Boundary Edges masking: pmap missing"); @@ -1693,6 +1688,10 @@ static void sculpt_automasking_init(Sculpt *sd, Object *ob) Brush *brush = BKE_paint_brush(&sd->paint); const int totvert = SCULPT_vertex_count_get(ss); + if (!sculpt_automasking_enabled(ss, brush)) { + return; + } + ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss), "automask_factor"); @@ -1711,7 +1710,8 @@ static void sculpt_automasking_init(Sculpt *sd, Object *ob) if (brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { SCULPT_vertex_random_access_init(ss); - sculpt_boundary_edges_automasking_init(sd, ob, ss->cache->automask); + sculpt_boundary_edges_automasking_init( + ob, brush->automasking_boundary_edges_propagation_steps, ss->cache->automask); } } @@ -3401,7 +3401,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.index, tls->thread_id); - if (fade > 0.05f && SCULPT_vertex_all_face_sets_visible_get(ss, vd.index)) { + if (fade > 0.05f) { SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set); } } @@ -3662,6 +3662,10 @@ void SCULPT_relax_vertex(SculptSession *ss, if (count > 0) { mul_v3_fl(smooth_pos, 1.0f / (float)count); } + else { + copy_v3_v3(r_final_pos, vd->co); + return; + } float plane[4]; float smooth_closest_plane[3]; @@ -3672,6 +3676,12 @@ void SCULPT_relax_vertex(SculptSession *ss, else { copy_v3_v3(vno, vd->fno); } + + if (is_zero_v3(vno)) { + copy_v3_v3(r_final_pos, vd->co); + return; + } + plane_from_point_normal_v3(plane, vd->co, vno); closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos); sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co); @@ -9143,6 +9153,10 @@ static void sculpt_filter_cache_free(SculptSession *ss) if (ss->filter_cache->prev_face_set) { MEM_freeN(ss->filter_cache->prev_face_set); } + if (ss->filter_cache->automask) { + MEM_freeN(ss->filter_cache->automask); + } + MEM_freeN(ss->filter_cache); ss->filter_cache = NULL; } @@ -9310,7 +9324,8 @@ static void mesh_filter_task_cb(void *__restrict userdata, break; } case MESH_FILTER_RELAX: { - SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), false, val); + SCULPT_relax_vertex( + ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val); sub_v3_v3v3(disp, val, vd.co); break; } @@ -9443,6 +9458,16 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y; ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z; + if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) { + const int totvert = SCULPT_vertex_count_get(ss); + ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float), + "Relax filter edge automask"); + for (int i = 0; i < totvert; i++) { + ss->filter_cache->automask[i] = 1.0f; + } + sculpt_boundary_edges_automasking_init(ob, 1, ss->filter_cache->automask); + } + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -10844,7 +10869,7 @@ static int sculpt_face_set_create_invoke(bContext *C, wmOperator *op, const wmEv if (mode == SCULPT_FACE_SET_VISIBLE) { for (int i = 0; i < tot_vert; i++) { - if (SCULPT_vertex_visible_get(ss, i) && SCULPT_vertex_all_face_sets_visible_get(ss, i)) { + if (SCULPT_vertex_visible_get(ss, i)) { SCULPT_vertex_face_set_set(ss, i, next_face_set); } } @@ -11017,6 +11042,18 @@ static int sculpt_face_sets_change_visibility_invoke(bContext *C, SCULPT_face_sets_visibility_invert(ss); } + /* For modes that use the cursor active vertex, update the rotation origin for viewport + * navigation. */ + if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + float location[3]; + copy_v3_v3(location, SCULPT_active_vertex_co_get(ss)); + mul_m4_v3(ob->obmat, location); + copy_v3_v3(ups->average_stroke_accum, location); + ups->average_stroke_counter = 1; + ups->last_stroke_valid = true; + } + /* Sync face sets visibility and vertex visibility. */ SCULPT_visibility_sync_all_face_sets_to_vertices(ss); @@ -11084,12 +11121,13 @@ static int sculpt_face_sets_randomize_colors_invoke(bContext *C, int totnode; Mesh *mesh = ob->data; - int new_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX); - mesh->face_sets_color_seed = new_seed; + mesh->face_sets_color_seed += 1; if (ss->face_sets) { - mesh->face_sets_color_default = ss->face_sets[0]; + const int random_index = clamp_i( + ss->totpoly * BLI_hash_int_01(mesh->face_sets_color_seed), 0, max_ii(0, ss->totpoly - 1)); + mesh->face_sets_color_default = ss->face_sets[random_index]; } - BKE_pbvh_face_sets_color_set(pbvh, new_seed, mesh->face_sets_color_default); + BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); for (int i = 0; i < totnode; i++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 7f90f86edd4..4e36ae7aa5e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -663,6 +663,9 @@ typedef struct FilterCache { float *prev_mask; float mask_expand_initial_co[3]; + /* Used to prevent undesired results on certain mesh filters. */ + float *automask; + int new_face_set; int *prev_face_set; diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index 34b4967beaf..6b9d3fd054a 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -259,8 +259,6 @@ typedef struct { MovieTrackingTrack *track; MovieTrackingMarker *marker; - /** current frame number */ - int framenr; /** position of marker in pixel coords */ float marker_pos[2]; /** position and dimensions of marker pattern in pixel coords */ @@ -283,14 +281,12 @@ static void to_pixel_space(float r[2], float a[2], int width, int height) static void marker_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) { MarkerUpdateCb *cb = (MarkerUpdateCb *)arg_cb; - MovieTrackingMarker *marker; if (!cb->compact) { return; } - marker = BKE_tracking_marker_ensure(cb->track, cb->framenr); - + MovieTrackingMarker *marker = cb->marker; marker->flag = cb->marker_flag; WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); @@ -299,14 +295,12 @@ static void marker_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) static void marker_block_handler(bContext *C, void *arg_cb, int event) { MarkerUpdateCb *cb = (MarkerUpdateCb *)arg_cb; - MovieTrackingMarker *marker; int width, height; bool ok = false; BKE_movieclip_get_size(cb->clip, cb->user, &width, &height); - marker = BKE_tracking_marker_ensure(cb->track, cb->framenr); - + MovieTrackingMarker *marker = cb->marker; if (event == B_MARKER_POS) { marker->pos[0] = cb->marker_pos[0] / width; marker->pos[1] = cb->marker_pos[1] / height; @@ -452,7 +446,8 @@ void uiTemplateMarker(uiLayout *layout, user = userptr->data; track = trackptr->data; - marker = BKE_tracking_marker_get(track, user->framenr); + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + marker = BKE_tracking_marker_get(track, clip_framenr); cb = MEM_callocN(sizeof(MarkerUpdateCb), "uiTemplateMarker update_cb"); cb->compact = compact; @@ -461,7 +456,6 @@ void uiTemplateMarker(uiLayout *layout, cb->track = track; cb->marker = marker; cb->marker_flag = marker->flag; - cb->framenr = user->framenr; if (compact) { block = uiLayoutGetBlock(layout); diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c index e5c82a4a80e..72c140011a9 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_draw.c +++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c @@ -296,7 +296,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region) SpaceClip *sc = CTX_wm_space_clip(C); View2D *v2d = ®ion->v2d; MovieClip *clip = ED_space_clip_get_clip(sc); - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); int fontid = style->widget.uifont_id; if (!clip) { diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 1332eb51baa..d7682a41570 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -170,7 +170,6 @@ static void file_draw_string(int sx, eFontStyle_Align align, const uchar col[4]) { - uiStyle *style; uiFontStyle fs; rcti rect; char fname[FILE_MAXFILE]; @@ -179,7 +178,7 @@ static void file_draw_string(int sx, return; } - style = UI_style_get(); + const uiStyle *style = UI_style_get(); fs = style->widgetlabel; BLI_strncpy(fname, string, FILE_MAXFILE); @@ -382,7 +381,6 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) char filename[FILE_MAX + 12]; wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - ScrArea *sa = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); BLI_join_dirfile(orgname, sizeof(orgname), sfile->params->dir, oldname); @@ -410,7 +408,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) } /* to make sure we show what is on disk */ - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); } ED_region_tag_redraw(region); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d72bc31e656..169abfb9a10 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1649,10 +1649,9 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); struct FSMenu *fsmenu = ED_fsmenu_get(); - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); /* refresh system directory menu */ fsmenu_refresh_system_category(fsmenu); @@ -1988,7 +1987,6 @@ int file_directory_new_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); const bool do_diropen = RNA_boolean_get(op->ptr, "open"); if (!sfile->params) { @@ -2047,13 +2045,13 @@ int file_directory_new_exec(bContext *C, wmOperator *op) /* set timer to smoothly view newly generated file */ /* max 30 frs/sec */ if (sfile->smoothscroll_timer != NULL) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + WM_event_remove_timer(wm, CTX_wm_window(C), sfile->smoothscroll_timer); } sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0); sfile->scroll_offset = 0; /* reload dir to make sure we're seeing what's in the directory */ - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); if (do_diropen) { BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); @@ -2302,11 +2300,10 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused)) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); if (sfile->params) { sfile->params->flag ^= FILE_HIDE_DOT; - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -2491,7 +2488,6 @@ int file_delete_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); int numfiles = filelist_files_ensure(sfile->files); const char *error_message = NULL; @@ -2520,7 +2516,7 @@ int file_delete_exec(bContext *C, wmOperator *op) } } - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 903698b1ace..188f3417ddc 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -268,6 +268,12 @@ typedef struct FileListEntryPreview { ImBuf *img; } FileListEntryPreview; +/* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing + * tasks' data (see T74609). */ +typedef struct FileListEntryPreviewTaskData { + FileListEntryPreview *preview; +} FileListEntryPreviewTaskData; + typedef struct FileListFilter { uint64_t filter; uint64_t filter_id; @@ -1254,7 +1260,8 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, int UNUSED(threadid)) { FileListEntryCache *cache = BLI_task_pool_userdata(pool); - FileListEntryPreview *preview = taskdata; + FileListEntryPreviewTaskData *preview_taskdata = taskdata; + FileListEntryPreview *preview = preview_taskdata->preview; ThumbSource source = 0; @@ -1283,10 +1290,8 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); IMB_thumb_path_unlock(preview->path); - /* Used to tell free func to not free anything. - * Note that we do not care about cas result here, - * we only want value attribution itself to be atomic (and memory barier).*/ - atomic_cas_uint32(&preview->flags, preview->flags, 0); + /* That way task freeing function won't free th preview, since it does not own it anymore. */ + atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); BLI_thread_queue_push(cache->previews_done, preview); // printf("%s: End (%d)...\n", __func__, threadid); @@ -1296,16 +1301,18 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) { - FileListEntryPreview *preview = taskdata; + FileListEntryPreviewTaskData *preview_taskdata = taskdata; + FileListEntryPreview *preview = preview_taskdata->preview; - /* If preview->flag is empty, it means that preview has already been generated and - * added to done queue, we do not own it anymore. */ - if (preview->flags) { + /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent + * to previews_done queue. */ + if (preview != NULL) { if (preview->img) { IMB_freeImBuf(preview->img); } MEM_freeN(preview); } + MEM_freeN(preview_taskdata); } static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) @@ -1322,11 +1329,10 @@ static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) static void filelist_cache_previews_clear(FileListEntryCache *cache) { - FileListEntryPreview *preview; - if (cache->previews_pool) { BLI_task_pool_cancel(cache->previews_pool); + FileListEntryPreview *preview; while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, // preview->img); @@ -1374,9 +1380,13 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); filelist_cache_preview_ensure_running(cache); + + FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), + __func__); + preview_taskdata->preview = preview; BLI_task_pool_push_ex(cache->previews_pool, filelist_cache_preview_runf, - preview, + preview_taskdata, true, filelist_cache_preview_freef, TASK_PRIORITY_LOW); @@ -3057,12 +3067,12 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) WM_jobs_start(CTX_wm_manager(C), wm_job); } -void filelist_readjob_stop(wmWindowManager *wm, ScrArea *sa) +void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene) { - WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_kill_type(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR); } -int filelist_readjob_running(wmWindowManager *wm, ScrArea *sa) +int filelist_readjob_running(wmWindowManager *wm, Scene *owner_scene) { - return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + return WM_jobs_test(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR); } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 654a86b1702..e39594bf1da 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -129,8 +129,8 @@ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group); void filelist_freelib(struct FileList *filelist); void filelist_readjob_start(struct FileList *filelist, const struct bContext *C); -void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa); -int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa); +void filelist_readjob_stop(struct wmWindowManager *wm, struct Scene *owner_scene); +int filelist_readjob_running(struct wmWindowManager *wm, struct Scene *owner_scene); bool filelist_cache_previews_update(struct FileList *filelist); void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index c0b859122a8..d07db12eeac 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -639,7 +639,7 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, float file_string_width(const char *str) { - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); float width; UI_fontstyle_set(&style->widget); @@ -661,12 +661,12 @@ float file_font_pointsize(void) #if 0 float s; char tmp[2] = "X"; - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); UI_fontstyle_set(&style->widget); s = BLF_height(style->widget.uifont_id, tmp); return style->widget.points; #else - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); UI_fontstyle_set(&style->widget); return style->widget.points * UI_DPI_FAC; #endif @@ -829,10 +829,9 @@ void ED_file_change_dir(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); if (sfile->params) { - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, CTX_data_scene(C), sfile); /* Clear search string, it is very rare to want to keep that filter while changing dir, * and usually very annoying to keep it actually! */ @@ -951,11 +950,11 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v)) return match; } -void ED_fileselect_clear(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) +void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile) { /* only NULL in rare cases - [#29734] */ if (sfile->files) { - filelist_readjob_stop(wm, sa); + filelist_readjob_stop(wm, owner_scene); filelist_freelib(sfile->files); filelist_clear(sfile->files); } @@ -964,7 +963,7 @@ void ED_fileselect_clear(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } -void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) +void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile) { if (!sfile) { return; @@ -990,7 +989,7 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) folderlist_free(sfile->folders_next); if (sfile->files) { - ED_fileselect_clear(wm, sa, sfile); + ED_fileselect_clear(wm, owner_scene, sfile); filelist_free(sfile->files); MEM_freeN(sfile->files); sfile->files = NULL; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 11d759b5b75..50ee64da9c8 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -191,7 +191,7 @@ static void file_exit(wmWindowManager *wm, ScrArea *sa) sfile->previews_timer = NULL; } - ED_fileselect_exit(wm, sa, sfile); + ED_fileselect_exit(wm, NULL, sfile); } static SpaceLink *file_duplicate(SpaceLink *sl) @@ -301,7 +301,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir); if (filelist_force_reset(sfile->files)) { - filelist_readjob_stop(wm, sa); + filelist_readjob_stop(wm, CTX_data_scene(C)); filelist_clear(sfile->files); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 34ff61749b2..c62fd53431b 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2351,7 +2351,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) else { BKE_reportf(reports, RPT_WARNING, - "Packed library image: %s from library %s can't be saved", + "Packed library image can't be saved: \"%s\" from \"%s\"", ima->id.name + 2, ima->id.lib->name); } @@ -2359,7 +2359,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) else if (!is_format_writable) { BKE_reportf(reports, RPT_WARNING, - "Image %s can't be saved automatically, must use a different file format", + "Image can't be saved, use a different file format: \"%s\"", ima->id.name + 2); } else { @@ -2368,7 +2368,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) if (BLI_gset_haskey(unique_paths, ima->name)) { BKE_reportf(reports, RPT_WARNING, - "File path used by more than one saved image: %s", + "Multiple images can't be saved to an identical path: \"%s\"", ima->name); } else { @@ -2376,11 +2376,8 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports) } } else { - BKE_reportf(reports, - RPT_WARNING, - "Image %s can't be saved, no valid file path: %s", - ima->id.name + 2, - ima->name); + BKE_reportf( + reports, RPT_WARNING, "Image can't be saved, no valid file path: \"%s\"", ima->name); } } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index dc546e5baf5..42a8a746eef 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -262,18 +262,22 @@ static void image_keymap(struct wmKeyConfig *keyconf) } /* dropboxes */ -static bool image_drop_poll(bContext *UNUSED(C), +static bool image_drop_poll(bContext *C, wmDrag *drag, - const wmEvent *UNUSED(event), + const wmEvent *event, const char **UNUSED(tooltip)) { + ScrArea *area = CTX_wm_area(C); + if (ED_region_overlap_isect_any_xy(area, &event->x)) { + return false; + } if (drag->type == WM_DRAG_PATH) { /* rule might not work? */ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { - return 1; + return true; } } - return 0; + return false; } static void image_drop_copy(wmDrag *drag, wmDropBox *drop) diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 0a5ca81484c..60170276a16 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -53,7 +53,7 @@ static enum eTextViewContext_LineFlag report_line_data(TextViewContext *tvc, /* Zebra striping for background. */ int bg_id = (report->flag & SELECT) ? TH_INFO_SELECTED : TH_BACK; - int shade = tvc->iter_tmp % 2 ? 4 : -4; + int shade = (tvc->iter_tmp % 2) ? 4 : -4; UI_GetThemeColorShade4ubv(bg_id, shade, bg); /* Icon color and backgound depend of report type. */ @@ -61,7 +61,10 @@ static enum eTextViewContext_LineFlag report_line_data(TextViewContext *tvc, int icon_fg_id; int icon_bg_id; - if (report->type & RPT_ERROR_ALL) { + if (tvc->iter_char_begin != 0) { + *r_icon = ICON_NONE; + } + else if (report->type & RPT_ERROR_ALL) { icon_fg_id = TH_INFO_ERROR_TEXT; icon_bg_id = TH_INFO_ERROR; *r_icon = ICON_CANCEL; @@ -115,14 +118,13 @@ static void report_textview_init__internal(TextViewContext *tvc) { const Report *report = tvc->iter; const char *str = report->message; - const char *next_str = strchr(str + tvc->iter_char, '\n'); - - if (next_str) { - tvc->iter_char_next = (int)(next_str - str); - } - else { - tvc->iter_char_next = report->len; + for (int i = tvc->iter_char_end - 1; i >= 0; i -= 1) { + if (str[i] == '\n') { + tvc->iter_char_begin = i + 1; + return; + } } + tvc->iter_char_begin = 0; } static int report_textview_skip__internal(TextViewContext *tvc) @@ -152,7 +154,8 @@ static int report_textview_begin(TextViewContext *tvc) tvc->iter_tmp = 0; if (tvc->iter && report_textview_skip__internal(tvc)) { /* init the newline iterator */ - tvc->iter_char = 0; + const Report *report = tvc->iter; + tvc->iter_char_end = report->len; report_textview_init__internal(tvc); return true; @@ -172,12 +175,13 @@ static int report_textview_step(TextViewContext *tvc) /* simple case, but no newline support */ const Report *report = tvc->iter; - if (report->len <= tvc->iter_char_next) { + if (tvc->iter_char_begin <= 0) { tvc->iter = (void *)((Link *)tvc->iter)->prev; if (tvc->iter && report_textview_skip__internal(tvc)) { tvc->iter_tmp++; - tvc->iter_char = 0; /* reset start */ + report = tvc->iter; + tvc->iter_char_end = report->len; /* reset start */ report_textview_init__internal(tvc); return true; @@ -188,7 +192,7 @@ static int report_textview_step(TextViewContext *tvc) } else { /* step to the next newline */ - tvc->iter_char = tvc->iter_char_next + 1; + tvc->iter_char_end = tvc->iter_char_begin - 1; report_textview_init__internal(tvc); return true; @@ -198,8 +202,8 @@ static int report_textview_step(TextViewContext *tvc) static void report_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len) { const Report *report = tvc->iter; - *r_line = report->message + tvc->iter_char; - *r_len = tvc->iter_char_next - tvc->iter_char; + *r_line = report->message + tvc->iter_char_begin; + *r_len = tvc->iter_char_end - tvc->iter_char_begin; } static void info_textview_draw_rect_calc(const ARegion *region, diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 54b7c477791..8eef4ef5d56 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -65,10 +65,10 @@ typedef struct TextViewContext { void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); const void *iter; int iter_index; - /** Char index, used for multi-line report display. */ - int iter_char; - /** Same as 'iter_char', next new-line. */ - int iter_char_next; + /** Used for internal multi-line iteration. */ + int iter_char_begin; + /** The last character (not inclusive). */ + int iter_char_end; /** Internal iterator use. */ int iter_tmp; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 905e3eddc97..56176c1cb92 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -604,7 +604,7 @@ static void nla_draw_strip_text(AnimData *adt, (nlt->flag & NLATRACK_SOLO) == 0); char str[256]; size_t str_len; - char col[4]; + uchar col[4]; /* just print the name and the range */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { @@ -652,7 +652,7 @@ static void nla_draw_strip_frames_text( NlaTrack *UNUSED(nlt), NlaStrip *strip, View2D *v2d, float UNUSED(yminc), float ymaxc) { const float ytol = 1.0f; /* small offset to vertical positioning of text, for legibility */ - const char col[4] = {220, 220, 220, 255}; /* light gray */ + const uchar col[4] = {220, 220, 220, 255}; /* light gray */ char numstr[32]; size_t numstr_len; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 025de1c898c..f679bcc4e15 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2450,7 +2450,7 @@ void NODE_OT_tree_socket_move(wmOperatorType *ot) static bool node_shader_script_update_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - RenderEngineType *type = RE_engines_find(scene->r.engine); + const RenderEngineType *type = RE_engines_find(scene->r.engine); SpaceNode *snode = CTX_wm_space_node(C); bNode *node; Text *text; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 3e88a7a7b88..1b34f85f800 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2252,9 +2252,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eGpencilModifierType_Armature: data.icon = ICON_MOD_ARMATURE; break; - case eGpencilModifierType_Vertexcolor: - data.icon = ICON_MOD_NORMALEDIT; - break; /* Default */ default: diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 4cd93b5d257..a99e1b63119 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -678,8 +678,8 @@ static void object_delete_cb(bContext *C, return; } - // check also library later - if ((ob->mode && OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) { + /* Check also library later. */ + if ((ob->mode & OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) { ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); } BKE_id_delete(bmain, ob); diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index b9e97a19b82..d2f2411c538 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -67,12 +67,12 @@ void SCRIPT_OT_python_file_run(wmOperatorType *ot) ot->name = "Run Python File"; ot->description = "Run Python file"; ot->idname = "SCRIPT_OT_python_file_run"; - ot->flag = OPTYPE_UNDO; /* api callbacks */ ot->exec = run_pyfile_exec; ot->poll = ED_operator_areaactive; + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "Path", ""); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index ef192f6c9db..864e518f182 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -542,7 +542,7 @@ static void draw_seq_handle(View2D *v2d, } if ((G.moving & G_TRANSFORM_SEQ) || (seq->flag & whichsel)) { - const char col[4] = {255, 255, 255, 255}; + const uchar col[4] = {255, 255, 255, 255}; char numstr[32]; size_t numstr_len; @@ -574,7 +574,7 @@ static void draw_seq_text(View2D *v2d, char str[32 + FILE_MAX]; size_t str_len; const char *name = seq->name + 2; - char col[4]; + uchar col[4]; /* note, all strings should include 'name' */ if (name[0] == '\0') { diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 48c522c5e1b..1e628bbc39b 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -291,7 +291,7 @@ static int txtfmt_py_literal_numeral(const char *string, char prev_fmt) } /* Previous was a number; if immediately followed by '.' it's a floating point decimal number. * Note: keep the decimal point, it's needed to allow leading zeros. */ - if ((prev_fmt == FMT_TYPE_NUMERAL) && (first == '.')) { + if (first == '.') { return txtfmt_py_find_numeral_inner(string); } /* "Imaginary" part of a complex number ends with 'j' */ diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 8ec7d5a166b..020c58270fc 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -436,35 +436,50 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *region) ED_view3d_stop_render_preview(wm, region); } -static bool view3d_ob_drop_poll(bContext *UNUSED(C), +static bool view3d_drop_id_in_main_region_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + ID_Type id_type) +{ + ScrArea *area = CTX_wm_area(C); + if (ED_region_overlap_isect_any_xy(area, &event->x)) { + return false; + } + return WM_drag_ID(drag, id_type) != NULL; +} + +static bool view3d_ob_drop_poll(bContext *C, wmDrag *drag, - const wmEvent *UNUSED(event), + const wmEvent *event, const char **UNUSED(tooltip)) { - return WM_drag_ID(drag, ID_OB) != NULL; + return view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB); } -static bool view3d_collection_drop_poll(bContext *UNUSED(C), +static bool view3d_collection_drop_poll(bContext *C, wmDrag *drag, - const wmEvent *UNUSED(event), + const wmEvent *event, const char **UNUSED(tooltip)) { - return WM_drag_ID(drag, ID_GR) != NULL; + return view3d_drop_id_in_main_region_poll(C, drag, event, ID_GR); } -static bool view3d_mat_drop_poll(bContext *UNUSED(C), +static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, - const wmEvent *UNUSED(event), + const wmEvent *event, const char **UNUSED(tooltip)) { - return WM_drag_ID(drag, ID_MA) != NULL; + return view3d_drop_id_in_main_region_poll(C, drag, event, ID_MA); } -static bool view3d_ima_drop_poll(bContext *UNUSED(C), +static bool view3d_ima_drop_poll(bContext *C, wmDrag *drag, - const wmEvent *UNUSED(event), + const wmEvent *event, const char **UNUSED(tooltip)) { + if (ED_region_overlap_isect_any_xy(CTX_wm_area(C), &event->x)) { + return false; + } if (drag->type == WM_DRAG_PATH) { /* rule might not work? */ return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 260546738f4..d812ed530ce 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -101,7 +101,7 @@ typedef struct View3DCameraControl { void *obtfm; } View3DCameraControl; -BLI_INLINE Object *view3d_cameracontrol_object(View3DCameraControl *vctrl) +BLI_INLINE Object *view3d_cameracontrol_object(const View3DCameraControl *vctrl) { return vctrl->root_parent ? vctrl->root_parent : vctrl->ctx_v3d->camera; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 087fce9e4fd..dbbbbc2af54 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -109,7 +109,7 @@ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore */ void ED_view3d_update_viewmat(Depsgraph *depsgraph, - Scene *scene, + const Scene *scene, View3D *v3d, ARegion *region, float viewmat[4][4], @@ -208,7 +208,7 @@ static void view3d_main_region_setup_view(Depsgraph *depsgraph, } static void view3d_main_region_setup_offscreen(Depsgraph *depsgraph, - Scene *scene, + const Scene *scene, View3D *v3d, ARegion *region, float viewmat[4][4], @@ -222,7 +222,10 @@ static void view3d_main_region_setup_offscreen(Depsgraph *depsgraph, GPU_matrix_set(rv3d->viewmat); } -static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d) +static bool view3d_stereo3d_active(wmWindow *win, + const Scene *scene, + View3D *v3d, + RegionView3D *rv3d) { if ((scene->r.scemode & R_MULTIVIEW) == 0) { return false; @@ -842,7 +845,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *region, View3D *v3d, bo /* ******************** other elements ***************** */ /** could move this elsewhere, but tied into #ED_view3d_grid_scale */ -float ED_scene_grid_scale(Scene *scene, const char **grid_unit) +float ED_scene_grid_scale(const Scene *scene, const char **grid_unit) { /* apply units */ if (scene->unit.system) { @@ -863,13 +866,13 @@ float ED_scene_grid_scale(Scene *scene, const char **grid_unit) return 1.0f; } -float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) +float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **grid_unit) { return v3d->grid * ED_scene_grid_scale(scene, grid_unit); } #define STEPS_LEN 8 -void ED_view3d_grid_steps(Scene *scene, +void ED_view3d_grid_steps(const Scene *scene, View3D *v3d, RegionView3D *rv3d, float r_grid_steps[STEPS_LEN]) @@ -1562,7 +1565,7 @@ static void view3d_draw_view(const bContext *C, ARegion *region) DRW_draw_view(C); } -RenderEngineType *ED_view3d_engine_type(Scene *scene, int drawtype) +RenderEngineType *ED_view3d_engine_type(const Scene *scene, int drawtype) { /* * Temporary viewport draw modes until we have a proper system. @@ -1606,7 +1609,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) * \{ */ static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph, - Scene *scene, + const Scene *scene, View3D *v3d, ARegion *region, float winmat[4][4], @@ -1630,7 +1633,7 @@ static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph, } void ED_view3d_draw_offscreen(Depsgraph *depsgraph, - Scene *scene, + const Scene *scene, eDrawType drawtype, View3D *v3d, ARegion *region, @@ -2395,7 +2398,7 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto * \note The info that this uses is updated in #ED_refresh_viewport_fps, * which currently gets called during #SCREEN_OT_animation_step. */ -void ED_scene_draw_fps(Scene *scene, int xoffset, int *yoffset) +void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset) { ScreenFrameRateInfo *fpsi = scene->fps_info; char printable[16]; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 2ced545a108..610c40c37eb 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -202,7 +202,7 @@ void view3d_winmatrix_set(struct Depsgraph *depsgraph, const View3D *v3d, const rcti *rect); void view3d_viewmatrix_set(struct Depsgraph *depsgraph, - Scene *scene, + const struct Scene *scene, const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index f6ec5c93e7f..e7153ddd361 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -586,8 +586,11 @@ bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionV } } -bool ED_view3d_camera_autokey( - Scene *scene, ID *id_key, struct bContext *C, const bool do_rotate, const bool do_translate) +bool ED_view3d_camera_autokey(const Scene *scene, + ID *id_key, + struct bContext *C, + const bool do_rotate, + const bool do_translate) { if (autokeyframe_cfra_can_key(scene, id_key)) { const float cfra = (float)CFRA; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 9b0c987c451..ee41b73ed16 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -807,7 +807,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) * \note don't set windows active in here, is used by renderwin too. */ void view3d_viewmatrix_set(Depsgraph *depsgraph, - Scene *scene, + const Scene *scene, const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]) diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 5f5a173932c..afa7b02a1f6 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -65,8 +65,6 @@ set(SRC transform_gizmo_3d.c transform_gizmo_extrude_3d.c transform_input.c - transform_ops.c - transform_orientations.c transform_mode.c transform_mode_align.c transform_mode_baketime.c @@ -98,6 +96,8 @@ set(SRC transform_mode_trackball.c transform_mode_translate.c transform_mode_vert_slide.c + transform_ops.c + transform_orientations.c transform_snap.c transform_snap_object.c diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index f93a3ec260b..4ccb97b7a00 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -830,25 +830,6 @@ bool FrameOnMouseSide(char side, float frame, float cframe) /* ********************* ACTION EDITOR ****************** */ -static int gpf_cmp_frame(void *thunk, const void *a, const void *b) -{ - const bGPDframe *frame_a = a; - const bGPDframe *frame_b = b; - - if (frame_a->framenum < frame_b->framenum) { - return -1; - } - if (frame_a->framenum > frame_b->framenum) { - return 1; - } - *((bool *)thunk) = true; - /* selected last */ - if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) { - return 1; - } - return 0; -} - static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b) { const MaskLayerShape *frame_a = a; @@ -881,7 +862,7 @@ static void posttrans_gpd_clean(bGPdata *gpd) bGPDframe *gpf, *gpfn; bool is_double = false; - BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double); + BKE_gpencil_layer_frames_sort(gpl, &is_double); if (is_double) { for (gpf = gpl->frames.first; gpf; gpf = gpfn) { diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index a8a930cc156..6180f6d3477 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -27,9 +27,9 @@ struct AnimData; struct LinkNode; -struct TransInfo; -struct TransDataContainer; struct TransData; +struct TransDataContainer; +struct TransInfo; struct wmOperator; /* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 41bb51340fc..4623cc61d29 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3048,7 +3048,6 @@ static void UV_OT_select_linked(wmOperatorType *ot) ot->name = "Select Linked"; ot->description = "Select all UV vertices linked to the active UV map"; ot->idname = "UV_OT_select_linked"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* api callbacks */ ot->exec = uv_select_linked_exec; @@ -3485,6 +3484,10 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, /** \} */ +#define UV_SELECT_ISLAND_LIMIT \ + float limit[2]; \ + uvedit_pixel_to_float(sima, limit, 0.05f) + /* -------------------------------------------------------------------- */ /** \name Box Select Operator * \{ */ @@ -3518,6 +3521,8 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) pinned = RNA_boolean_get(op->ptr, "pinned"); + UV_SELECT_ISLAND_LIMIT; + bool changed_multi = false; uint objects_len = 0; @@ -3569,24 +3574,34 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { continue; } + bool has_selected = false; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { - - /* UV_SYNC_SELECTION - can't do pinned selection */ - if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { + /* UV_SYNC_SELECTION - can't do pinned selection */ + if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } } - } - else if (pinned) { - if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + else if (pinned) { + if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } } if (sima->sticky == SI_STICKY_VERTEX) { @@ -3681,6 +3696,8 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); + UV_SELECT_ISLAND_LIMIT; + bool changed_multi = false; uint objects_len = 0; @@ -3728,14 +3745,29 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + bool has_selected = false; BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_inside_circle(luv->uv, offset, ellipse)) { - changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_inside_circle(luv->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } } } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } } if (sima->sticky == SI_STICKY_VERTEX) { @@ -3809,6 +3841,8 @@ static bool do_lasso_select_mesh_uv(bContext *C, bool changed_multi = false; rcti rect; + UV_SELECT_ISLAND_LIMIT; + BLI_lasso_boundbox(&rect, mcords, moves); uint objects_len = 0; @@ -3857,22 +3891,33 @@ static bool do_lasso_select_mesh_uv(bContext *C, BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip( - ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - changed = true; - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (UI_view2d_view_to_region_clip( + ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && + BLI_rcti_isect_pt_v(&rect, screen_uv) && + BLI_lasso_is_point_inside( + mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; } } } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, ima, objects, objects_len, limit, &hit, true, !select, false, false); + } } if (sima->sticky == SI_STICKY_VERTEX) { diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h index 86bb696a031..544fdee519f 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h +++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h @@ -35,7 +35,7 @@ class CalligraphicShader : public StrokeShader { public: /*! Builds the shader. * \param iMinThickness: - * The minimum thickness in the direction perpandicular to the main direction. + * The minimum thickness in the direction perpendicular to the main direction. * \param iMaxThickness: * The maximum thickness in the main direction. * \param iOrientation: diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 709674e6b43..87743911add 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -59,7 +59,6 @@ set(SRC intern/MOD_gpencilthick.c intern/MOD_gpenciltime.c intern/MOD_gpenciltint.c - intern/MOD_gpencilvertexcolor.c MOD_gpencil_modifiertypes.h ) diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h index b8e8e8fc87f..f5c064c1c07 100644 --- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h +++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h @@ -43,7 +43,6 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Offset; extern GpencilModifierTypeInfo modifierType_Gpencil_Armature; extern GpencilModifierTypeInfo modifierType_Gpencil_Time; extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply; -extern GpencilModifierTypeInfo modifierType_Gpencil_Vertexcolor; /* MOD_gpencil_util.c */ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 1462b6f72c9..6c3815d7c0e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -72,7 +72,6 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) INIT_GP_TYPE(Armature); INIT_GP_TYPE(Time); INIT_GP_TYPE(Multiply); - INIT_GP_TYPE(Vertexcolor); #undef INIT_GP_TYPE } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 9b3d37bf11f..b8009b8405e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -55,7 +55,6 @@ static void initData(GpencilModifierData *md) { NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; gpmd->pass_index = 0; - gpmd->flag |= GP_NOISE_MOD_LOCATION; gpmd->flag |= GP_NOISE_FULL_STROKE; gpmd->flag |= GP_NOISE_USE_RANDOM; gpmd->factor = 0.5f; @@ -182,7 +181,7 @@ static void deformStroke(GpencilModifierData *md, for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; /* verify vertex group */ - dvert = &gps->dvert[i]; + dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; float weight = get_modifier_point_weight(dvert, invert_group, def_nr); if (weight < 0.0f) { continue; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 96f1f004812..6aaa37d494b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -25,34 +25,64 @@ #include "BLI_utildefines.h" -#include "BLI_blenlib.h" -#include "BLI_math_vector.h" +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_gpencil_types.h" #include "DNA_gpencil_modifier_types.h" +#include "DNA_modifier_types.h" +#include "BKE_action.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" +#include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" -#include "BKE_material.h" +#include "BKE_layer.h" +#include "BKE_lib_query.h" #include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_modifier.h" +#include "BKE_scene.h" -#include "DEG_depsgraph.h" +#include "MEM_guardedalloc.h" #include "MOD_gpencil_util.h" #include "MOD_gpencil_modifiertypes.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + static void initData(GpencilModifierData *md) { TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; gpmd->pass_index = 0; - gpmd->factor = 0.5f; gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->object = NULL; + gpmd->radius = 1.0f; + gpmd->factor = 0.5f; ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f); - gpmd->modify_color = GP_MODIFY_COLOR_BOTH; + gpmd->mode = GPPAINT_MODE_BOTH; + + /* Add default color ramp. */ + gpmd->colorband = BKE_colorband_add(false); + if (gpmd->colorband) { + BKE_colorband_init(gpmd->colorband, true); + CBData *ramp = gpmd->colorband->data; + ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f; + ramp[0].pos = 0.0f; + ramp[1].r = ramp[1].g = ramp[1].b = 0.0f; + ramp[1].a = 1.0f; + ramp[1].pos = 1.0f; + + gpmd->colorband->tot = 2; + } gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); if (gpmd->curve_intensity) { @@ -66,6 +96,8 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target) TintGpencilModifierData *gmd = (TintGpencilModifierData *)md; TintGpencilModifierData *tgmd = (TintGpencilModifierData *)target; + MEM_SAFE_FREE(tgmd->colorband); + if (tgmd->curve_intensity != NULL) { BKE_curvemapping_free(tgmd->curve_intensity); tgmd->curve_intensity = NULL; @@ -73,10 +105,14 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target) BKE_gpencil_modifier_copyData_generic(md, target); + if (gmd->colorband) { + tgmd->colorband = MEM_dupallocN(gmd->colorband); + } + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } -/* tint strokes */ +/* deform stroke */ static void deformStroke(GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), Object *ob, @@ -85,6 +121,11 @@ static void deformStroke(GpencilModifierData *md, bGPDstroke *gps) { TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + if ((mmd->type == GP_TINT_GRADIENT) && (!mmd->object)) { + return; + } + + const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); const bool use_curve = (mmd->flag & GP_TINT_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, @@ -101,10 +142,10 @@ static void deformStroke(GpencilModifierData *md, mmd->flag & GP_TINT_INVERT_MATERIAL)) { return; } - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + const bool is_gradient = (mmd->type == GP_TINT_GRADIENT); - /* if factor > 1.0, affect the strength of the stroke */ + /* If factor > 1.0, affect the strength of the stroke. */ if (mmd->factor > 1.0f) { for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; @@ -113,67 +154,173 @@ static void deformStroke(GpencilModifierData *md, } } - /* Apply to Vertex Color. */ - float mixfac = mmd->factor; - - CLAMP(mixfac, 0.0, 1.0f); - /* Fill */ - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - /* If not using Vertex Color, use the material color. */ - if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && - (gp_style->fill_rgba[3] > 0.0f)) { - copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); - gps->vert_color_fill[3] = 1.0f; + float coba_res[4]; + float matrix[4][4]; + if (is_gradient) { + mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat); + } + + /* loop points and apply color. */ + bool fill_done = false; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + + if (!fill_done) { + /* Apply to fill. */ + if (mmd->mode != GPPAINT_MODE_STROKE) { + + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; + } + + if (is_gradient) { + float center[3]; + add_v3_v3v3(center, gps->boundbox_min, gps->boundbox_max); + mul_v3_fl(center, 0.5f); + float pt_loc[3]; + mul_v3_m4v3(pt_loc, matrix, &pt->x); + float dist = len_v3(pt_loc); + float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); + + BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, coba_res, mmd->factor); + gps->vert_color_fill[3] = clamp_f(mmd->factor, 0.0f, 1.0f); + } + else { + interp_v3_v3v3(gps->vert_color_fill, + gps->vert_color_fill, + mmd->rgb, + clamp_f(mmd->factor, 0.0f, 1.0f)); + } + /* If no stroke, cancel loop. */ + if (mmd->mode != GPPAINT_MODE_BOTH) { + break; + } + } + + fill_done = true; } - interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, mmd->rgb, mixfac); - } + /* Verify vertex group. */ + if (mmd->mode != GPPAINT_MODE_FILL) { + float weight = get_modifier_point_weight( + dvert, (mmd->flag & GP_TINT_INVERT_VGROUP) != 0, def_nr); + if (weight < 0.0f) { + continue; + } + /* Custom curve to modulate value. */ + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + } - /* Stroke */ - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; /* If not using Vertex Color, use the material color. */ if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); pt->vert_color[3] = 1.0f; } - /* Custom curve to modulate value. */ - float mixvalue = mixfac; - if (use_curve) { - float value = (float)i / (gps->totpoints - 1); - mixvalue *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); - } + if (is_gradient) { + /* Calc world position of point. */ + float pt_loc[3]; + mul_v3_m4v3(pt_loc, matrix, &pt->x); + float dist = len_v3(pt_loc); + + /* Calc the factor using the distance and get mix color. */ + float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); + BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); - interp_v3_v3v3(pt->vert_color, pt->vert_color, mmd->rgb, mixvalue); + interp_v3_v3v3(pt->vert_color, + pt->vert_color, + coba_res, + clamp_f(mmd->factor, 0.0f, 1.0f) * weight * coba_res[3]); + } + else { + interp_v3_v3v3( + pt->vert_color, pt->vert_color, mmd->rgb, clamp_f(mmd->factor * weight, 0.0, 1.0f)); + } } } } -static void bakeModifier(Main *UNUSED(bmain), - Depsgraph *depsgraph, - GpencilModifierData *md, - Object *ob) +/* FIXME: Ideally we be doing this on a copy of the main depsgraph + * (i.e. one where we don't have to worry about restoring state) + */ +static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) { + return; + } LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + /* apply effects on this frame + * NOTE: this assumes that we don't want animation on non-keyframed frames + */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* compute effects on this frame */ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } static void freeData(GpencilModifierData *md) { - TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + if (mmd->colorband) { + MEM_freeN(mmd->colorband); + mmd->colorband = NULL; + } + if (mmd->curve_intensity) { + BKE_curvemapping_free(mmd->curve_intensity); + } +} - if (gpmd->curve_intensity) { - BKE_curvemapping_free(gpmd->curve_intensity); +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + if (mmd->type == GP_TINT_UNIFORM) { + return false; + } + + return !mmd->object; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + TintGpencilModifierData *lmd = (TintGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Vertexcolor Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); +} + +static void foreachObjectLink(GpencilModifierData *md, + Object *ob, + ObjectWalkFunc walk, + void *userData) +{ + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } GpencilModifierTypeInfo modifierType_Gpencil_Tint = { @@ -192,10 +339,10 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* initData */ initData, /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, - /* foreachObjectLink */ NULL, + /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c deleted file mode 100644 index b279d90dd4f..00000000000 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2017, Blender Foundation - * This is a new part of Blender - */ - -/** \file - * \ingroup modifiers - */ - -#include <stdio.h> - -#include "BLI_utildefines.h" - -#include "BLI_math.h" -#include "BLI_listbase.h" - -#include "DNA_meshdata_types.h" -#include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_gpencil_modifier_types.h" -#include "DNA_modifier_types.h" - -#include "BKE_action.h" -#include "BKE_colorband.h" -#include "BKE_colortools.h" -#include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" -#include "BKE_layer.h" -#include "BKE_lib_query.h" -#include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_modifier.h" -#include "BKE_scene.h" - -#include "MEM_guardedalloc.h" - -#include "MOD_gpencil_util.h" -#include "MOD_gpencil_modifiertypes.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_query.h" - -static void initData(GpencilModifierData *md) -{ - VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md; - gpmd->pass_index = 0; - gpmd->layername[0] = '\0'; - gpmd->materialname[0] = '\0'; - gpmd->vgname[0] = '\0'; - gpmd->object = NULL; - gpmd->radius = 1.0f; - gpmd->factor = 1.0f; - - /* Add default color ramp. */ - gpmd->colorband = BKE_colorband_add(false); - if (gpmd->colorband) { - BKE_colorband_init(gpmd->colorband, true); - CBData *ramp = gpmd->colorband->data; - ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f; - ramp[0].pos = 0.0f; - ramp[1].r = ramp[1].g = ramp[1].b = 0.0f; - ramp[1].a = 1.0f; - ramp[1].pos = 1.0f; - - gpmd->colorband->tot = 2; - } - - gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - if (gpmd->curve_intensity) { - CurveMapping *curve = gpmd->curve_intensity; - BKE_curvemapping_initialize(curve); - } -} - -static void copyData(const GpencilModifierData *md, GpencilModifierData *target) -{ - VertexcolorGpencilModifierData *gmd = (VertexcolorGpencilModifierData *)md; - VertexcolorGpencilModifierData *tgmd = (VertexcolorGpencilModifierData *)target; - - MEM_SAFE_FREE(tgmd->colorband); - - if (tgmd->curve_intensity != NULL) { - BKE_curvemapping_free(tgmd->curve_intensity); - tgmd->curve_intensity = NULL; - } - - BKE_gpencil_modifier_copyData_generic(md, target); - - if (gmd->colorband) { - tgmd->colorband = MEM_dupallocN(gmd->colorband); - } - - tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); -} - -/* deform stroke */ -static void deformStroke(GpencilModifierData *md, - Depsgraph *UNUSED(depsgraph), - Object *ob, - bGPDlayer *gpl, - bGPDframe *UNUSED(gpf), - bGPDstroke *gps) -{ - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - if (!mmd->object) { - return; - } - - const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); - const bool use_curve = (mmd->flag & GP_VERTEXCOL_CUSTOM_CURVE) != 0 && mmd->curve_intensity; - - if (!is_stroke_affected_by_modifier(ob, - mmd->layername, - mmd->materialname, - mmd->pass_index, - mmd->layer_pass, - 1, - gpl, - gps, - mmd->flag & GP_VERTEXCOL_INVERT_LAYER, - mmd->flag & GP_VERTEXCOL_INVERT_PASS, - mmd->flag & GP_VERTEXCOL_INVERT_LAYERPASS, - mmd->flag & GP_VERTEXCOL_INVERT_MATERIAL)) { - return; - } - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - - float coba_res[4]; - float matrix[4][4]; - mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat); - - /* loop points and apply deform */ - bool fill_done = false; - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; - - if (!fill_done) { - /* Apply to fill. */ - if (mmd->mode != GPPAINT_MODE_STROKE) { - - /* If not using Vertex Color, use the material color. */ - if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && - (gp_style->fill_rgba[3] > 0.0f)) { - copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); - gps->vert_color_fill[3] = 1.0f; - } - - float center[3]; - add_v3_v3v3(center, gps->boundbox_min, gps->boundbox_max); - mul_v3_fl(center, 0.5f); - float pt_loc[3]; - mul_v3_m4v3(pt_loc, matrix, &pt->x); - float dist = len_v3(pt_loc); - float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); - - BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); - interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, coba_res, mmd->factor); - gps->vert_color_fill[3] = mmd->factor; - /* If no stroke, cancel loop. */ - if (mmd->mode != GPPAINT_MODE_BOTH) { - break; - } - } - - fill_done = true; - } - - /* Verify vertex group. */ - if (mmd->mode != GPPAINT_MODE_FILL) { - float weight = get_modifier_point_weight( - dvert, (mmd->flag & GP_VERTEXCOL_INVERT_VGROUP) != 0, def_nr); - if (weight < 0.0f) { - continue; - } - /* Custom curve to modulate value. */ - if (use_curve) { - float value = (float)i / (gps->totpoints - 1); - weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); - } - - /* Calc world position of point. */ - float pt_loc[3]; - mul_v3_m4v3(pt_loc, matrix, &pt->x); - float dist = len_v3(pt_loc); - - /* If not using Vertex Color, use the material color. */ - if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { - copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); - pt->vert_color[3] = 1.0f; - } - - /* Calc the factor using the distance and get mix color. */ - float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); - BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); - - interp_v3_v3v3(pt->vert_color, pt->vert_color, coba_res, mmd->factor * weight * coba_res[3]); - } - } -} - -/* FIXME: Ideally we be doing this on a copy of the main depsgraph - * (i.e. one where we don't have to worry about restoring state) - */ -static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) -{ - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - Scene *scene = DEG_get_evaluated_scene(depsgraph); - bGPdata *gpd = ob->data; - int oldframe = (int)DEG_get_ctime(depsgraph); - - if (mmd->object == NULL) { - return; - } - - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - /* apply effects on this frame - * NOTE: this assumes that we don't want animation on non-keyframed frames - */ - CFRA = gpf->framenum; - BKE_scene_graph_update_for_newframe(depsgraph, bmain); - - /* compute effects on this frame */ - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - deformStroke(md, depsgraph, ob, gpl, gpf, gps); - } - } - } - - /* return frame state and DB to original state */ - CFRA = oldframe; - BKE_scene_graph_update_for_newframe(depsgraph, bmain); -} - -static void freeData(GpencilModifierData *md) -{ - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - if (mmd->colorband) { - MEM_freeN(mmd->colorband); - mmd->colorband = NULL; - } - if (mmd->curve_intensity) { - BKE_curvemapping_free(mmd->curve_intensity); - } -} - -static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) -{ - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - - return !mmd->object; -} - -static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) -{ - VertexcolorGpencilModifierData *lmd = (VertexcolorGpencilModifierData *)md; - if (lmd->object != NULL) { - DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Vertexcolor Modifier"); - DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); - } - DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); -} - -static void foreachObjectLink(GpencilModifierData *md, - Object *ob, - ObjectWalkFunc walk, - void *userData) -{ - VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; - - walk(userData, ob, &mmd->object, IDWALK_CB_NOP); -} - -GpencilModifierTypeInfo modifierType_Gpencil_Vertexcolor = { - /* name */ "Vertex Color", - /* structName */ "VertexcolorGpencilModifierData", - /* structSize */ sizeof(VertexcolorGpencilModifierData), - /* type */ eGpencilModifierTypeType_Gpencil, - /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, - - /* copyData */ copyData, - - /* deformStroke */ deformStroke, - /* generateStrokes */ NULL, - /* bakeModifier */ bakeModifier, - /* remapTime */ NULL, - - /* initData */ initData, - /* freeData */ freeData, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, - /* foreachObjectLink */ foreachObjectLink, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, -}; diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 5eae86e50f0..f21cd990a41 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -189,15 +189,17 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) * \{ */ /* Returns the Face Set random color for rendering in the overlay given its ID and a color seed. */ +#define GOLDEN_RATIO_CONJUGATE 0.618033988749895f static void face_set_overlay_color_get(const int face_set, const int seed, uchar *r_color) { float rgba[4]; - const float random_mod_hue = BLI_hash_int_01(abs(face_set) + seed); + float random_mod_hue = GOLDEN_RATIO_CONJUGATE * (abs(face_set) + (seed % 10)); + random_mod_hue = random_mod_hue - floorf(random_mod_hue); const float random_mod_sat = BLI_hash_int_01(abs(face_set) + seed + 1); const float random_mod_val = BLI_hash_int_01(abs(face_set) + seed + 2); hsv_to_rgb(random_mod_hue, - 0.45f + (random_mod_sat * 0.35f), - 1.0f - (random_mod_val * 0.45f), + 0.6f + (random_mod_sat * 0.25f), + 1.0f - (random_mod_val * 0.35f), &rgba[0], &rgba[1], &rgba[2]); @@ -264,8 +266,8 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, } /* Face Sets. */ - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; for (uint i = 0; i < buffers->face_indices_len; i++) { + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; if (show_face_sets) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; const int fset = abs(sculpt_face_sets[lt->poly]); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 33bc3ced5b2..348b9dddba9 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -180,27 +180,28 @@ float GPU_get_anisotropic(void) /* Set OpenGL state for an MTFace */ -static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget) +static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget, const int multiview_eye) { if (textarget == GL_TEXTURE_2D) { - return &ima->gputexture[TEXTARGET_TEXTURE_2D]; + return &(ima->gputexture[TEXTARGET_TEXTURE_2D][multiview_eye]); } else if (textarget == GL_TEXTURE_CUBE_MAP) { - return &ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP]; + return &(ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP][multiview_eye]); } else if (textarget == GL_TEXTURE_2D_ARRAY) { - return &ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]; + return &(ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][multiview_eye]); } else if (textarget == GL_TEXTURE_1D_ARRAY) { - return &ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING]; + return &(ima->gputexture[TEXTARGET_TEXTURE_TILE_MAPPING][multiview_eye]); } return NULL; } -static uint gpu_texture_create_tile_mapping(Image *ima) +static uint gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye) { - GPUTexture *tilearray = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]; + GPUTexture *tilearray = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][multiview_eye]; + if (tilearray == NULL) { return 0; } @@ -876,7 +877,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, BKE_image_tag_time(ima); /* Test if we already have a texture. */ - GPUTexture **tex = gpu_get_image_gputexture(ima, textarget); + GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser->multiview_eye); if (*tex) { return *tex; } @@ -904,7 +905,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, bindcode = gpu_texture_create_tile_array(ima, ibuf_intern); } else if (textarget == GL_TEXTURE_1D_ARRAY) { - bindcode = gpu_texture_create_tile_mapping(ima); + bindcode = gpu_texture_create_tile_mapping(ima, iuser->multiview_eye); } else { bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget); @@ -1288,14 +1289,16 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { if (BKE_image_has_opengl_texture(ima)) { if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) { - for (int a = 0; a < TEXTARGET_COUNT; a++) { - if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) { - GPUTexture *tex = ima->gputexture[a]; - if (tex != NULL) { - GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - GPU_texture_unbind(tex); + for (int eye = 0; eye < 2; eye++) { + for (int a = 0; a < TEXTARGET_COUNT; a++) { + if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) { + GPUTexture *tex = ima->gputexture[a][eye]; + if (tex != NULL) { + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); + GPU_texture_unbind(tex); + } } } } @@ -1312,14 +1315,16 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) else { for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { if (BKE_image_has_opengl_texture(ima)) { - for (int a = 0; a < TEXTARGET_COUNT; a++) { - if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) { - GPUTexture *tex = ima->gputexture[a]; - if (tex != NULL) { - GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - GPU_texture_unbind(tex); + for (int eye = 0; eye < 2; eye++) { + for (int a = 0; a < TEXTARGET_COUNT; a++) { + if (ELEM(a, TEXTARGET_TEXTURE_2D, TEXTARGET_TEXTURE_2D_ARRAY)) { + GPUTexture *tex = ima->gputexture[a][eye]; + if (tex != NULL) { + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); + GPU_texture_unbind(tex); + } } } } @@ -1343,14 +1348,14 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i GPU_free_image(ima); } - GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D]; + GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D][0]; /* Check if we need to update the main gputexture. */ if (tex != NULL && tile == ima->tiles.first) { gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h); } /* Check if we need to update the array gputexture. */ - tex = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY]; + tex = ima->gputexture[TEXTARGET_TEXTURE_2D_ARRAY][0]; if (tex != NULL) { gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h); } @@ -1395,11 +1400,13 @@ void GPU_free_unused_buffers(Main *bmain) static void gpu_free_image_immediate(Image *ima) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - /* free glsl image binding */ - if (ima->gputexture[i] != NULL) { - GPU_texture_free(ima->gputexture[i]); - ima->gputexture[i] = NULL; + for (int eye = 0; eye < 2; eye++) { + for (int i = 0; i < TEXTARGET_COUNT; i++) { + /* free glsl image binding */ + if (ima->gputexture[i][eye] != NULL) { + GPU_texture_free(ima->gputexture[i][eye]); + ima->gputexture[i][eye] = NULL; + } } } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 351c85aa2d8..941f5049dbf 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -677,7 +677,7 @@ static void gpu_viewport_storage_free(StorageList *stl, int stl_len) static void gpu_viewport_passes_free(PassList *psl, int psl_len) { - memset(psl, 0, sizeof(struct DRWPass *) * psl_len); + memset(psl->passes, 0, sizeof(*psl->passes) * psl_len); } /* Must be executed inside Drawmanager Opengl Context. */ diff --git a/source/blender/io/avi/intern/avi_rgb.c b/source/blender/io/avi/intern/avi_rgb.c index d449556e79b..6f4f33d72d1 100644 --- a/source/blender/io/avi/intern/avi_rgb.c +++ b/source/blender/io/avi/intern/avi_rgb.c @@ -33,6 +33,8 @@ #include "IMB_imbuf.h" +#include "BLI_utildefines.h" + /* implementation */ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buffer, size_t *size) @@ -97,7 +99,8 @@ void *avi_converter_from_avi_rgb(AviMovie *movie, int stream, unsigned char *buf if (buf) { size_t rowstride = movie->header->Width * 3; - if ((bits != 16) && (movie->header->Width % 2)) { + BLI_assert(bits != 16); + if (movie->header->Width % 2) { rowstride++; } diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc index a958a445a3d..50f81c2ffb1 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc @@ -25,6 +25,8 @@ extern "C" { #include "BKE_anim.h" +#include "BKE_animsys.h" +#include "BKE_key.h" #include "BKE_particle.h" #include "BLI_assert.h" @@ -33,6 +35,7 @@ extern "C" { #include "DNA_ID.h" #include "DNA_layer_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" @@ -76,6 +79,31 @@ AbstractHierarchyWriter::~AbstractHierarchyWriter() { } +bool AbstractHierarchyWriter::check_is_animated(const HierarchyContext &context) const +{ + const Object *object = context.object; + + if (BKE_animdata_id_is_animated(static_cast<ID *>(object->data))) { + return true; + } + if (BKE_key_from_object(object) != nullptr) { + return true; + } + + /* Test modifiers. */ + /* TODO(Sybren): replace this with a check on the depsgraph to properly check for dependency on + * time. */ + ModifierData *md = static_cast<ModifierData *>(object->modifiers.first); + while (md) { + if (md->type != eModifierType_Subsurf) { + return true; + } + md = md->next; + } + + return false; +} + AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph) : depsgraph_(depsgraph), writers_() { diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h index c121e3b704d..64c831877ab 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h @@ -115,6 +115,8 @@ class AbstractHierarchyWriter { // TODO(Sybren): add function like absent() that's called when a writer was previously created, // but wasn't used while exporting the current frame (for example, a particle-instanced mesh of // which the particle is no longer alive). + protected: + virtual bool check_is_animated(const HierarchyContext &context) const; }; /* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index 83e11cd7bf3..60ab3676847 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -49,7 +49,6 @@ extern "C" { namespace USD { struct ExportJobData { - ViewLayer *view_layer; Main *bmain; Depsgraph *depsgraph; wmWindowManager *wm; @@ -57,22 +56,13 @@ struct ExportJobData { char filename[FILE_MAX]; USDExportParams params; - short *stop; - short *do_update; - float *progress; - - bool was_canceled; bool export_ok; }; static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) { ExportJobData *data = static_cast<ExportJobData *>(customdata); - - data->stop = stop; - data->do_update = do_update; - data->progress = progress; - data->was_canceled = false; + data->export_ok = false; G.is_rendering = true; WM_set_locked_interface(data->wm, true); @@ -97,7 +87,6 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo * USDC files, and creating a new UsdStage fails. */ WM_reportf( RPT_ERROR, "USD Export: unable to find suitable USD plugin to write %s", data->filename); - data->export_ok = false; return; } @@ -150,8 +139,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); } - data->export_ok = !data->was_canceled; - + data->export_ok = true; *progress = 1.0f; *do_update = true; } @@ -162,7 +150,7 @@ static void export_endjob(void *customdata) DEG_graph_free(data->depsgraph); - if (data->was_canceled && BLI_exists(data->filename)) { + if (!data->export_ok && BLI_exists(data->filename)) { BLI_delete(data->filename, false, false); } diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc index 4d0b4364fb5..76a2436ee92 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.cc +++ b/source/blender/io/usd/intern/usd_writer_abstract.cc @@ -21,13 +21,6 @@ #include <pxr/base/tf/stringUtils.h> -extern "C" { -#include "BKE_animsys.h" -#include "BKE_key.h" - -#include "DNA_modifier_types.h" -} - /* TfToken objects are not cheap to construct, so we do it once. */ namespace usdtokens { // Materials @@ -85,31 +78,6 @@ void USDAbstractWriter::write(HierarchyContext &context) frame_has_been_written_ = true; } -bool USDAbstractWriter::check_is_animated(const HierarchyContext &context) const -{ - const Object *object = context.object; - - if (BKE_animdata_id_is_animated(static_cast<ID *>(object->data))) { - return true; - } - if (BKE_key_from_object(object) != nullptr) { - return true; - } - - /* Test modifiers. */ - /* TODO(Sybren): replace this with a check on the depsgraph to properly check for dependency on - * time. */ - ModifierData *md = static_cast<ModifierData *>(object->modifiers.first); - while (md) { - if (md->type != eModifierType_Subsurf) { - return true; - } - md = md->next; - } - - return false; -} - const pxr::SdfPath &USDAbstractWriter::usd_path() const { return usd_export_context_.usd_path; diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h index 835d3a42c80..ad8049f499c 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.h +++ b/source/blender/io/usd/intern/usd_writer_abstract.h @@ -66,7 +66,6 @@ class USDAbstractWriter : public AbstractHierarchyWriter { protected: virtual void do_write(HierarchyContext &context) = 0; - virtual bool check_is_animated(const HierarchyContext &context) const; pxr::UsdTimeCode get_export_time_code() const; pxr::UsdShadeMaterial ensure_usd_material(Material *material); diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 1121bdf4df0..bc7873adb70 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -47,7 +47,6 @@ typedef enum GpencilModifierType { eGpencilModifierType_Armature = 15, eGpencilModifierType_Time = 16, eGpencilModifierType_Multiply = 17, - eGpencilModifierType_Vertexcolor = 18, NUM_GREASEPENCIL_MODIFIER_TYPES, } GpencilModifierType; @@ -106,15 +105,15 @@ typedef struct NoiseGpencilModifierData { typedef enum eNoiseGpencil_Flag { GP_NOISE_USE_RANDOM = (1 << 0), - GP_NOISE_MOD_LOCATION = (1 << 1), - GP_NOISE_MOD_STRENGTH = (1 << 2), - GP_NOISE_MOD_THICKNESS = (1 << 3), + GP_NOISE_MOD_LOCATION = (1 << 1), /* Deprecated (only for versioning). */ + GP_NOISE_MOD_STRENGTH = (1 << 2), /* Deprecated (only for versioning). */ + GP_NOISE_MOD_THICKNESS = (1 << 3), /* Deprecated (only for versioning). */ GP_NOISE_FULL_STROKE = (1 << 4), GP_NOISE_CUSTOM_CURVE = (1 << 5), GP_NOISE_INVERT_LAYER = (1 << 6), GP_NOISE_INVERT_PASS = (1 << 7), GP_NOISE_INVERT_VGROUP = (1 << 8), - GP_NOISE_MOD_UV = (1 << 9), + GP_NOISE_MOD_UV = (1 << 9), /* Deprecated (only for versioning). */ GP_NOISE_INVERT_LAYERPASS = (1 << 10), GP_NOISE_INVERT_MATERIAL = (1 << 11), } eNoiseGpencil_Flag; @@ -223,38 +222,6 @@ typedef enum eOpacityModesGpencil_Flag { GP_OPACITY_MODE_STRENGTH = 1, } eOpacityModesGpencil_Flag; -typedef struct TintGpencilModifierData { - GpencilModifierData modifier; - /** Layer name. */ - char layername[64]; - /** Material name. */ - char materialname[64]; - /** Custom index for passes. */ - int pass_index; - /** Flags. */ - int flag; - /** Tint color. */ - float rgb[3]; - /** Mix factor. */ - float factor; - /** Modify stroke, fill or both. */ - char modify_color; - char _pad[7]; - /** Custom index for passes. */ - int layer_pass; - - char _pad1[4]; - struct CurveMapping *curve_intensity; -} TintGpencilModifierData; - -typedef enum eTintGpencil_Flag { - GP_TINT_INVERT_LAYER = (1 << 1), - GP_TINT_INVERT_PASS = (1 << 2), - GP_TINT_INVERT_LAYERPASS = (1 << 3), - GP_TINT_INVERT_MATERIAL = (1 << 4), - GP_TINT_CUSTOM_CURVE = (1 << 5), -} eTintGpencil_Flag; - typedef struct ColorGpencilModifierData { GpencilModifierData modifier; /** Layer name. */ @@ -700,7 +667,7 @@ typedef enum eMultiplyGpencil_Flag { GP_MULTIPLY_ENABLE_FADING = (1 << 2), } eMultiplyGpencil_Flag; -typedef struct VertexcolorGpencilModifierData { +typedef struct TintGpencilModifierData { GpencilModifierData modifier; struct Object *object; @@ -716,25 +683,33 @@ typedef struct VertexcolorGpencilModifierData { int layer_pass; /** Flags. */ int flag; - /** Mode. */ + /** Mode (Stroke/Fill/Both). */ int mode; float factor; float radius; + /** Simple Tint color. */ + float rgb[3]; + /** Type of Tint. */ + int type; struct CurveMapping *curve_intensity; struct ColorBand *colorband; -} VertexcolorGpencilModifierData; - -typedef enum eVertexcolorGpencil_Flag { - GP_VERTEXCOL_INVERT_LAYER = (1 << 0), - GP_VERTEXCOL_INVERT_PASS = (1 << 1), - GP_VERTEXCOL_INVERT_VGROUP = (1 << 2), - GP_VERTEXCOL_UNIFORM_SPACE = (1 << 3), - GP_VERTEXCOL_INVERT_LAYERPASS = (1 << 4), - GP_VERTEXCOL_INVERT_MATERIAL = (1 << 5), - GP_VERTEXCOL_CUSTOM_CURVE = (1 << 6), -} eVertexcolorGpencil_Flag; +} TintGpencilModifierData; + +typedef enum eTintGpencil_Type { + GP_TINT_UNIFORM = 0, + GP_TINT_GRADIENT = 1, +} eTintGpencil_Type; + +typedef enum eTintGpencil_Flag { + GP_TINT_INVERT_LAYER = (1 << 0), + GP_TINT_INVERT_PASS = (1 << 1), + GP_TINT_INVERT_VGROUP = (1 << 2), + GP_TINT_INVERT_LAYERPASS = (1 << 4), + GP_TINT_INVERT_MATERIAL = (1 << 5), + GP_TINT_CUSTOM_CURVE = (1 << 6), +} eTintGpencil_Flag; #endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 6059df6f886..909d65fb5ed 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -28,7 +28,6 @@ #include "DNA_ID.h" #include "DNA_brush_types.h" -struct ARegion; struct AnimData; struct MDeformVert; @@ -481,8 +480,6 @@ typedef enum eGPLayerBlendModes { /* Runtime temp data for bGPdata */ typedef struct bGPdata_Runtime { - /** Last region where drawing was originated. */ - struct ARegion *ar; /** Stroke buffer. */ void *sbuffer; /** Temp batches cleared after drawing. */ diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 03de4fb0473..d443d7806ad 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -133,8 +133,8 @@ typedef struct Image { /** Not written in file. */ struct MovieCache *cache; - /** Not written in file 4 = TEXTARGET_COUNT. */ - struct GPUTexture *gputexture[4]; + /** Not written in file 4 = TEXTARGET_COUNT, 2 = stereo eyes. */ + struct GPUTexture *gputexture[4][2]; /* sources from: */ ListBase anims; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index b2d02600124..7e8b888b82c 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4348,7 +4348,9 @@ static void rna_generate(BlenderRNA *brna, FILE *f, const char *filename, const /* include the generated prototypes header */ fprintf(f, "#include \"rna_prototypes_gen.h\"\n\n"); - fprintf(f, "#include \"%s\"\n", filename); + if (filename) { + fprintf(f, "#include \"%s\"\n", filename); + } if (api_filename) { fprintf(f, "#include \"%s\"\n", api_filename); } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 5c824dc6e93..bd5c7e755d6 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1468,6 +1468,15 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_FAKE_USER_OFF, true); RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_fake_user_set"); + prop = RNA_def_property(srna, "is_embedded_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_EMBEDDED_DATA); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, + "Embedded Data", + "This data-block is not an independant one, but is actually a sub-data of another ID " + "(typical example: root node trees or master collections)"); + prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_DOIT); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 0caa93940c8..00188ac0887 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -129,11 +129,6 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { "Opacity", "Opacity of the strokes"}, {eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"}, - {eGpencilModifierType_Vertexcolor, - "GP_VERTEXCOLOR", - ICON_MOD_NORMALEDIT, - "Vertex Color", - "Apply color changes to Vertex Color"}, {0, NULL, 0, NULL, NULL}, }; @@ -170,6 +165,11 @@ static const EnumPropertyItem gpencil_subdivision_type_items[] = { {GP_SUBDIV_SIMPLE, "SIMPLE", 0, "Simple", ""}, {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem gpencil_tint_type_items[] = { + {GP_TINT_UNIFORM, "UNIFORM", 0, "Uniform", ""}, + {GP_TINT_GRADIENT, "GRADIENT", 0, "Gradient", ""}, + {0, NULL, 0, NULL, NULL}, +}; #endif #ifdef RNA_RUNTIME @@ -226,8 +226,6 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr) return &RNA_ArmatureGpencilModifier; case eGpencilModifierType_Multiply: return &RNA_MultiplyGpencilModifier; - case eGpencilModifierType_Vertexcolor: - return &RNA_VertexcolorGpencilModifier; /* Default */ case eGpencilModifierType_None: case NUM_GREASEPENCIL_MODIFIER_TYPES: @@ -342,11 +340,11 @@ static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, BKE_object_modifier_gpencil_hook_reset(ob, hmd); } -static void rna_VertexcolorGpencilModifier_object_set(PointerRNA *ptr, - PointerRNA value, - struct ReportList *UNUSED(reports)) +static void rna_TintGpencilModifier_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { - VertexcolorGpencilModifierData *hmd = ptr->data; + TintGpencilModifierData *hmd = ptr->data; Object *ob = (Object *)value.data; hmd->object = ob; @@ -480,12 +478,6 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Seed", "Random seed"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_LOCATION); - RNA_def_property_ui_text( - prop, "Affect Position", "The modifier affects the position of the point"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "noise_scale"); RNA_def_property_range(prop, 0.0, 1.0); @@ -1018,15 +1010,25 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + /* modes */ + static EnumPropertyItem tint_mode_types_items[] = { + {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, + {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Both", "Vertex Color affects to Stroke and Fill"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "TintGpencilModifier", "GpencilModifier"); - RNA_def_struct_ui_text(srna, "Tint Modifier", "Tint Stroke Color modifier"); + RNA_def_struct_ui_text(srna, "Tint Modifier", "Tint modifier"); RNA_def_struct_sdna(srna, "TintGpencilModifierData"); RNA_def_struct_ui_icon(srna, ICON_COLOR); - prop = RNA_def_property(srna, "modify_color", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, modifier_modify_color_items); /* share the enum */ - RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Parent object to define the center of the effect"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_pointer_funcs(prop, NULL, "rna_TintGpencilModifier_object_set", NULL, NULL); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "layername"); @@ -1038,17 +1040,10 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Material", "Material name"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); - RNA_def_property_range(prop, 0.0, 1.0); - RNA_def_property_float_sdna(prop, NULL, "rgb"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Color", "Color used for tinting"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "factor"); - RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2); - RNA_def_property_ui_text(prop, "Factor", "Factor for mixing color"); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookGpencilModifier_vgname_set"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); @@ -1072,6 +1067,11 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_VGROUP); + 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); RNA_def_property_int_sdna(prop, NULL, "layer_pass"); RNA_def_property_range(prop, 0, 100); @@ -1083,10 +1083,54 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_range(prop, 0, 2.0); + RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2); + RNA_def_property_ui_text(prop, "Strength", "Factor for tinting"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "radius"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 1, 3); + RNA_def_property_ui_text(prop, "Radius", "Defines the maximum distance of the effect"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Mode type. */ + prop = RNA_def_property(srna, "vertex_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, tint_mode_types_items); + RNA_def_property_ui_text(prop, "Mode", "Defines how vertex color affect to the strokes"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Type of Tint. */ + prop = RNA_def_property(srna, "tint_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, gpencil_tint_type_items); + RNA_def_property_ui_text(prop, "Tint Type", "Select type of tinting algorithm"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Simple Color. */ + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Color", "Color used for tinting"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Color band. */ + prop = RNA_def_property(srna, "colors", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "colorband"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Colors", "Color ramp used to define tinting colors"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CUSTOM_CURVE); RNA_def_property_ui_text( - prop, "Custom Curve", "Use a custom curve to define tint effect along the strokes"); + prop, "Custom Curve", "Use a custom curve to define vertex color effect along the strokes"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE); @@ -2078,125 +2122,6 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } -static void rna_def_modifier_gpencilvertexcolor(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - /* modes */ - static EnumPropertyItem vertexcol_mode_types_items[] = { - {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, - {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Both", "Vertex Color affects to Stroke and Fill"}, - {0, NULL, 0, NULL, NULL}, - }; - - srna = RNA_def_struct(brna, "VertexcolorGpencilModifier", "GpencilModifier"); - RNA_def_struct_ui_text(srna, "Vertexcolor Modifier", "Vertex color modifier"); - RNA_def_struct_sdna(srna, "VertexcolorGpencilModifierData"); - RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT); - - prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "Object", "Parent object to define the center of the effect"); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_pointer_funcs( - prop, NULL, "rna_VertexcolorGpencilModifier_object_set", NULL, NULL); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); - - prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "layername"); - RNA_def_property_ui_text(prop, "Layer", "Layer name"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "materialname"); - RNA_def_property_ui_text(prop, "Material", "Material name"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "vgname"); - RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookGpencilModifier_vgname_set"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "pass_index"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Pass", "Pass index"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_LAYER); - RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_MATERIAL); - RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_PASS); - RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_VGROUP); - 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); - RNA_def_property_int_sdna(prop, NULL, "layer_pass"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Pass", "Layer pass index"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_LAYERPASS); - RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "factor"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Factor", "Factor of tinting"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_sdna(prop, NULL, "radius"); - RNA_def_property_range(prop, 1e-6f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 1, 3); - RNA_def_property_ui_text(prop, "Radius", "Defines the maximum distance of the effect"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - /* Mode type. */ - prop = RNA_def_property(srna, "vertex_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); - RNA_def_property_enum_items(prop, vertexcol_mode_types_items); - RNA_def_property_ui_text(prop, "Mode", "Defines how vertex color affect to the strokes"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - /* Color band */ - prop = RNA_def_property(srna, "colors", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "colorband"); - RNA_def_property_struct_type(prop, "ColorRamp"); - RNA_def_property_ui_text(prop, "Colors", "Color ramp used to define tinting colors"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_CUSTOM_CURVE); - RNA_def_property_ui_text( - prop, "Custom Curve", "Use a custom curve to define vertex color effect along the strokes"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - - prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity"); - RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); -} - void RNA_def_greasepencil_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -2270,7 +2195,6 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna) rna_def_modifier_gpencilhook(brna); rna_def_modifier_gpencilarmature(brna); rna_def_modifier_gpencilmultiply(brna); - rna_def_modifier_gpencilvertexcolor(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index b8174f094ec..8f2a841b55c 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -398,7 +398,7 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values) static int rna_Image_bindcode_get(PointerRNA *ptr) { Image *ima = (Image *)ptr->data; - GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D]; + GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D][0]; return (tex) ? GPU_texture_opengl_bindcode(tex) : 0; } diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 883c17aa1e1..2068c747f4e 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -60,7 +60,7 @@ static void initData(ModifierData *md) mmd->renderlvl = 0; mmd->totlvl = 0; mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - mmd->quality = 3; + mmd->quality = 4; mmd->flags |= eMultiresModifierFlag_UseCrease; } diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 605919662f7..743c2227981 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1121,20 +1121,25 @@ static void deformVert(void *__restrict userdata, { const SDefDeformData *const data = (SDefDeformData *)userdata; const SDefBind *sdbind = data->bind_verts[index].binds; + const int num_binds = data->bind_verts[index].numbinds; float *const vertexCos = data->vertexCos[index]; float norm[3], temp[3]; zero_v3(vertexCos); - for (int j = 0; j < data->bind_verts[index].numbinds; j++, sdbind++) { - /* Mode-generic operations (allocate poly coordinates) */ - float(*coords)[3] = MEM_malloc_arrayN(sdbind->numverts, sizeof(*coords), "SDefDoPolyCoords"); + /* Allocate a `coords_buffer` that fits all the temp-data. */ + int max_verts = 0; + for (int j = 0; j < num_binds; j++) { + max_verts = MAX2(max_verts, sdbind[j].numverts); + } + float(*coords_buffer)[3] = MEM_malloc_arrayN(max_verts, sizeof(*coords_buffer), __func__); + for (int j = 0; j < num_binds; j++, sdbind++) { for (int k = 0; k < sdbind->numverts; k++) { - copy_v3_v3(coords[k], data->targetCos[sdbind->vert_inds[k]]); + copy_v3_v3(coords_buffer[k], data->targetCos[sdbind->vert_inds[k]]); } - normal_poly_v3(norm, coords, sdbind->numverts); + normal_poly_v3(norm, coords_buffer, sdbind->numverts); zero_v3(temp); /* ---------- looptri mode ---------- */ @@ -1147,14 +1152,14 @@ static void deformVert(void *__restrict userdata, /* ---------- ngon mode ---------- */ if (sdbind->mode == MOD_SDEF_MODE_NGON) { for (int k = 0; k < sdbind->numverts; k++) { - madd_v3_v3fl(temp, coords[k], sdbind->vert_weights[k]); + madd_v3_v3fl(temp, coords_buffer[k], sdbind->vert_weights[k]); } } /* ---------- centroid mode ---------- */ else if (sdbind->mode == MOD_SDEF_MODE_CENTROID) { float cent[3]; - mid_v3_v3_array(cent, coords, sdbind->numverts); + mid_v3_v3_array(cent, coords_buffer, sdbind->numverts); madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[0]], sdbind->vert_weights[0]); madd_v3_v3fl(temp, data->targetCos[sdbind->vert_inds[1]], sdbind->vert_weights[1]); @@ -1162,13 +1167,12 @@ static void deformVert(void *__restrict userdata, } } - MEM_freeN(coords); - /* Apply normal offset (generic for all modes) */ madd_v3_v3fl(temp, norm, sdbind->normal_dist); madd_v3_v3fl(vertexCos, temp, sdbind->influence); } + MEM_freeN(coords_buffer); } static void surfacedeformModifier_do(ModifierData *md, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 41227a14fb3..a2f825ee454 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -206,10 +206,10 @@ set(SRC shader/nodes/node_shader_uvmap.c shader/nodes/node_shader_valToRgb.c shader/nodes/node_shader_value.c - shader/nodes/node_shader_vector_rotate.c shader/nodes/node_shader_vectTransform.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_vector_math.c + shader/nodes/node_shader_vector_rotate.c shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_info.c diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 93f2ba44a3a..8c224eb335f 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -101,9 +101,8 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree) bNode *node = ntree->nodes.first; bNode *local_node = localtree->nodes.first; while (node != NULL) { - local_node->original = node; - /* ensure new user input gets handled ok */ + /* Ensure new user input gets handled ok. */ node->need_exec = 0; local_node->original = node; diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.c b/source/blender/nodes/composite/nodes/node_composite_keying.c index 504126cb387..73e86a21ebe 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keying.c +++ b/source/blender/nodes/composite/nodes/node_composite_keying.c @@ -57,7 +57,6 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node) data->despill_factor = 1.0f; data->edge_kernel_radius = 3; data->edge_kernel_tolerance = 0.1f; - data->clip_white = 1.0f; data->clip_black = 0.0f; data->clip_white = 1.0f; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c32ef3e6624..92230ece35e 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -5424,6 +5424,174 @@ static PyObject *pyrna_prop_collection_foreach_set(BPy_PropertyRNA *self, PyObje return foreach_getset(self, args, 1); } +static PyObject *pyprop_array_foreach_getset(BPy_PropertyArrayRNA *self, + PyObject *args, + const bool do_set) +{ + PyObject *item = NULL; + Py_ssize_t i, seq_size, size; + void *array = NULL; + PropertyType prop_type = RNA_property_type(self->prop); + + /* Get/set both take the same args currently. */ + PyObject *seq; + + if (prop_type != PROP_INT && prop_type != PROP_FLOAT) { + PyErr_Format(PyExc_TypeError, "foreach_get/set available only for int and float"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "O:foreach_get/set", &seq)) { + return NULL; + } + + if (!PySequence_Check(seq) && PyObject_CheckBuffer(seq)) { + PyErr_Format( + PyExc_TypeError, + "foreach_get/set expected second argument to be a sequence or buffer, not a %.200s", + Py_TYPE(seq)->tp_name); + return NULL; + } + + size = pyrna_prop_array_length(self); + seq_size = PySequence_Size(seq); + + if (size != seq_size) { + PyErr_Format(PyExc_TypeError, "expected sequence size %d, got %d", size, seq_size); + return NULL; + } + + Py_buffer buf; + if (PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT) == -1) { + PyErr_Clear(); + + switch (prop_type) { + case PROP_INT: + array = PyMem_Malloc(sizeof(int) * size); + if (do_set) { + for (i = 0; i < size; i++) { + item = PySequence_GetItem(seq, i); + ((int *)array)[i] = (int)PyLong_AsLong(item); + Py_DECREF(item); + } + + RNA_property_int_set_array(&self->ptr, self->prop, array); + } + else { + RNA_property_int_get_array(&self->ptr, self->prop, array); + + for (i = 0; i < size; i++) { + item = PyLong_FromLong((long)((int *)array)[i]); + PySequence_SetItem(seq, i, item); + Py_DECREF(item); + } + } + + break; + case PROP_FLOAT: + array = PyMem_Malloc(sizeof(float) * size); + if (do_set) { + for (i = 0; i < size; i++) { + item = PySequence_GetItem(seq, i); + ((float *)array)[i] = (float)PyFloat_AsDouble(item); + Py_DECREF(item); + } + + RNA_property_float_set_array(&self->ptr, self->prop, array); + } + else { + RNA_property_float_get_array(&self->ptr, self->prop, array); + + for (i = 0; i < size; i++) { + item = PyFloat_FromDouble((double)((float *)array)[i]); + PySequence_SetItem(seq, i, item); + Py_DECREF(item); + } + } + break; + case PROP_BOOLEAN: + case PROP_STRING: + case PROP_ENUM: + case PROP_POINTER: + case PROP_COLLECTION: + /* Should never happen. */ + BLI_assert(false); + break; + } + + PyMem_Free(array); + + if (PyErr_Occurred()) { + /* Maybe we could make our own error. */ + PyErr_Print(); + PyErr_SetString(PyExc_TypeError, "couldn't access the py sequence"); + return NULL; + } + } + else { + char f = buf.format ? buf.format[0] : 0; + if ((prop_type == PROP_INT && (buf.itemsize != sizeof(int) || (f != 'l' && f != 'i'))) || + (prop_type == PROP_FLOAT && (buf.itemsize != sizeof(float) || f != 'f'))) { + PyBuffer_Release(&buf); + PyErr_Format(PyExc_TypeError, "incorrect sequence item type: %s", buf.format); + return NULL; + } + + switch (prop_type) { + case PROP_INT: + if (do_set) { + RNA_property_int_set_array(&self->ptr, self->prop, buf.buf); + } + else { + RNA_property_int_get_array(&self->ptr, self->prop, buf.buf); + } + break; + case PROP_FLOAT: + if (do_set) { + RNA_property_float_set_array(&self->ptr, self->prop, buf.buf); + } + else { + RNA_property_float_get_array(&self->ptr, self->prop, buf.buf); + } + break; + case PROP_BOOLEAN: + case PROP_STRING: + case PROP_ENUM: + case PROP_POINTER: + case PROP_COLLECTION: + /* Should never happen. */ + BLI_assert(false); + break; + } + + PyBuffer_Release(&buf); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pyrna_prop_array_foreach_get_doc, + ".. method:: foreach_get(seq)\n" + "\n" + " This is a function to give fast access to array data.\n"); +static PyObject *pyrna_prop_array_foreach_get(BPy_PropertyArrayRNA *self, PyObject *args) +{ + PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self); + + return pyprop_array_foreach_getset(self, args, false); +} + +PyDoc_STRVAR(pyrna_prop_array_foreach_set_doc, + ".. method:: foreach_set(seq)\n" + "\n" + " This is a function to give fast access to array data.\n"); +static PyObject *pyrna_prop_array_foreach_set(BPy_PropertyArrayRNA *self, PyObject *args) +{ + PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self); + + return pyprop_array_foreach_getset(self, args, true); +} + /* A bit of a kludge, make a list out of a collection or array, * then return the list's iter function, not especially fast, but convenient for now. */ static PyObject *pyrna_prop_array_iter(BPy_PropertyArrayRNA *self) @@ -5572,6 +5740,15 @@ static struct PyMethodDef pyrna_prop_methods[] = { }; static struct PyMethodDef pyrna_prop_array_methods[] = { + {"foreach_get", + (PyCFunction)pyrna_prop_array_foreach_get, + METH_VARARGS, + pyrna_prop_array_foreach_get_doc}, + {"foreach_set", + (PyCFunction)pyrna_prop_array_foreach_set, + METH_VARARGS, + pyrna_prop_array_foreach_set_doc}, + {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 88614de1641..38cba264a01 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -198,7 +198,7 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg); int RE_engine_render(struct Render *re, int do_all); -bool RE_engine_is_external(struct Render *re); +bool RE_engine_is_external(const struct Render *re); void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe); diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 3c089335115..fabbd5fb096 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -57,7 +57,7 @@ struct RenderResult *render_result_new_from_exr( void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); void render_result_view_new(struct RenderResult *rr, const char *viewname); -void render_result_views_new(struct RenderResult *rr, struct RenderData *rd); +void render_result_views_new(struct RenderResult *rr, const struct RenderData *rd); /* Merge */ @@ -110,7 +110,7 @@ bool render_result_exr_file_cache_read(struct Render *re); /* Combined Pixel Rect */ struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, - struct RenderData *rd, + const struct RenderData *rd, const int view_id); void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 598f300cf86..4fcb5f5f16e 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -116,7 +116,7 @@ RenderEngineType *RE_engines_find(const char *idname) return type; } -bool RE_engine_is_external(Render *re) +bool RE_engine_is_external(const Render *re) { return (re->engine && re->engine->type && re->engine->type->render); } diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 2021967b05d..4e20dd51122 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -798,7 +798,7 @@ void render_result_view_new(RenderResult *rr, const char *viewname) BLI_strncpy(rv->name, viewname, sizeof(rv->name)); } -void render_result_views_new(RenderResult *rr, RenderData *rd) +void render_result_views_new(RenderResult *rr, const RenderData *rd) { SceneRenderView *srv; @@ -1459,7 +1459,7 @@ bool render_result_exr_file_cache_read(Render *re) /*************************** Combined Pixel Rect *****************************/ -ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id) +ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const int view_id) { ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0); RenderView *rv = RE_RenderViewGetById(rr, view_id); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 83355ecb786..c8c86ade07a 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -113,6 +113,7 @@ #include "GHOST_Path-api.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -2817,7 +2818,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, void *UNUSED(arg1)) { wmWindowManager *wm = CTX_wm_manager(C); - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS); UI_block_flag_enable( @@ -3055,58 +3056,77 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, { wmGenericCallback *post_action = (wmGenericCallback *)arg1; Main *bmain = CTX_data_main(C); - uiStyle *style = UI_style_get(); - uiFontStyle *fs = &style->widgetlabel; + const uiStyle *style = UI_style_get_dpi(); + const int dialog_width = U.widget_unit * 22; + const short icon_size = 64 * U.dpi_fac; - /* Filename */ - const char *blendfile_pathpath = BKE_main_blendfile_path(bmain); - char filename[FILE_MAX]; - if (blendfile_pathpath[0] != '\0') { - BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename)); - BLI_path_extension_replace(filename, sizeof(filename), ""); - } - else { - STRNCPY(filename, IFACE_("Untitled")); - } + /* Calculate icon column factor. */ + const float split_factor = (float)icon_size / (float)(dialog_width - style->columnspace); - /* Title */ - char title[FILE_MAX + 100]; - UI_text_clip_middle_ex( - fs, filename, U.widget_unit * 9, U.widget_unit * 2, sizeof(filename), '\0'); - BLI_snprintf(title, sizeof(title), TIP_("Save changes to \"%s\" before closing?"), filename); - int title_width = MAX2(UI_fontstyle_string_width(fs, title), U.widget_unit * 22); - - /* Create dialog */ uiBlock *block = UI_block_begin(C, region, close_file_dialog_name, UI_EMBOSS); - style = UI_style_get_dpi(); UI_block_flag_enable( block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); UI_block_emboss_set(block, UI_EMBOSS); - uiLayout *layout = UI_block_layout(block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - 10, - 2, - U.widget_unit * 2 + title_width, - U.widget_unit * 6, - 0, - style); + uiLayout *block_layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); + + /* Split layout to put alert icon on left side. */ + uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); + + /* Alert Icon. */ + uiLayout *layout = uiLayoutColumn(split_block, false); + uiDefButAlert(block, ALERT_ICON_WARNING, 0, 0, 0, icon_size); - /* Title */ - uiItemL_ex(layout, title, ICON_ERROR, true, false); + /* The rest of the content on the right. */ + layout = uiLayoutColumn(split_block, false); - /* Image Saving */ + /* Title. */ + uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false); + + /* Filename. */ + const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C)); + char filename[FILE_MAX]; + if (blendfile_pathpath[0] != '\0') { + BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename)); + BLI_path_extension_replace(filename, sizeof(filename), ""); + } + else { + STRNCPY(filename, IFACE_("Untitled")); + } + uiItemL(layout, filename, ICON_NONE); + + /* Image Saving Warnings. */ ReportList reports; BKE_reports_init(&reports, RPT_STORE); uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports); LISTBASE_FOREACH (Report *, report, &reports.list) { - uiItemL_ex(layout, report->message, ICON_CANCEL, false, true); + uiLayout *row = uiLayoutColumn(layout, false); + uiLayoutSetScaleY(row, 0.6f); + uiItemS_ex(row, 1.2f); + + /* Error messages created in ED_image_save_all_modified_info() can be long, + * but are made to separate into two parts at first colon between text and paths. + */ + char *message = BLI_strdupn(report->message, report->len); + char *path_info = strstr(message, ": "); + if (path_info) { + /* Terminate message string at colon. */ + path_info[1] = '\0'; + /* Skip over the ": " */ + path_info += 2; + } + uiItemL_ex(row, message, ICON_NONE, false, true); + if (path_info) { + uiItemL_ex(row, path_info, ICON_NONE, false, true); + } + MEM_freeN(message); } + /* Modified Images Checkbox. */ if (modified_images_count > 0) { char message[64]; BLI_snprintf(message, @@ -3114,7 +3134,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, (modified_images_count == 1) ? "Save %u modified image" : "Save %u modified images", modified_images_count); - uiItemS(layout); + uiItemS_ex(layout, 2.0f); uiDefButBitC(block, UI_BTYPE_CHECKBOX, 1, @@ -3134,9 +3154,9 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, BKE_reports_clear(&reports); - uiItemS_ex(layout, 3.0f); + uiItemS_ex(layout, 1.0f); - /* Buttons */ + /* Buttons. */ #ifdef _WIN32 const bool windows_layout = true; #else @@ -3146,37 +3166,44 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, if (windows_layout) { /* Windows standard layout. */ - uiLayout *split = uiLayoutSplit(layout, 0.18f, true); + uiLayout *split = uiLayoutSplit(block_layout, 0.174f, true); uiLayoutSetScaleY(split, 1.2f); - uiLayout *col = uiLayoutColumn(split, false); - uiItemS(col); + uiLayoutColumn(split, false); + uiItemS(layout); - col = uiLayoutColumn(split, false); + uiLayoutColumn(split, false); wm_block_file_close_save_button(block, post_action); - col = uiLayoutColumn(split, false); + uiLayoutColumn(split, false); wm_block_file_close_discard_button(block, post_action); - col = uiLayoutColumn(split, false); + uiLayoutColumn(split, false); wm_block_file_close_cancel_button(block, post_action); } else { /* macOS and Linux standard layout. */ - uiLayout *split = uiLayoutSplit(layout, 0.0f, true); + uiLayout *split = uiLayoutSplit(block_layout, 0.167f, true); uiLayoutSetScaleY(split, 1.2f); - uiLayout *col = uiLayoutColumn(split, true); + layout = uiLayoutColumn(split, false); + uiItemS(layout); + + /* Split button area into two sections: 40/60. */ + uiLayout *mac_left = uiLayoutSplit(split, 0.40f, true); + + /* First button uses 75% of left side (30% of original). */ + uiLayoutSplit(mac_left, 0.75f, true); wm_block_file_close_discard_button(block, post_action); - col = uiLayoutColumn(split, true); - uiItemS(col); + /* The right side is split 50/50 (each 30% of original). */ + uiLayout *mac_right = uiLayoutSplit(mac_left, 0.50f, true); - col = uiLayoutColumn(split, true); + uiLayoutColumn(mac_right, false); wm_block_file_close_cancel_button(block, post_action); - col = uiLayoutColumn(split, false); + uiLayoutColumn(mac_right, false); wm_block_file_close_save_button(block, post_action); } diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 1cc9c82ec60..9dedab8cc55 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -76,17 +76,30 @@ struct wmJob { /** Should store entire own context, for start, update, free */ void *customdata; - /** To prevent cpu overhead, - * use this one which only gets called when job really starts, not in thread */ + /** + * To prevent cpu overhead, use this one which only gets called when job really starts. + * Executed in main thread. + */ void (*initjob)(void *); - /** This runs inside thread, and does full job */ + /** + * This performs the actual parallel work. + * Executed in worker thread(s). + */ void (*startjob)(void *, short *stop, short *do_update, float *progress); - /** Update gets called if thread defines so, and max once per timerstep - * it runs outside thread, blocking blender, no drawing! */ + /** + * Called if thread defines so (see `do_update` flag), and max once per timer step. + * Executed in main thread. + */ void (*update)(void *); - /** Free entire customdata, doesn't run in thread */ + /** + * Free callback (typically for customdata). + * Executed in main thread. + */ void (*free)(void *); - /** Gets called when job is stopped, not in thread */ + /** + * Called when job is stopped. + * Executed in main thread. + */ void (*endjob)(void *); /** Running jobs each have own timer */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index aab2acaac76..80116507c4a 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1319,7 +1319,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op) wmOperator *op = arg_op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); int width = 15 * UI_UNIT_X; block = UI_block_begin(C, region, __func__, UI_EMBOSS); @@ -1401,7 +1401,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *userD wmOperator *op = data->op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); block = UI_block_begin(C, region, __func__, UI_EMBOSS); UI_block_flag_disable(block, UI_BLOCK_LOOP); @@ -1450,7 +1450,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *region, void *userDa wmOperator *op = data->op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); block = UI_block_begin(C, region, __func__, UI_EMBOSS); UI_block_flag_disable(block, UI_BLOCK_LOOP); @@ -2308,7 +2308,7 @@ static void radial_control_paint_curve(uint pos, Brush *br, float radius, int li static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata) { RadialControl *rc = customdata; - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; short fstyle_points = fstyle->points; @@ -3516,7 +3516,7 @@ static int previews_clear_exec(bContext *C, wmOperator *op) BKE_idcode_to_idfilter(GS(id->name)) & id_filters); #endif - if (!id || !(BKE_idcode_to_idfilter(GS(id->name)) & id_filters)) { + if (!(BKE_idcode_to_idfilter(GS(id->name)) & id_filters)) { continue; } diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 51dccf5bb8b..ac5fd522664 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -525,9 +525,7 @@ static void build_pict_list_ex( BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) { - if (hasevent) { - GHOST_DispatchEvents(g_WS.ghost_system); - } + GHOST_DispatchEvents(g_WS.ghost_system); if (ps->loading == false) { return; } diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 97490f7cc3b..dcf09e9cbc5 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -81,7 +81,7 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, return; } - uiStyle *style = UI_style_get(); + const uiStyle *style = UI_style_get(); BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi); int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label)); @@ -259,7 +259,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE { uiBlock *block; uiBut *but; - uiStyle *style = UI_style_get_dpi(); + const uiStyle *style = UI_style_get_dpi(); block = UI_block_begin(C, region, "splash", UI_EMBOSS); @@ -272,21 +272,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE /* 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 * ibuf_unit_size[0], - U.dpi_fac * ibuf_unit_size[1], - /* Button owns the imbuf now. */ - ibuf, - 0.0, - 0.0, - 0, - 0, - ""); + but = uiDefButImage(block, + ibuf, + 0, + 0.5f * U.widget_unit, + U.dpi_fac * ibuf_unit_size[0], + U.dpi_fac * ibuf_unit_size[1], + NULL); UI_but_func_set(but, wm_block_splash_close, block, NULL); UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); |