diff options
Diffstat (limited to 'source')
184 files changed, 2890 insertions, 2572 deletions
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 394d97223e3..42897c59043 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -274,7 +274,7 @@ bool BKE_nurb_valid_message(int pnts, short flag, short type, bool is_surf, - const char *dir, + int dir, char *message_dst, size_t maxncpy); diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h index 189d2db1b4f..633af54ea4f 100644 --- a/source/blender/blenkernel/BKE_image_format.h +++ b/source/blender/blenkernel/BKE_image_format.h @@ -16,6 +16,7 @@ struct BlendWriter; struct ImbFormatOptions; struct ImageFormatData; struct ImBuf; +struct Scene; /* Init/Copy/Free */ @@ -75,6 +76,22 @@ char BKE_imtype_from_arg(const char *arg); void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf); void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf); +/* Color Management */ + +void BKE_image_format_color_management_copy(struct ImageFormatData *imf, + const struct ImageFormatData *imf_src); +void BKE_image_format_color_management_copy_from_scene(struct ImageFormatData *imf, + const struct Scene *scene); + +/* Image Output + * + * Initialize an image format that can be used for file writing, including + * color management settings from the scene. */ + +void BKE_image_format_init_for_write(struct ImageFormatData *imf, + const struct Scene *scene_src, + const struct ImageFormatData *imf_src); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h index f9d07387463..b022e677845 100644 --- a/source/blender/blenkernel/BKE_image_save.h +++ b/source/blender/blenkernel/BKE_image_save.h @@ -47,7 +47,7 @@ bool BKE_image_save(struct ReportList *reports, struct ImageUser *iuser, struct ImageSaveOptions *opts); -/* Lower level image writing. */ +/* Render saving. */ /* Save single or multilayer OpenEXR files from the render result. * Optionally saves only a specific view or layer. */ @@ -55,6 +55,7 @@ bool BKE_image_render_write_exr(struct ReportList *reports, const struct RenderResult *rr, const char *filename, const struct ImageFormatData *imf, + const bool save_as_render, const char *view, int layer); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index da436b7d33f..bf9e7651e36 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -13,6 +13,7 @@ struct Lattice; struct ListBase; struct Main; struct Mesh; +struct MVert; struct Object; /* Kernel prototypes */ @@ -119,7 +120,8 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb); void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb); -void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me); +void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct MVert *mvert, int totvert); + /** * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key. * diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2373bb289cd..0ba9713b96d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -472,6 +472,21 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert, float (*r_poly_normals)[3]); /** + * Calculate face and vertex normals directly into result arrays. + * + * \note Usually #BKE_mesh_vertex_normals_ensure is the preferred way to access vertex normals, + * since they may already be calculated and cached on the mesh. + */ +void BKE_mesh_calc_normals_poly_and_vertex(const struct MVert *mvert, + int mvert_len, + const struct MLoop *mloop, + int mloop_len, + const struct MPoly *mpoly, + int mpoly_len, + float (*r_poly_normals)[3], + float (*r_vert_normals)[3]); + +/** * Calculate vertex and face normals, storing the result in custom data layers on the mesh. * * \note It is usually preferable to calculate normals lazily with diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 5c2d77f20a8..0a6ef8f0f01 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2164,8 +2164,8 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m const float y = nor[1]; const float z = nor[2]; - float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */ - const float theta_alt = x * x + z * z; /* squared distance from origin in x,z plane. */ + float theta = 1.0f + y; /* Remapping Y from [-1,+1] to [0,2]. */ + const float theta_alt = x * x + z * z; /* Squared distance from origin in x,z plane. */ float rMatrix[3][3], bMatrix[3][3]; BLI_ASSERT_UNIT_V3(nor); diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 0b619c1a969..354ddd7d167 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -62,6 +62,14 @@ using blender::IndexRange; /* local */ // static CLG_LogRef LOG = {"bke.curve"}; +enum class NURBSValidationStatus { + Valid, + AtLeastTwoPointsRequired, + MorePointsThanOrderRequired, + MoreRowsForBezierRequired, + MorePointsForBezierRequired +}; + static void curve_init_data(ID *id) { Curve *curve = (Curve *)id; @@ -4700,56 +4708,94 @@ void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key) } } -bool BKE_nurb_valid_message(const int pnts, - const short order, - const short flag, - const short type, - const bool is_surf, - const char *dir, - char *message_dst, - const size_t maxncpy) +static NURBSValidationStatus nurb_check_valid(const int pnts, + const short order, + const short flag, + const short type, + const bool is_surf, + int *r_points_needed) { - const char *msg_template = ""; - uint16_t points_needed = 0; - if (pnts <= 1) { - msg_template = TIP_("At least two points required."); + return NURBSValidationStatus::AtLeastTwoPointsRequired; } else if (type == CU_NURBS) { if (pnts < order) { - msg_template = TIP_("Must have more control points than Order"); + return NURBSValidationStatus::MorePointsThanOrderRequired; } else if (flag & CU_NURB_BEZIER) { + int points_needed = 0; if (flag & CU_NURB_CYCLIC) { - const uint16_t remainder = pnts % (order - 1); + const int remainder = pnts % (order - 1); points_needed = remainder > 0 ? order - 1 - remainder : 0; } else if (((flag & CU_NURB_ENDPOINT) == 0) && pnts <= order) { points_needed = order + 1 - pnts; } if (points_needed) { - msg_template = is_surf ? TIP_("%d more %s row(s) needed for Bezier") : - TIP_("%d more point(s) needed for Bezier"); + *r_points_needed = points_needed; + return is_surf ? NURBSValidationStatus::MoreRowsForBezierRequired : + NURBSValidationStatus::MorePointsForBezierRequired; } } } + return NURBSValidationStatus::Valid; +} + +bool BKE_nurb_valid_message(const int pnts, + const short order, + const short flag, + const short type, + const bool is_surf, + const int dir, + char *message_dst, + const size_t maxncpy) +{ + int points_needed; + NURBSValidationStatus status = nurb_check_valid( + pnts, order, flag, type, is_surf, &points_needed); - if (message_dst) { - BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir); + const char *msg_template = nullptr; + switch (status) { + case NURBSValidationStatus::Valid: + message_dst[0] = 0; + return false; + case NURBSValidationStatus::AtLeastTwoPointsRequired: + if (dir == 1) { + /* Exception made for curves as their pntsv == 1. */ + message_dst[0] = 0; + return false; + } + msg_template = TIP_("At least two points required."); + break; + case NURBSValidationStatus::MorePointsThanOrderRequired: + msg_template = TIP_("Must have more control points than Order"); + break; + case NURBSValidationStatus::MoreRowsForBezierRequired: + msg_template = TIP_("%d more %s row(s) needed for Bezier"); + break; + case NURBSValidationStatus::MorePointsForBezierRequired: + msg_template = TIP_("%d more point(s) needed for Bezier"); + break; } - return msg_template[0]; + + BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V"); + return true; } bool BKE_nurb_check_valid_u(const Nurb *nu) { - return !BKE_nurb_valid_message( - nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, "U", nullptr, 0); + int points_needed; + return NURBSValidationStatus::Valid == + nurb_check_valid( + nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, &points_needed); } bool BKE_nurb_check_valid_v(const Nurb *nu) { - return !BKE_nurb_valid_message( - nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, "V", nullptr, 0); + int points_needed; + return NURBSValidationStatus::Valid == + nurb_check_valid( + nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, &points_needed); } bool BKE_nurb_check_valid_uv(const Nurb *nu) diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index f0400417ffc..44aa9e21195 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -14,6 +14,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -732,7 +733,7 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf) } #endif else { - /* R_IMF_IMTYPE_JPEG90, etc. default we save jpegs */ + /* #R_IMF_IMTYPE_JPEG90, etc. default to JPEG. */ if (quality < 10) { quality = 90; } @@ -872,3 +873,58 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf) /* planes */ im_format->planes = imbuf->planes; } + +/* Color Management */ + +void BKE_image_format_color_management_copy(ImageFormatData *imf, const ImageFormatData *imf_src) +{ + BKE_color_managed_view_settings_free(&imf->view_settings); + + BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings); + BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings, + &imf_src->linear_colorspace_settings); +} + +void BKE_image_format_color_management_copy_from_scene(ImageFormatData *imf, const Scene *scene) +{ + BKE_color_managed_view_settings_free(&imf->view_settings); + + BKE_color_managed_display_settings_copy(&imf->display_settings, &scene->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &scene->view_settings); + STRNCPY(imf->linear_colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR)); +} + +/* Output */ + +void BKE_image_format_init_for_write(ImageFormatData *imf, + const Scene *scene_src, + const ImageFormatData *imf_src) +{ + *imf = (imf_src) ? *imf_src : scene_src->r.im_format; + + if (imf_src && imf_src->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + /* Use settings specific to one node, image save operation, etc. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings); + BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings, + &imf_src->linear_colorspace_settings); + } + else if (scene_src->r.im_format.color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + /* Use scene settings specific to render output. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, + &scene_src->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, + &scene_src->r.im_format.view_settings); + BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings, + &scene_src->r.im_format.linear_colorspace_settings); + } + else { + /* Use general scene settings also used for display. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, &scene_src->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &scene_src->view_settings); + STRNCPY(imf->linear_colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR)); + } +} diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index f6ea814cbc0..f530183f967 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -11,6 +11,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_vector.hh" #include "DNA_image_types.h" @@ -31,6 +32,8 @@ #include "RE_pipeline.h" +using blender::Vector; + void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene) { memset(opts, 0, sizeof(*opts)); @@ -220,18 +223,19 @@ static bool image_save_single(ReportList *reports, /* fancy multiview OpenEXR */ if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { /* save render result */ - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } /* regular mono pipeline */ else if (is_mono) { if (is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); } else { - colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( - ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); + colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf); ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy); imbuf_save_post(ibuf, colormanaged_ibuf); } @@ -262,7 +266,8 @@ static bool image_save_single(ReportList *reports, if (is_exr_rr) { BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); - ok_view = BKE_image_render_write_exr(reports, rr, filepath, imf, view, layer); + ok_view = BKE_image_render_write_exr( + reports, rr, filepath, imf, save_as_render, view, layer); image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); } else { @@ -292,8 +297,7 @@ static bool image_save_single(ReportList *reports, BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); - colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( - ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); + colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf); ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy); imbuf_save_post(ibuf, colormanaged_ibuf); image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); @@ -309,7 +313,8 @@ static bool image_save_single(ReportList *reports, /* stereo (multiview) images */ else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } @@ -358,8 +363,7 @@ static bool image_save_single(ReportList *reports, ibuf->planes = planes; /* color manage the ImBuf leaving it ready for saving */ - colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( - ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); + colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf); BKE_image_format_to_imbuf(colormanaged_ibuf, imf); IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf); @@ -453,10 +457,38 @@ bool BKE_image_save( /* OpenEXR saving, single and multilayer. */ +static float *image_exr_from_scene_linear_to_output(float *rect, + const int width, + const int height, + const int channels, + const ImageFormatData *imf, + Vector<float *> &tmp_output_rects) +{ + if (imf == nullptr) { + return rect; + } + + const char *to_colorspace = imf->linear_colorspace_settings.name; + if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) { + return rect; + } + + float *output_rect = (float *)MEM_dupallocN(rect); + tmp_output_rects.append(output_rect); + + const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get( + COLOR_ROLE_SCENE_LINEAR); + IMB_colormanagement_transform( + output_rect, width, height, channels, from_colorspace, to_colorspace, false); + + return output_rect; +} + bool BKE_image_render_write_exr(ReportList *reports, const RenderResult *rr, - const char *filename, + const char *filepath, const ImageFormatData *imf, + const bool save_as_render, const char *view, int layer) { @@ -464,6 +496,7 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16); const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR); const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF)); + Vector<float *> tmp_output_rects; /* Write first layer if not multilayer and no layer was specified. */ if (!multi_layer && layer == -1) { @@ -501,7 +534,10 @@ bool BKE_image_render_write_exr(ReportList *reports, continue; } - float *output_rect = rview->rectf; + float *output_rect = (save_as_render) ? + image_exr_from_scene_linear_to_output( + rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rview->rectf; for (int a = 0; a < 4; a++) { char passname[EXR_PASS_MAXNAME]; @@ -559,7 +595,11 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A")); const bool pass_half_float = half_float && pass_RGBA; - float *output_rect = rp->rect; + /* Colorspace conversion only happens on RGBA passes. */ + float *output_rect = (save_as_render && pass_RGBA) ? + image_exr_from_scene_linear_to_output( + rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rp->rect; for (int a = 0; a < rp->channels; a++) { /* Save Combined as RGBA if single layer save. */ @@ -590,11 +630,11 @@ bool BKE_image_render_write_exr(ReportList *reports, errno = 0; - BLI_make_existing_file(filename); + BLI_make_existing_file(filepath); int compress = (imf ? imf->exr_codec : 0); bool success = IMB_exr_begin_write( - exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data); + exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data); if (success) { IMB_exr_write_channels(exrhandle); } @@ -604,6 +644,10 @@ bool BKE_image_render_write_exr(ReportList *reports, reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno)); } + for (float *rect : tmp_output_rects) { + MEM_freeN(rect); + } + IMB_exr_close(exrhandle); return success; } @@ -652,26 +696,27 @@ bool BKE_image_render_write(ReportList *reports, const char *filename) { bool ok = true; - const RenderData *rd = &scene->r; if (!rr) { return false; } + ImageFormatData image_format; + BKE_image_format_init_for_write(&image_format, scene, nullptr); + const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; - const bool is_exr_rr = ELEM(rd->im_format.imtype, - R_IMF_IMTYPE_OPENEXR, - R_IMF_IMTYPE_MULTILAYER) && + const bool is_exr_rr = ELEM( + image_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); const float dither = scene->r.dither_intensity; - if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, filename, &rd->im_format, nullptr, -1); + if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { + ok = BKE_image_render_write_exr(reports, rr, filename, &image_format, true, nullptr, -1); image_render_print_save_message(reports, filename, ok, errno); } /* mono, legacy code */ - else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + else if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { int view_id = 0; for (const RenderView *rv = (const RenderView *)rr->views.first; rv; rv = rv->next, view_id++) { @@ -684,37 +729,35 @@ bool BKE_image_render_write(ReportList *reports, } if (is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, filepath, &rd->im_format, rv->name, -1); + ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, true, rv->name, -1); image_render_print_save_message(reports, filepath, ok, errno); /* optional preview images for exr */ - if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = rd->im_format; - imf.imtype = R_IMF_IMTYPE_JPEG90; + if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + image_format.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; } - BKE_image_path_ensure_ext_from_imformat(filepath, &imf); + BKE_image_path_ensure_ext_from_imformat(filepath, &image_format); - ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &imf, dither, view_id); + ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id); ibuf->planes = 24; - IMB_colormanagement_imbuf_for_write( - ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf); + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format); - ok = image_render_write_stamp_test(reports, scene, rr, ibuf, filepath, &imf, stamp); + ok = image_render_write_stamp_test( + reports, scene, rr, ibuf, filepath, &image_format, stamp); IMB_freeImBuf(ibuf); } } else { - ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); + ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id); - IMB_colormanagement_imbuf_for_write( - ibuf, true, false, &scene->view_settings, &scene->display_settings, &rd->im_format); + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format); ok = image_render_write_stamp_test( - reports, scene, rr, ibuf, filepath, &rd->im_format, stamp); + reports, scene, rr, ibuf, filepath, &image_format, stamp); /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); @@ -722,12 +765,12 @@ bool BKE_image_render_write(ReportList *reports, } } else { /* R_IMF_VIEWS_STEREO_3D */ - BLI_assert(rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D); + BLI_assert(image_format.views_format == R_IMF_VIEWS_STEREO_3D); char filepath[FILE_MAX]; STRNCPY(filepath, filename); - if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) { printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath); } else { @@ -737,34 +780,29 @@ bool BKE_image_render_write(ReportList *reports, for (i = 0; i < 2; i++) { int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); - ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); - IMB_colormanagement_imbuf_for_write(ibuf_arr[i], - true, - false, - &scene->view_settings, - &scene->display_settings, - &rd->im_format); + ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id); + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format); IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]); } - ibuf_arr[2] = IMB_stereo3d_ImBuf(&rd->im_format, ibuf_arr[0], ibuf_arr[1]); + ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]); ok = image_render_write_stamp_test( - reports, scene, rr, ibuf_arr[2], filepath, &rd->im_format, stamp); + reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp); /* optional preview images for exr */ - if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = rd->im_format; - imf.imtype = R_IMF_IMTYPE_JPEG90; + if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + image_format.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_path_extension_check(filepath, ".exr")) { filepath[strlen(filepath) - 4] = 0; } - BKE_image_path_ensure_ext_from_imformat(filepath, &imf); + BKE_image_path_ensure_ext_from_imformat(filepath, &image_format); ibuf_arr[2]->planes = 24; - ok = image_render_write_stamp_test(reports, scene, rr, ibuf_arr[2], filepath, &imf, stamp); + ok = image_render_write_stamp_test( + reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp); } /* imbuf knows which rects are not part of ibuf */ @@ -774,5 +812,7 @@ bool BKE_image_render_write(ReportList *reports, } } + BKE_image_format_free(&image_format); + return ok; } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 11d6e6ef973..5247e9f358b 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -2171,16 +2171,14 @@ void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb) BKE_keyblock_update_from_mesh(me, kb); } -void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me) +void BKE_keyblock_convert_to_mesh(KeyBlock *kb, struct MVert *mvert, int totvert) { - MVert *mvert; const float(*fp)[3]; int a, tot; - mvert = me->mvert; fp = kb->data; - tot = min_ii(kb->totelem, me->totvert); + tot = min_ii(kb->totelem, totvert); for (a = 0; a < tot; a++, fp++, mvert++) { copy_v3_v3(mvert->co, *fp); @@ -2193,68 +2191,77 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb, float (*r_polynors)[3], float (*r_loopnors)[3]) { - /* We use a temp, shallow copy of mesh to work. */ - Mesh me; - bool free_polynors = false; - if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) { return; } - me = *mesh; - me.mvert = MEM_dupallocN(mesh->mvert); - CustomData_reset(&me.vdata); - CustomData_reset(&me.edata); - CustomData_reset(&me.pdata); - CustomData_reset(&me.ldata); - CustomData_reset(&me.fdata); - - BKE_keyblock_convert_to_mesh(kb, &me); - - if (r_polynors == NULL && r_loopnors != NULL) { - r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__); - free_polynors = true; - } - - const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh); - if (r_vertnors) { - memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert); - } - - const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh); - memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly); - - if (r_loopnors) { + MVert *mvert = MEM_dupallocN(mesh->mvert); + BKE_keyblock_convert_to_mesh(kb, mesh->mvert, mesh->totvert); + + const bool loop_normals_needed = r_loopnors != NULL; + const bool vert_normals_needed = r_vertnors != NULL || loop_normals_needed; + const bool poly_normals_needed = r_polynors != NULL || vert_normals_needed || + loop_normals_needed; + + float(*vert_normals)[3] = r_vertnors; + float(*poly_normals)[3] = r_polynors; + bool free_vert_normals = false; + bool free_poly_normals = false; + if (vert_normals_needed && r_vertnors == NULL) { + vert_normals = MEM_malloc_arrayN(mesh->totvert, sizeof(float[3]), __func__); + free_vert_normals = true; + } + if (poly_normals_needed && r_polynors == NULL) { + poly_normals = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); + free_poly_normals = true; + } + + if (poly_normals_needed) { + BKE_mesh_calc_normals_poly(mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + poly_normals); + } + if (vert_normals_needed) { + BKE_mesh_calc_normals_poly_and_vertex(mvert, + mesh->totvert, + mesh->mloop, + mesh->totloop, + mesh->mpoly, + mesh->totpoly, + poly_normals, + vert_normals); + } + if (loop_normals_needed) { short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */ - - BKE_mesh_normals_loop_split(me.mvert, + BKE_mesh_normals_loop_split(mesh->mvert, vert_normals, - me.totvert, - me.medge, - me.totedge, - me.mloop, + mesh->totvert, + mesh->medge, + mesh->totedge, + mesh->mloop, r_loopnors, - me.totloop, - me.mpoly, - face_normals, - me.totpoly, - (me.flag & ME_AUTOSMOOTH) != 0, - me.smoothresh, + mesh->totloop, + mesh->mpoly, + poly_normals, + mesh->totpoly, + (mesh->flag & ME_AUTOSMOOTH) != 0, + mesh->smoothresh, NULL, clnors, NULL); } - CustomData_free(&me.vdata, me.totvert); - CustomData_free(&me.edata, me.totedge); - CustomData_free(&me.pdata, me.totpoly); - CustomData_free(&me.ldata, me.totloop); - CustomData_free(&me.fdata, me.totface); - MEM_freeN(me.mvert); - - if (free_polynors) { - MEM_freeN(r_polynors); + if (free_vert_normals) { + MEM_freeN(vert_normals); + } + if (free_poly_normals) { + MEM_freeN(poly_normals); } + MEM_freeN(mvert); } /************************* raw coords ************************/ diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index e6838264be8..782d5442c99 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1166,6 +1166,7 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, { BMeshFromMeshParams bmesh_from_mesh_params{}; bmesh_from_mesh_params.calc_face_normal = false; + bmesh_from_mesh_params.calc_vert_normal = false; bmesh_from_mesh_params.add_key_index = add_key_index; bmesh_from_mesh_params.use_shapekey = true; bmesh_from_mesh_params.active_shapekey = ob->shapenr; diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 1542f7119d1..40c6fbcf67e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -1308,7 +1308,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, if (build_shapekey_layers && me->key && (kb = (KeyBlock *)BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) { - BKE_keyblock_convert_to_mesh(kb, me); + BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert); } Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE); diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c index da23aea43f3..9202690b3c9 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.c +++ b/source/blender/blenkernel/intern/mesh_mirror.c @@ -46,6 +46,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm &(struct BMeshCreateParams){0}, &(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, @@ -92,6 +93,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain, }, &(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, .cd_mask_extra = { .vmask = CD_MASK_SHAPEKEY, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 1c2a903d8c3..7633a3155ba 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -306,14 +306,14 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn( } } -static void mesh_calc_normals_poly_and_vertex(const MVert *mvert, - const int mvert_len, - const MLoop *mloop, - const int UNUSED(mloop_len), - const MPoly *mpoly, - const int mpoly_len, - float (*r_poly_normals)[3], - float (*r_vert_normals)[3]) +void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert, + const int mvert_len, + const MLoop *mloop, + const int UNUSED(mloop_len), + const MPoly *mpoly, + const int mpoly_len, + float (*r_poly_normals)[3], + float (*r_vert_normals)[3]) { TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); @@ -372,14 +372,14 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3] vert_normals = BKE_mesh_vertex_normals_for_write(&mesh_mutable); poly_normals = BKE_mesh_poly_normals_for_write(&mesh_mutable); - mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert, - mesh_mutable.totvert, - mesh_mutable.mloop, - mesh_mutable.totloop, - mesh_mutable.mpoly, - mesh_mutable.totpoly, - poly_normals, - vert_normals); + BKE_mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert, + mesh_mutable.totvert, + mesh_mutable.mloop, + mesh_mutable.totloop, + mesh_mutable.mpoly, + mesh_mutable.totpoly, + poly_normals, + vert_normals); BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable); BKE_mesh_poly_normals_clear_dirty(&mesh_mutable); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index b34a241bca8..3c7992ec3d7 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -401,6 +401,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh) BMeshFromMeshParams bmesh_from_mesh_params{}; bmesh_from_mesh_params.calc_face_normal = true; + bmesh_from_mesh_params.calc_vert_normal = true; BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params); BMVert *v; diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index 80926bfc1e2..cad680ecedd 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -869,6 +869,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh) mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); return bm; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 985c9edac1a..1e3b5d77fa7 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -4630,9 +4630,11 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb) if (key->refkey) { /* apply new basis key on original data */ switch (ob->type) { - case OB_MESH: - BKE_keyblock_convert_to_mesh(key->refkey, (Mesh *)ob->data); + case OB_MESH: { + Mesh *mesh = (Mesh *)ob->data; + BKE_keyblock_convert_to_mesh(key->refkey, mesh->mvert, mesh->totvert); break; + } case OB_CURVES_LEGACY: case OB_SURF: BKE_keyblock_convert_to_curve( diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 4bba84f2e29..c31e3045c97 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -202,7 +202,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]); * \return the lowest squared distance to either of the planes. * where `(return < 0.0)` is outside. * - * <pre> + * \code{.unparsed} * v1 * + * / @@ -211,7 +211,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]); * +----+ * v2 v3 * x - also outside - * </pre> + * \endcode */ float dist_signed_squared_to_corner_v3v3v3(const float p[3], const float v1[3], @@ -322,18 +322,22 @@ double closest_to_line_v2_db(double r_close[2], float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); /** * Point closest to v1 on line v2-v3 in 2D. + * + * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment. */ -void closest_to_line_segment_v2(float r_close[2], - const float p[2], - const float l1[2], - const float l2[2]); +float closest_to_line_segment_v2(float r_close[2], + const float p[2], + const float l1[2], + const float l2[2]); /** * Point closest to v1 on line v2-v3 in 3D. + * + * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment. */ -void closest_to_line_segment_v3(float r_close[3], - const float p[3], - const float l1[3], - const float l2[3]); +float closest_to_line_segment_v3(float r_close[3], + const float p[3], + const float l1[3], + const float l2[3]); void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]); /** * Find the closest point on a plane. diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index bc3ed099fd5..e1ec22063e0 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -294,46 +294,48 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2)); } -void closest_to_line_segment_v2(float r_close[2], - const float p[2], - const float l1[2], - const float l2[2]) +float closest_to_line_segment_v2(float r_close[2], + const float p[2], + const float l1[2], + const float l2[2]) { float lambda, cp[2]; lambda = closest_to_line_v2(cp, p, l1, l2); /* flip checks for !finite case (when segment is a point) */ - if (!(lambda > 0.0f)) { + if (lambda <= 0.0f) { copy_v2_v2(r_close, l1); + return 0.0f; } - else if (!(lambda < 1.0f)) { + if (lambda >= 1.0f) { copy_v2_v2(r_close, l2); + return 1.0f; } - else { - copy_v2_v2(r_close, cp); - } + copy_v2_v2(r_close, cp); + return lambda; } -void closest_to_line_segment_v3(float r_close[3], - const float p[3], - const float l1[3], - const float l2[3]) +float closest_to_line_segment_v3(float r_close[3], + const float p[3], + const float l1[3], + const float l2[3]) { float lambda, cp[3]; lambda = closest_to_line_v3(cp, p, l1, l2); /* flip checks for !finite case (when segment is a point) */ - if (!(lambda > 0.0f)) { + if (lambda <= 0.0f) { copy_v3_v3(r_close, l1); + return 0.0f; } - else if (!(lambda < 1.0f)) { + if (lambda >= 1.0f) { copy_v3_v3(r_close, l2); + return 1.0f; } - else { - copy_v3_v3(r_close, cp); - } + copy_v3_v3(r_close, cp); + return lambda; } void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]) diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc index 35a111f04db..8c310645d6d 100644 --- a/source/blender/blenlib/tests/BLI_math_vector_test.cc +++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc @@ -85,4 +85,4 @@ TEST(math_vector, Clamp) EXPECT_EQ(result_2.z, -50); } -} // namespace blender::tests
\ No newline at end of file +} // namespace blender::tests diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 0d16cc9dffd..a5994b52bc2 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -17,7 +17,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm); void BM_mesh_elem_toolflags_clear(BMesh *bm); struct BMeshCreateParams { - uint use_toolflags : 1; + bool use_toolflags : true; }; /** diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index fd14a3416e2..118e7751cbc 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -229,7 +229,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps * in edit mode. */ const float(*vert_normals)[3] = nullptr; - if (!BKE_mesh_vertex_normals_are_dirty(me)) { + if (params->calc_vert_normal) { vert_normals = BKE_mesh_vertex_normals_ensure(me); } diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h index 0bd70749cb1..cc1ad71549d 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.h +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h @@ -18,11 +18,12 @@ void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag); char BM_mesh_cd_flag_from_bmesh(BMesh *bm); struct BMeshFromMeshParams { - uint calc_face_normal : 1; + bool calc_face_normal : true; + bool calc_vert_normal : true; /* add a vertex CD_SHAPE_KEYINDEX layer */ - uint add_key_index : 1; + bool add_key_index : true; /* set vertex coordinates from the shapekey */ - uint use_shapekey : 1; + bool use_shapekey : true; /* define the active shape key (index + 1) */ int active_shapekey; struct CustomData_MeshMasks cd_mask_extra; @@ -42,7 +43,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFrom struct BMeshToMeshParams { /** Update object hook indices & vertex parents. */ - uint calc_object_remap : 1; + bool calc_object_remap : true; /** * This re-assigns shape-key indices. Only do if the BMesh will have continued use * to update the mesh & shape key in the future. @@ -52,12 +53,12 @@ struct BMeshToMeshParams { * so a second flush or edit-mode exit doesn't run with indices * that have become invalid from updating the shape-key, see T71865. */ - uint update_shapekey_indices : 1; + bool update_shapekey_indices : true; /** * Instead of copying the basis shape-key into the #MVert array, * copy the #BMVert.co directly to #MVert.co (used for reading undo data). */ - uint active_shapekey_to_mvert : 1; + bool active_shapekey_to_mvert : true; struct CustomData_MeshMasks cd_mask_extra; }; /** diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index 1bc5b70f874..8bc16324971 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -1869,7 +1869,7 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len) for (int i = 0; i < len; i++) { BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) { - /* Check if all vers in this face are flagged. */ + /* Check if all verts in this face are flagged. */ BMLoop *l_iter, *l_first; if (is_init == false) { diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index eafa6614d31..0fdd7647f8d 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -318,12 +318,6 @@ extern "C" { * - output nodes can have different priorities in the WorkScheduler. * This is implemented in the COM_execute function. * - * \param view_settings: - * reference to view settings used for color management - * - * \param display_settings: - * reference to display settings used for color management - * * OCIO_TODO: this options only used in rare cases, namely in output file node, * so probably this settings could be passed in a nicer way. * should be checked further, probably it'll be also needed for preview @@ -335,8 +329,6 @@ void COM_execute(RenderData *render_data, Scene *scene, bNodeTree *node_tree, int rendering, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name); /** diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc index f17a24c6b9d..2c55af1779a 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.cc +++ b/source/blender/compositor/intern/COM_CompositorContext.cc @@ -12,8 +12,6 @@ CompositorContext::CompositorContext() quality_ = eCompositorQuality::High; hasActiveOpenCLDevices_ = false; fast_calculation_ = false; - view_settings_ = nullptr; - display_settings_ = nullptr; bnodetree_ = nullptr; } diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index 430bab48352..480f70f4193 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -64,10 +64,6 @@ class CompositorContext { */ bool fast_calculation_; - /* \brief color management settings */ - const ColorManagedViewSettings *view_settings_; - const ColorManagedDisplaySettings *display_settings_; - /** * \brief active rendering view name */ @@ -153,38 +149,6 @@ class CompositorContext { } /** - * \brief set view settings of color management - */ - void set_view_settings(const ColorManagedViewSettings *view_settings) - { - view_settings_ = view_settings; - } - - /** - * \brief get view settings of color management - */ - const ColorManagedViewSettings *get_view_settings() const - { - return view_settings_; - } - - /** - * \brief set display settings of color management - */ - void set_display_settings(const ColorManagedDisplaySettings *display_settings) - { - display_settings_ = display_settings; - } - - /** - * \brief get display settings of color management - */ - const ColorManagedDisplaySettings *get_display_settings() const - { - return display_settings_; - } - - /** * \brief set the quality */ void set_quality(eCompositorQuality quality) diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc index 036e2bc8a91..c850585148a 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cc +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc @@ -23,8 +23,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool rendering, bool fastcalculation, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name) { num_work_threads_ = WorkScheduler::get_num_cpu_threads(); @@ -45,8 +43,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, (editingtree->flag & NTREE_COM_OPENCL)); context_.set_render_data(rd); - context_.set_view_settings(view_settings); - context_.set_display_settings(display_settings); BLI_mutex_init(&work_mutex_); BLI_condition_init(&work_finished_cond_); diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 9dd20d18144..2cd9e2d9001 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -160,8 +160,6 @@ class ExecutionSystem { bNodeTree *editingtree, bool rendering, bool fastcalculation, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name); /** diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc index 2f27699ce9c..788686f3036 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc @@ -221,8 +221,9 @@ PreviewOperation *NodeOperationBuilder::make_preview_operation() const bNodeInstanceHash *previews = context_->get_preview_hash(); if (previews) { - PreviewOperation *operation = new PreviewOperation(context_->get_view_settings(), - context_->get_display_settings(), + Scene *scene = context_->get_scene(); + PreviewOperation *operation = new PreviewOperation(&scene->view_settings, + &scene->display_settings, current_node_->get_bnode()->preview_xsize, current_node_->get_bnode()->preview_ysize); operation->set_bnodetree(context_->get_bnodetree()); diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc index 791cc327bfb..519ad93bcaf 100644 --- a/source/blender/compositor/intern/COM_compositor.cc +++ b/source/blender/compositor/intern/COM_compositor.cc @@ -49,8 +49,6 @@ void COM_execute(RenderData *render_data, Scene *scene, bNodeTree *node_tree, int rendering, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name) { /* Initialize mutex, TODO: this mutex init is actually not thread safe and @@ -80,14 +78,8 @@ void COM_execute(RenderData *render_data, /* Execute. */ const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; if (twopass) { - blender::compositor::ExecutionSystem fast_pass(render_data, - scene, - node_tree, - rendering, - true, - view_settings, - display_settings, - view_name); + blender::compositor::ExecutionSystem fast_pass( + render_data, scene, node_tree, rendering, true, view_name); fast_pass.execute(); if (node_tree->test_break(node_tree->tbh)) { @@ -97,7 +89,7 @@ void COM_execute(RenderData *render_data, } blender::compositor::ExecutionSystem system( - render_data, scene, node_tree, rendering, false, view_settings, display_settings, view_name); + render_data, scene, node_tree, rendering, false, view_name); system.execute(); BLI_mutex_unlock(&g_compositor.mutex); diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc index ab5898c526d..f69511d88e6 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cc +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc @@ -106,36 +106,33 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter, if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) { output_operation = new OutputOpenExrSingleLayerMultiViewOperation( + context.get_scene(), context.get_render_data(), context.get_bnodetree(), input->get_data_type(), format, path, - context.get_view_settings(), - context.get_display_settings(), context.get_view_name(), sockdata->save_as_render); } else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) { - output_operation = new OutputSingleLayerOperation(context.get_render_data(), + output_operation = new OutputSingleLayerOperation(context.get_scene(), + context.get_render_data(), context.get_bnodetree(), input->get_data_type(), format, path, - context.get_view_settings(), - context.get_display_settings(), context.get_view_name(), sockdata->save_as_render); } else { /* R_IMF_VIEWS_STEREO_3D */ - output_operation = new OutputStereoOperation(context.get_render_data(), + output_operation = new OutputStereoOperation(context.get_scene(), + context.get_render_data(), context.get_bnodetree(), input->get_data_type(), format, path, sockdata->layer, - context.get_view_settings(), - context.get_display_settings(), context.get_view_name(), sockdata->save_as_render); } diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc index 0e7db05980a..d02bc6e773d 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cc +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc @@ -24,6 +24,7 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter, NodeInput *image2Socket = this->get_input_socket(1); Image *image = (Image *)this->get_bnode()->id; ImageUser *image_user = (ImageUser *)this->get_bnode()->storage; + Scene *scene = context.get_scene(); SplitOperation *split_viewer_operation = new SplitOperation(); split_viewer_operation->set_split_percentage(this->get_bnode()->custom1); @@ -36,8 +37,8 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter, ViewerOperation *viewer_operation = new ViewerOperation(); viewer_operation->set_image(image); viewer_operation->set_image_user(image_user); - viewer_operation->set_view_settings(context.get_view_settings()); - viewer_operation->set_display_settings(context.get_display_settings()); + viewer_operation->set_view_settings(&scene->view_settings); + viewer_operation->set_display_settings(&scene->display_settings); viewer_operation->set_render_data(context.get_render_data()); viewer_operation->set_view_name(context.get_view_name()); diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc index 216df59cc47..be5f7b90e11 100644 --- a/source/blender/compositor/nodes/COM_TextureNode.cc +++ b/source/blender/compositor/nodes/COM_TextureNode.cc @@ -17,8 +17,7 @@ void TextureNode::convert_to_operations(NodeConverter &converter, bNode *editor_node = this->get_bnode(); Tex *texture = (Tex *)editor_node->id; TextureOperation *operation = new TextureOperation(); - const ColorManagedDisplaySettings *display_settings = context.get_display_settings(); - bool scene_color_manage = !STREQ(display_settings->display_device, "None"); + bool scene_color_manage = !STREQ(context.get_scene()->display_settings.display_device, "None"); operation->set_texture(texture); operation->set_render_data(context.get_render_data()); operation->set_scene_color_manage(scene_color_manage); diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc index 1b335abc4d7..ebef331c62f 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.cc +++ b/source/blender/compositor/nodes/COM_ViewerNode.cc @@ -37,8 +37,9 @@ void ViewerNode::convert_to_operations(NodeConverter &converter, viewer_operation->set_render_data(context.get_render_data()); viewer_operation->set_view_name(context.get_view_name()); - viewer_operation->set_view_settings(context.get_view_settings()); - viewer_operation->set_display_settings(context.get_display_settings()); + Scene *scene = context.get_scene(); + viewer_operation->set_view_settings(&scene->view_settings); + viewer_operation->set_display_settings(&scene->display_settings); viewer_operation->set_canvas_input_index(0); if (!image_socket->is_linked()) { diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc index 4da11cc9053..aeaf6b659e3 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc @@ -17,24 +17,16 @@ namespace blender::compositor { /************************************ OpenEXR Singlelayer Multiview ******************************/ OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation( + const Scene *scene, const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name, const bool save_as_render) - : OutputSingleLayerOperation(rd, - tree, - datatype, - format, - path, - view_settings, - display_settings, - view_name, - save_as_render) + : OutputSingleLayerOperation( + scene, rd, tree, datatype, format, path, view_name, save_as_render) { } @@ -68,7 +60,7 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam /* prepare the file with all the channels */ - if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_->exr_codec, nullptr)) { + if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_.exr_codec, nullptr)) { printf("Error Writing Singlelayer Multiview Openexr\n"); IMB_exr_close(exrhandle); } @@ -104,7 +96,7 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinit_execution() datatype_, view_name_, width, - format_->depth == R_IMF_CHAN_DEPTH_16, + format_.depth == R_IMF_CHAN_DEPTH_16, output_buffer_); /* memory can only be freed after we write all views to the file */ @@ -247,25 +239,17 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinit_execution() /******************************** Stereo3D ******************************/ -OutputStereoOperation::OutputStereoOperation(const RenderData *rd, +OutputStereoOperation::OutputStereoOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, const char *name, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name, const bool save_as_render) - : OutputSingleLayerOperation(rd, - tree, - datatype, - format, - path, - view_settings, - display_settings, - view_name, - save_as_render) + : OutputSingleLayerOperation( + scene, rd, tree, datatype, format, path, view_name, save_as_render) { BLI_strncpy(name_, name, sizeof(name_)); channels_ = get_datatype_size(datatype); @@ -317,7 +301,7 @@ void OutputStereoOperation::deinit_execution() 1, channels_ * width * height, buf, - format_->depth == R_IMF_CHAN_DEPTH_16); + format_.depth == R_IMF_CHAN_DEPTH_16); image_input_ = nullptr; output_buffer_ = nullptr; @@ -332,7 +316,7 @@ void OutputStereoOperation::deinit_execution() /* get rectf from EXR */ for (i = 0; i < 2; i++) { float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, name_, names[i]); - ibuf[i] = IMB_allocImBuf(width, height, format_->planes, 0); + ibuf[i] = IMB_allocImBuf(width, height, format_.planes, 0); ibuf[i]->channels = channels_; ibuf[i]->rect_float = rectf; @@ -340,24 +324,23 @@ void OutputStereoOperation::deinit_execution() ibuf[i]->dither = rd_->dither_intensity; /* do colormanagement in the individual views, so it doesn't need to do in the stereo */ - IMB_colormanagement_imbuf_for_write( - ibuf[i], true, false, view_settings_, display_settings_, format_); + IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, &format_); IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]); } /* create stereo buffer */ - ibuf[2] = IMB_stereo3d_ImBuf(format_, ibuf[0], ibuf[1]); + ibuf[2] = IMB_stereo3d_ImBuf(&format_, ibuf[0], ibuf[1]); BKE_image_path_from_imformat(filename, path_, BKE_main_blendfile_path_from_global(), rd_->cfra, - format_, + &format_, (rd_->scemode & R_EXTENSION) != 0, true, nullptr); - BKE_imbuf_write(ibuf[2], filename, format_); + BKE_imbuf_write(ibuf[2], filename, &format_); /* imbuf knows which rects are not part of ibuf */ for (i = 0; i < 3; i++) { diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h index 6d36db3b777..69f4011d340 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h @@ -18,13 +18,12 @@ namespace blender::compositor { class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation { private: public: - OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd, + OutputOpenExrSingleLayerMultiViewOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name, bool save_as_render); @@ -54,14 +53,13 @@ class OutputStereoOperation : public OutputSingleLayerOperation { size_t channels_; public: - OutputStereoOperation(const RenderData *rd, + OutputStereoOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, DataType datatype, struct ImageFormatData *format, const char *path, const char *name, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name, bool save_as_render); void *get_handle(const char *filename); diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc index 67c92a3bcb0..cde1496546e 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc @@ -200,16 +200,14 @@ static void write_buffer_rect(rcti *rect, } } -OutputSingleLayerOperation::OutputSingleLayerOperation( - const RenderData *rd, - const bNodeTree *tree, - DataType datatype, - ImageFormatData *format, - const char *path, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, - const char *view_name, - const bool save_as_render) +OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene, + const RenderData *rd, + const bNodeTree *tree, + DataType datatype, + ImageFormatData *format, + const char *path, + const char *view_name, + const bool save_as_render) { rd_ = rd; tree_ = tree; @@ -220,11 +218,9 @@ OutputSingleLayerOperation::OutputSingleLayerOperation( datatype_ = datatype; image_input_ = nullptr; - format_ = format; + BKE_image_format_init_for_write(&format_, scene, format); BLI_strncpy(path_, path, sizeof(path_)); - view_settings_ = view_settings; - display_settings_ = display_settings; view_name_ = view_name; save_as_render_ = save_as_render; } @@ -245,7 +241,7 @@ void OutputSingleLayerOperation::deinit_execution() if (this->get_width() * this->get_height() != 0) { int size = get_datatype_size(datatype_); - ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_->planes, 0); + ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_.planes, 0); char filename[FILE_MAX]; const char *suffix; @@ -254,8 +250,7 @@ void OutputSingleLayerOperation::deinit_execution() ibuf->mall |= IB_rectfloat; ibuf->dither = rd_->dither_intensity; - IMB_colormanagement_imbuf_for_write( - ibuf, save_as_render_, false, view_settings_, display_settings_, format_); + IMB_colormanagement_imbuf_for_write(ibuf, save_as_render_, false, &format_); suffix = BKE_scene_multiview_view_suffix_get(rd_, view_name_); @@ -263,12 +258,12 @@ void OutputSingleLayerOperation::deinit_execution() path_, BKE_main_blendfile_path_from_global(), rd_->cfra, - format_, + &format_, (rd_->scemode & R_EXTENSION) != 0, true, suffix); - if (0 == BKE_imbuf_write(ibuf, filename, format_)) { + if (0 == BKE_imbuf_write(ibuf, filename, &format_)) { printf("Cannot save Node File Output to %s\n", filename); } else { diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h index 51240082a80..98b7e77cc21 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileOperation.h @@ -20,27 +20,23 @@ class OutputSingleLayerOperation : public MultiThreadedOperation { const RenderData *rd_; const bNodeTree *tree_; - ImageFormatData *format_; + ImageFormatData format_; char path_[FILE_MAX]; float *output_buffer_; DataType datatype_; SocketReader *image_input_; - const ColorManagedViewSettings *view_settings_; - const ColorManagedDisplaySettings *display_settings_; - const char *view_name_; bool save_as_render_; public: - OutputSingleLayerOperation(const RenderData *rd, + OutputSingleLayerOperation(const Scene *scene, + const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name, bool save_as_render); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 78c01ce5a23..5dd26d19e02 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -214,6 +214,7 @@ set(SRC engines/eevee_next/eevee_engine.h engines/external/external_engine.h engines/image/image_batches.hh + engines/image/image_buffer_cache.hh engines/image/image_drawing_mode.hh engines/image/image_engine.h engines/image/image_instance_data.hh diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl index 584aacc9e19..ddc6a0b9661 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl @@ -26,10 +26,13 @@ struct ClosureEvalGlossy { #ifdef STEP_RESOLVE /* SSR */ /* Prototype. */ +# ifndef GPU_METAL +/* MSL does not require prototypes. */ void raytrace_resolve(ClosureInputGlossy cl_in, inout ClosureEvalGlossy cl_eval, inout ClosureEvalCommon cl_common, inout ClosureOutputGlossy cl_out); +# endif #endif ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in, diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl index f66f45635f4..fefc8743691 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl @@ -32,8 +32,10 @@ struct Closure { #endif }; +#ifndef GPU_METAL /* Prototype */ Closure nodetree_exec(void); +#endif /* clang-format off */ /* Avoid multi-line defines. */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl index 9d9d7beb3cb..bdcc0a2ba93 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl @@ -150,7 +150,7 @@ vec4 step_blit(void) float br = max_v3(m); /* Under-threshold part: quadratic curve */ - float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y); + float rq = clamp(br - curveThreshold.x, 0.0, curveThreshold.y); rq = curveThreshold.z * rq * rq; /* Combine and apply the brightness response curve. */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl index 57027c71156..688ae4915e1 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl @@ -142,7 +142,7 @@ void dof_resolve_load_layer(sampler2D color_tex, out float out_weight) { vec2 pixel_co = gl_FragCoord.xy / 2.0; - vec2 uv = pixel_co / textureSize(color_tex, 0).xy; + vec2 uv = pixel_co / vec2(textureSize(color_tex, 0).xy); out_color = textureLod(color_tex, uv, 0.0); out_weight = textureLod(weight_tex, uv, 0.0).r; } diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index b05223e755d..51a351babd3 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -95,7 +95,7 @@ void main() weights = dof_layer_weight(cocs) * dof_sample_weight(cocs); /* Filter NaNs. */ - weights = mix(weights, vec4(0.0), equal(cocs, vec4(0.0))); + weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0))); color1 = colors[0] * weights[0]; color2 = colors[1] * weights[1]; diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl index 235145b221b..178ef46862b 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl @@ -54,12 +54,12 @@ void main() bvec4 focus = lessThanEqual(cocs, vec4(0.5)); if (any(defocus) && any(focus)) { /* For the same reason as in the flatten pass. This is a case we cannot optimize for. */ - cocs = mix(cocs, vec4(DOF_TILE_MIXED), focus); - cocs = mix(cocs, vec4(DOF_TILE_MIXED), defocus); + cocs = select(cocs, vec4(DOF_TILE_MIXED), focus); + cocs = select(cocs, vec4(DOF_TILE_MIXED), defocus); } else { - cocs = mix(cocs, vec4(DOF_TILE_FOCUS), focus); - cocs = mix(cocs, vec4(DOF_TILE_DEFOCUS), defocus); + cocs = select(cocs, vec4(DOF_TILE_FOCUS), focus); + cocs = select(cocs, vec4(DOF_TILE_DEFOCUS), defocus); } outCoc.y = max_v4(cocs); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index ce455123987..aaf673eecd2 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -38,7 +38,7 @@ uniform vec2 texelSize; /* On some AMD card / driver combination, it is needed otherwise, * the shader does not write anything. */ -#if defined(GPU_INTEL) || defined(GPU_ATI) +#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL) out vec4 fragColor; #endif @@ -68,9 +68,14 @@ void main() float val = minmax4(samp.x, samp.y, samp.z, samp.w); #endif -#if defined(GPU_INTEL) || defined(GPU_ATI) +#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL) /* Use color format instead of 24bit depth texture */ fragColor = vec4(val); #endif + +#if !(defined(GPU_INTEL) && defined(GPU_OPENGL)) + /* If using Intel workaround, do not write out depth as there will be no depth target and this is + * invalid. */ gl_FragDepth = val; +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl index f4ff28eaee4..c9010749060 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl @@ -60,11 +60,11 @@ void main() vec3 P = transform_point(ViewMatrixInverse, vP); vec3 vV = viewCameraVec(vP); vec3 V = cameraVec(P); - vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV); + vec3 vN = normal_decode(textureLod(normalBuffer, uvs, 0.0).rg, vV); vec3 N = transform_direction(ViewMatrixInverse, vN); /* Retrieve pixel data */ - vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba; + vec4 speccol_roughness = textureLod(specroughBuffer, uvs, 0.0).rgba; /* Early out */ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) { diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl index 300477570d0..fc8091161d7 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl @@ -74,7 +74,7 @@ bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity) * offset. If the offset coordinate is zero then * velocity is irrelevant. */ - vec2 point = sign(offset * velocity); + vec2 point = sign(vec2(offset) * velocity); float dist = (point.x + point.y); /** diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index 84626eac4cf..e1035af37be 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -289,7 +289,7 @@ vec3 probe_evaluate_grid(GridData gd, vec3 P, vec3 N, vec3 localpos) weight += prbIrradianceSmooth; /* Trilinear weights */ - vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, offset); + vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, vec3(offset)); weight *= trilinear.x * trilinear.y * trilinear.z; /* Avoid zero weight */ diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl index cf44a04b707..5674e464f4c 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl @@ -16,11 +16,11 @@ void main() { #if 0 /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */ - vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0)); + vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0).xy); FragColor = textureLod(source, vec3(uvs, layer), 0.0); #else - vec2 texel_size = 1.0 / vec2(textureSize(source, 0)); + vec2 texel_size = 1.0 / vec2(textureSize(source, 0).xy); vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size; vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 25661a0d731..9f1afc4767c 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -31,7 +31,7 @@ layout(location = 3) out vec4 volumePhase; void main() { - ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); + ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice); vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl index 12b7d8acbea..11f57c0a82e 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl @@ -52,7 +52,7 @@ void main() ivec2 texco = ivec2(gl_FragCoord.xy); #endif for (int i = 0; i <= slice; i++) { - ivec3 volume_cell = ivec3(gl_FragCoord.xy, i); + ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), i); vec3 Lscat = texelFetch(volumeScattering, volume_cell, 0).rgb; vec3 s_extinction = texelFetch(volumeExtinction, volume_cell, 0).rgb; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl index dc755aeab8b..df3f92966e6 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl @@ -22,7 +22,7 @@ layout(location = 1) out vec4 outTransmittance; void main() { - ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); + ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice); /* Emission */ outScattering = texelFetch(volumeEmission, volume_cell, 0); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 7bfbcfa9e21..be35660a4d7 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -269,8 +269,8 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, float vert_col_opacity = (override_vertcol) ? (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) : - pd->is_render ? gpl->vertex_paint_opacity : - pd->vertex_paint_opacity; + (pd->is_render ? gpl->vertex_paint_opacity : + pd->vertex_paint_opacity); /* Negate thickness sign to tag that strokes are in screen space. * Convert to world units (by default, 1 meter = 2000 pixels). */ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR); diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/background_frag.glsl index 52052d414f8..19313c0415b 100644 --- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/background_frag.glsl @@ -38,8 +38,8 @@ void main() * This removes the alpha channel and put the background behind reference images * while masking the reference images by the render alpha. */ - float alpha = texture(colorBuffer, uvcoordsvar.st).a; - float depth = texture(depthBuffer, uvcoordsvar.st).r; + float alpha = texture(colorBuffer, uvcoordsvar.xy).a; + float depth = texture(depthBuffer, uvcoordsvar.xy).r; vec3 bg_col; vec3 col_high; diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl index 0e4757f8ea8..19d54a57479 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl @@ -169,7 +169,7 @@ void diag_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end void main() { - uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r; + uint ref = textureLod(outlineId, uvcoordsvar.xy, 0.0).r; uint ref_col = ref; vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy; diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl index f714646fe40..507beb8a418 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl @@ -53,7 +53,7 @@ vec4 flag_to_color(uint flag) if (bool(flag & uint(16))) { color.rgb += vec3(0.9, 0.3, 0.0); /* orange */ } - if (color.rgb == vec3(0.0)) { + if (is_zero(color.rgb)) { color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */ } return color; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl index 59222b588a0..7704e7ed0b7 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl @@ -9,11 +9,11 @@ void main() float cavity = 0.0, edges = 0.0, curvature = 0.0; #ifdef USE_CAVITY - cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges); + cavity_compute(uvcoordsvar.xy, depthBuffer, normalBuffer, cavity, edges); #endif #ifdef USE_CURVATURE - curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature); + curvature_compute(uvcoordsvar.xy, objectIdBuffer, normalBuffer, curvature); #endif float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl index ae564435258..30daca6b7e3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl @@ -1,7 +1,7 @@ void main() { - float depth = texture(depthBuffer, uvcoordsvar.st).r; + float depth = texture(depthBuffer, uvcoordsvar.xy).r; /* Fix issues with Intel drivers (see T80023). */ fragColor = vec4(0.0); /* Discard background pixels. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl index a2c45d2f8e3..35bea830bac 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl @@ -9,8 +9,8 @@ void main() /* Revealage is actually stored in transparentAccum alpha channel. * This is a workaround to older hardware not having separate blend equation per render target. */ - vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st); - float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r; + vec4 trans_accum = texture(transparentAccum, uvcoordsvar.xy); + float trans_weight = texture(transparentRevealage, uvcoordsvar.xy).r; float trans_reveal = trans_accum.a; /* Listing 4 */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 076f6e80104..4ff281ccd29 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -94,7 +94,7 @@ vec4 flag_to_color(uint flag) if (bool(flag & uint(16))) { color.rgb += vec3(0.9, 0.3, 0.0); /* orange */ } - if (color.rgb == vec3(0.0)) { + if (is_zero(color.rgb)) { color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */ } return color; diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 37f884e398c..ed94c485b32 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -515,7 +515,7 @@ class Texture : NonCopyable { /** * Ensure the availability of mipmap views. - * Mip view covers all layers of array textures. + * MIP view covers all layers of array textures. */ bool ensure_mip_views(bool cube_as_array = false) { diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index eb73ab78a1a..832897b7040 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -432,7 +432,7 @@ struct DRWView { struct DRWView *parent; ViewInfos storage; - /** Number of active clipplanes. */ + /** Number of active clip planes. */ int clip_planes_len; /** Does culling result needs to be updated. */ bool is_dirty; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index ae536f0b87c..27149a80f9b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -419,7 +419,7 @@ static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache } static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, - const MeshRenderData *mr, + const MeshRenderData *UNUSED(mr), void *_data, uint subdiv_quad_index, const BMFace *coarse_quad) @@ -431,11 +431,8 @@ static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_ca uint end_loop_idx = (subdiv_quad_index + 1) * 4; for (uint i = start_loop_idx; i < end_loop_idx; i++) { const int vert_origindex = subdiv_loop_vert_index[i]; - const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && - vert_origindex != -1 && - mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); edituv_point_add(data, - (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert, + (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) || vert_origindex == -1), BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0, i); } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index 2dfd2cd43dc..f79fe345f5a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -137,7 +137,7 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach uint end_loop_idx = (subdiv_quad_index + 1) * 4; for (uint i = start_loop_idx; i < end_loop_idx; i++) { const int vert_origindex = subdiv_loop_vert_index[i]; - const int edge_origindex = subdiv_loop_edge_index[i]; + int edge_origindex = subdiv_loop_edge_index[i]; EditLoopData *edit_loop_data = &data->vbo_data[i]; memset(edit_loop_data, 0, sizeof(EditLoopData)); @@ -149,6 +149,22 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data); mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data); } + else { + if (edge_origindex == -1) { + /* Find if the loop's vert is not part of an edit edge. + * For this, we check if the previous loop was on an edge. */ + const uint loop_index_last = (i == start_loop_idx) ? end_loop_idx - 1 : i - 1; + edge_origindex = subdiv_loop_edge_index[loop_index_last]; + } + if (edge_origindex != -1) { + /* Mapped points on an edge between two edit verts. */ + BMEdge *eed = BM_edge_at_index(mr->bm, edge_origindex); + BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data); + } + } + + mesh_render_data_face_flag(mr, coarse_quad, data->cd_ofs, edit_loop_data); } } diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl index 8d0ba713616..9e3c219a30b 100644 --- a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl +++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl @@ -119,7 +119,7 @@ float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos) * * WARNING: Max attribute count is actually 14 because OSX OpenGL implementation * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) - **/ + */ vec4 gpencil_vertex(ivec4 ma, ivec4 ma1, ivec4 ma2, diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index ed8b8aeb849..7f94b7ea1c1 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -158,7 +158,7 @@ float hair_shaperadius(float shape, float root, float tip, float time) return (radius * (root - tip)) + tip; } -# ifdef OS_MAC +# if defined(OS_MAC) && defined(GPU_OPENGL) in float dummy; # endif @@ -178,7 +178,7 @@ void hair_get_pos_tan_binor_time(bool is_persp, wpos = data.point_position; time = data.point_time; -# ifdef OS_MAC +# if defined(OS_MAC) && defined(GPU_OPENGL) /* Generate a dummy read to avoid the driver bug with shaders having no * vertex reads on macOS (T60171) */ wpos.y += dummy * 0.0; diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl index 7b701d1d81b..6d4452c18c8 100644 --- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -86,7 +86,7 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection) float line_unit_box_intersect_dist_safe(vec3 lineorigin, vec3 linedirection) { vec3 safe_linedirection = max(vec3(1e-8), abs(linedirection)) * - mix(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0))); + select(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0))); return line_unit_box_intersect_dist(lineorigin, safe_linedirection); } diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 1701056cbb7..4d0ffaeb40f 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -84,9 +84,9 @@ float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); } float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); } float safe_rcp(float a) { return (a != 0.0) ? (1.0 / a) : 0.0; } -vec2 safe_rcp(vec2 a) { return mix(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); } -vec3 safe_rcp(vec3 a) { return mix(vec3(0.0), (1.0 / a), notEqual(a, vec3(0.0))); } -vec4 safe_rcp(vec4 a) { return mix(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); } +vec2 safe_rcp(vec2 a) { return select(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); } +vec3 safe_rcp(vec3 a) { return select(vec3(0.0), (1.0 / a), notEqual(a, vec3(0.0))); } +vec4 safe_rcp(vec4 a) { return select(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); } float safe_sqrt(float a) { return sqrt(max(a, 0.0)); } diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 2ac157ad208..6c58752c8bb 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -174,7 +174,7 @@ flat in int resourceIDFrag; /* Breaking this across multiple lines causes issues for some older GLSL compilers. */ /* clang-format off */ -#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX) +#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX) /* clang-format on */ /* Temporary until we fully make the switch. */ @@ -251,7 +251,7 @@ uniform mat4 ModelMatrixInverse; /* Due to some shader compiler bug, we somewhat need to access gl_VertexID * to make vertex shaders work. even if it's actually dead code. */ -#ifdef GPU_INTEL +#if defined(GPU_INTEL) && defined(GPU_OPENGL) # define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexID); #else # define GPU_INTEL_VERTEX_SHADER_WORKAROUND diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index df418b204f9..08379be36fa 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1131,7 +1131,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn { AnimChanRearrangeFp rearrange_func; ListBase anim_data_visible = {NULL, NULL}; - const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact); + const bool is_liboverride = (ac->obact != NULL) ? ID_IS_OVERRIDE_LIBRARY(ac->obact) : false; /* hack: invert mode so that functions will work in right order */ mode *= -1; diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index dcf8835c911..6fcdd21bad8 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -715,54 +715,55 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C, PropertyRNA *UNUSED(prop), bool *r_free) { + Scene *scene = CTX_data_scene(C); KeyingSet *ks; EnumPropertyItem *item = NULL, item_tmp = {0}; int totitem = 0; int i = 0; - if (C != NULL) { - Scene *scene = CTX_data_scene(C); - /* active Keying Set - * - only include entry if it exists - */ - if (scene->active_keyingset) { - /* active Keying Set */ - item_tmp.identifier = "__ACTIVE__"; - item_tmp.name = "Active Keying Set"; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); + if (C == NULL) { + return DummyRNA_DEFAULT_items; + } - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); - } + /* active Keying Set + * - only include entry if it exists + */ + if (scene->active_keyingset) { + /* active Keying Set */ + item_tmp.identifier = "__ACTIVE__"; + item_tmp.name = "Active Keying Set"; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); + } - i++; + i++; - /* user-defined Keying Sets - * - these are listed in the order in which they were defined for the active scene - */ - if (scene->keyingsets.first) { - for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) { - if (ANIM_keyingset_context_ok_poll(C, ks)) { - item_tmp.identifier = ks->idname; - item_tmp.name = ks->name; - item_tmp.description = ks->description; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } + /* user-defined Keying Sets + * - these are listed in the order in which they were defined for the active scene + */ + if (scene->keyingsets.first) { + for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) { + if (ANIM_keyingset_context_ok_poll(C, ks)) { + item_tmp.identifier = ks->idname; + item_tmp.name = ks->name; + item_tmp.description = ks->description; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); } - - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); } + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); } /* builtin Keying Sets */ i = -1; for (ks = builtin_keyingsets.first; ks; ks = ks->next, i--) { - /* Only show #KeyingSet if context is suitable or if there is no context which is needed - * to support key-bindings to be assigned since key bindings are not context aware. */ - if ((C == NULL) || ANIM_keyingset_context_ok_poll(C, ks)) { + /* only show KeyingSet if context is suitable */ + if (ANIM_keyingset_context_ok_poll(C, ks)) { item_tmp.identifier = ks->idname; item_tmp.name = ks->name; item_tmp.description = ks->description; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 54bd1a2cebb..0f4f0ef48ff 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1976,6 +1976,9 @@ static void UI_OT_drop_name(wmOperatorType *ot) static bool ui_list_focused_poll(bContext *C) { const ARegion *region = CTX_wm_region(C); + if (!region) { + return false; + } const wmWindow *win = CTX_wm_window(C); const uiList *list = UI_list_find_mouse_over(region, win->eventstate); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 077eedd6e58..38499a7f089 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6223,16 +6223,13 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, ColorManagedViewSettings *view_settings = view_transform_ptr.data; uiLayout *col = uiLayoutColumn(layout, false); - - uiLayout *row = uiLayoutRow(col, false); - uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); + uiItemR(col, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); + uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE); - uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); - col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE); if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) { diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index faf449a77aa..d3fc83eedd7 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -108,6 +108,7 @@ static int geometry_extract_apply(bContext *C, new_mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BMEditMesh *em = BKE_editmesh_create(bm); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 9c7d712a739..ecc5f8f8ef5 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -673,6 +673,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em) (&(struct BMeshFromMeshParams){ /* Handled with tessellation. */ .calc_face_normal = false, + .calc_vert_normal = false, .active_shapekey = um->shapenr, })); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index b0c8646dd04..7fedc2c6265 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -2219,7 +2219,7 @@ static int multires_unsubdivide_exec(bContext *C, wmOperator *op) int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true); if (new_levels == 0) { - BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level"); + BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild a lower level"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 1970851c326..24425b5a991 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -1135,7 +1135,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } if (ob->data == nullptr) { - /* special support for dupligroups */ + /* Special support for instanced collections. */ if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection && (ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) { if (ID_IS_LINKED(ob->instance_collection)) { diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 247948c7e6d..7392f05aea4 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ) set(SRC + curves_sculpt_3d_brush.cc curves_sculpt_add.cc curves_sculpt_comb.cc curves_sculpt_delete.cc diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc new file mode 100644 index 00000000000..94c0f5536b7 --- /dev/null +++ b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <algorithm> + +#include "curves_sculpt_intern.hh" + +#include "BKE_bvhutils.h" +#include "BKE_context.h" +#include "BKE_curves.hh" + +#include "ED_view3d.h" + +#include "UI_interface.h" + +#include "BLI_enumerable_thread_specific.hh" +#include "BLI_task.hh" + +/** + * The code below uses a prefix naming convention to indicate the coordinate space: + * cu: Local space of the curves object that is being edited. + * su: Local space of the surface object. + * wo: World space. + * re: 2D coordinates within the region. + */ + +namespace blender::ed::sculpt_paint { + +struct BrushPositionCandidate { + /** 3D position of the brush. */ + float3 position_cu; + /** Squared distance from the mouse position in screen space. */ + float distance_sq_re = FLT_MAX; + /** Measure for how far away the candidate is from the camera. */ + float depth_sq_cu = FLT_MAX; +}; + +/** + * Determine the 3D position of a brush based on curve segments under a screen position. + */ +static std::optional<float3> find_curves_brush_position(const CurvesGeometry &curves, + const float3 &ray_start_cu, + const float3 &ray_end_cu, + const float brush_radius_re, + ARegion ®ion, + RegionView3D &rv3d, + Object &object) +{ + /* This value might have to be adjusted based on user feedback. */ + const float brush_inner_radius_re = std::min<float>(brush_radius_re, (float)UI_UNIT_X / 3.0f); + const float brush_inner_radius_sq_re = pow2f(brush_inner_radius_re); + + float4x4 projection; + ED_view3d_ob_project_mat_get(&rv3d, &object, projection.values); + + float2 brush_pos_re; + ED_view3d_project_float_v2_m4(®ion, ray_start_cu, brush_pos_re, projection.values); + + const float max_depth_sq_cu = math::distance_squared(ray_start_cu, ray_end_cu); + + /* Contains the logic that checks if `b` is a better candidate than `a`. */ + auto is_better_candidate = [&](const BrushPositionCandidate &a, + const BrushPositionCandidate &b) { + if (b.distance_sq_re <= brush_inner_radius_sq_re) { + if (a.distance_sq_re > brush_inner_radius_sq_re) { + /* New candidate is in inner radius while old one is not. */ + return true; + } + else if (b.depth_sq_cu < a.depth_sq_cu) { + /* Both candidates are in inner radius, but new one is closer to the camera. */ + return true; + } + } + else if (b.distance_sq_re < a.distance_sq_re) { + /* Both candidates are outside of inner radius, but new on is closer to the brush center. */ + return true; + } + return false; + }; + + auto update_if_better = [&](BrushPositionCandidate &a, const BrushPositionCandidate &b) { + if (is_better_candidate(a, b)) { + a = b; + } + }; + + const Span<float3> positions = curves.positions(); + + BrushPositionCandidate best_candidate = threading::parallel_reduce( + curves.curves_range(), + 128, + BrushPositionCandidate(), + [&](IndexRange curves_range, const BrushPositionCandidate &init) { + BrushPositionCandidate best_candidate = init; + + for (const int curve_i : curves_range) { + const IndexRange points = curves.range_for_curve(curve_i); + const int tot_segments = points.size() - 1; + + for (const int segment_i : IndexRange(tot_segments)) { + const float3 &p1_cu = positions[points[segment_i]]; + const float3 &p2_cu = positions[points[segment_i] + 1]; + + float2 p1_re, p2_re; + ED_view3d_project_float_v2_m4(®ion, p1_cu, p1_re, projection.values); + ED_view3d_project_float_v2_m4(®ion, p2_cu, p2_re, projection.values); + + float2 closest_re; + const float lambda = closest_to_line_segment_v2( + closest_re, brush_pos_re, p1_re, p2_re); + + const float3 closest_cu = math::interpolate(p1_cu, p2_cu, lambda); + const float depth_sq_cu = math::distance_squared(ray_start_cu, closest_cu); + if (depth_sq_cu > max_depth_sq_cu) { + continue; + } + + const float distance_sq_re = math::distance_squared(brush_pos_re, closest_re); + + BrushPositionCandidate candidate; + candidate.position_cu = closest_cu; + candidate.depth_sq_cu = depth_sq_cu; + candidate.distance_sq_re = distance_sq_re; + + update_if_better(best_candidate, candidate); + } + } + return best_candidate; + }, + [&](const BrushPositionCandidate &a, const BrushPositionCandidate &b) { + return is_better_candidate(a, b) ? b : a; + }); + + if (best_candidate.distance_sq_re == FLT_MAX) { + /* Nothing found. */ + return std::nullopt; + } + + return best_candidate.position_cu; +} + +std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C, + Object &curves_object, + const float2 &brush_pos_re, + const float brush_radius_re) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C); + ARegion *region = CTX_wm_region(&C); + View3D *v3d = CTX_wm_view3d(&C); + RegionView3D *rv3d = CTX_wm_region_view3d(&C); + + Curves &curves_id = *static_cast<Curves *>(curves_object.data); + CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); + Object *surface_object = curves_id.surface; + + float3 center_ray_start_wo, center_ray_end_wo; + ED_view3d_win_to_segment_clipped( + depsgraph, region, v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true); + + /* Shorten ray when the surface object is hit. */ + if (surface_object != nullptr) { + const float4x4 surface_to_world_mat = surface_object->obmat; + const float4x4 world_to_surface_mat = surface_to_world_mat.inverted(); + + Mesh &surface = *static_cast<Mesh *>(surface_object->data); + BVHTreeFromMesh surface_bvh; + BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_LOOPTRI, 2); + BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); }); + + const float3 center_ray_start_su = world_to_surface_mat * center_ray_start_wo; + float3 center_ray_end_su = world_to_surface_mat * center_ray_end_wo; + const float3 center_ray_direction_su = math::normalize(center_ray_end_su - + center_ray_start_su); + + BVHTreeRayHit center_ray_hit; + center_ray_hit.dist = FLT_MAX; + center_ray_hit.index = -1; + BLI_bvhtree_ray_cast(surface_bvh.tree, + center_ray_start_su, + center_ray_direction_su, + 0.0f, + ¢er_ray_hit, + surface_bvh.raycast_callback, + &surface_bvh); + if (center_ray_hit.index >= 0) { + const float3 hit_position_su = center_ray_hit.co; + if (math::distance(center_ray_start_su, center_ray_end_su) > + math::distance(center_ray_start_su, hit_position_su)) { + center_ray_end_su = hit_position_su; + center_ray_end_wo = surface_to_world_mat * center_ray_end_su; + } + } + } + + const float4x4 curves_to_world_mat = curves_object.obmat; + const float4x4 world_to_curves_mat = curves_to_world_mat.inverted(); + + const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo; + const float3 center_ray_end_cu = world_to_curves_mat * center_ray_end_wo; + + const std::optional<float3> brush_position_optional_cu = find_curves_brush_position( + curves, + center_ray_start_cu, + center_ray_end_cu, + brush_radius_re, + *region, + *rv3d, + curves_object); + if (!brush_position_optional_cu.has_value()) { + /* Nothing found. */ + return std::nullopt; + } + const float3 brush_position_cu = *brush_position_optional_cu; + + /* Determine the 3D brush radius. */ + float3 radius_ray_start_wo, radius_ray_end_wo; + ED_view3d_win_to_segment_clipped(depsgraph, + region, + v3d, + brush_pos_re + float2(brush_radius_re, 0.0f), + radius_ray_start_wo, + radius_ray_end_wo, + true); + const float3 radius_ray_start_cu = world_to_curves_mat * radius_ray_start_wo; + const float3 radius_ray_end_cu = world_to_curves_mat * radius_ray_end_wo; + + CurvesBrush3D brush_3d; + brush_3d.position_cu = brush_position_cu; + brush_3d.radius_cu = dist_to_line_v3(brush_position_cu, radius_ray_start_cu, radius_ray_end_cu); + return brush_3d; +} + +} // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc index 6c13704a3a6..35b2b2ce956 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc @@ -35,129 +35,340 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "UI_interface.h" + +/** + * The code below uses a prefix naming convention to indicate the coordinate space: + * cu: Local space of the curves object that is being edited. + * su: Local space of the surface object. + * wo: World space. + * re: 2D coordinates within the region. + */ + namespace blender::ed::sculpt_paint { using blender::bke::CurvesGeometry; +using threading::EnumerableThreadSpecific; /** * Moves individual points under the brush and does a length preservation step afterwards. */ class CombOperation : public CurvesSculptStrokeOperation { private: - float2 last_mouse_position_; + /** Last mouse position. */ + float2 brush_pos_last_re_; + + /** Only used when a 3D brush is used. */ + CurvesBrush3D brush_3d_; + + /** Length of each segment indexed by the index of the first point in the segment. */ + Array<float> segment_lengths_cu_; + + friend struct CombOperationExecutor; public: - void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override + void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override; +}; + +/** + * Utility class that actually executes the update when the stroke is updated. That's useful + * because it avoids passing a very large number of parameters between functions. + */ +struct CombOperationExecutor { + CombOperation *self_ = nullptr; + bContext *C_ = nullptr; + Depsgraph *depsgraph_ = nullptr; + Scene *scene_ = nullptr; + Object *object_ = nullptr; + ARegion *region_ = nullptr; + View3D *v3d_ = nullptr; + RegionView3D *rv3d_ = nullptr; + + CurvesSculpt *curves_sculpt_ = nullptr; + Brush *brush_ = nullptr; + float brush_radius_re_; + float brush_strength_; + + eBrushFalloffShape falloff_shape_; + + Curves *curves_id_ = nullptr; + CurvesGeometry *curves_ = nullptr; + + const Object *surface_ob_ = nullptr; + const Mesh *surface_ = nullptr; + Span<MLoopTri> surface_looptris_; + + float2 brush_pos_prev_re_; + float2 brush_pos_re_; + float2 brush_pos_diff_re_; + float brush_pos_diff_length_re_; + + float4x4 curves_to_world_mat_; + float4x4 world_to_curves_mat_; + float4x4 surface_to_world_mat_; + float4x4 world_to_surface_mat_; + + BVHTreeFromMesh surface_bvh_; + + void execute(CombOperation &self, bContext *C, const StrokeExtension &stroke_extension) { - BLI_SCOPED_DEFER([&]() { last_mouse_position_ = stroke_extension.mouse_position; }); + self_ = &self; + + BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; }); + + C_ = C; + depsgraph_ = CTX_data_depsgraph_pointer(C); + scene_ = CTX_data_scene(C); + object_ = CTX_data_active_object(C); + region_ = CTX_wm_region(C); + v3d_ = CTX_wm_view3d(C); + rv3d_ = CTX_wm_region_view3d(C); + + curves_sculpt_ = scene_->toolsettings->curves_sculpt; + brush_ = BKE_paint_brush(&curves_sculpt_->paint); + brush_radius_re_ = BKE_brush_size_get(scene_, brush_); + brush_strength_ = BKE_brush_alpha_get(scene_, brush_); + + curves_to_world_mat_ = object_->obmat; + world_to_curves_mat_ = curves_to_world_mat_.inverted(); + + falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape); + + curves_id_ = static_cast<Curves *>(object_->data); + curves_ = &CurvesGeometry::wrap(curves_id_->geometry); + + brush_pos_prev_re_ = self_->brush_pos_last_re_; + brush_pos_re_ = stroke_extension.mouse_position; + brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_; + brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_); + + surface_ob_ = curves_id_->surface; + if (surface_ob_ != nullptr) { + surface_ = static_cast<const Mesh *>(surface_ob_->data); + surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), + BKE_mesh_runtime_looptri_len(surface_)}; + surface_to_world_mat_ = surface_ob_->obmat; + world_to_surface_mat_ = surface_to_world_mat_.inverted(); + BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); + } + + BLI_SCOPED_DEFER([&]() { + if (surface_ob_ != nullptr) { + free_bvhtree_from_mesh(&surface_bvh_); + } + }); if (stroke_extension.is_first) { + if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { + this->initialize_spherical_brush_reference_point(); + } + this->initialize_segment_lengths(); + /* Combing does nothing when there is no mouse movement, so return directly. */ return; } - Scene &scene = *CTX_data_scene(C); - Object &object = *CTX_data_active_object(C); - ARegion *region = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); + EnumerableThreadSpecific<Vector<int>> changed_curves; - CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt; - Brush &brush = *BKE_paint_brush(&curves_sculpt.paint); - const float brush_radius = BKE_brush_size_get(&scene, &brush); - const float brush_strength = BKE_brush_alpha_get(&scene, &brush); + if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) { + this->comb_projected(changed_curves); + } + else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) { + this->comb_spherical(changed_curves); + } + else { + BLI_assert_unreachable(); + } - const float4x4 ob_mat = object.obmat; - const float4x4 ob_imat = ob_mat.inverted(); + this->restore_segment_lengths(changed_curves); - float4x4 projection; - ED_view3d_ob_project_mat_get(rv3d, &object, projection.values); + curves_->tag_positions_changed(); + DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY); + ED_region_tag_redraw(region_); + } + + /** + * Do combing in screen space. + */ + void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves) + { + MutableSpan<float3> positions_cu = curves_->positions(); - Curves &curves_id = *static_cast<Curves *>(object.data); - CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry); - MutableSpan<float3> positions = curves.positions(); + float4x4 projection; + ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); - const float2 mouse_prev = last_mouse_position_; - const float2 mouse_cur = stroke_extension.mouse_position; - const float2 mouse_diff = mouse_cur - mouse_prev; - const float mouse_diff_len = math::length(mouse_diff); + const float brush_radius_sq_re = pow2f(brush_radius_re_); - threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) { + threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + Vector<int> &local_changed_curves = r_changed_curves.local(); for (const int curve_i : curves_range) { - const IndexRange curve_points = curves.range_for_curve(curve_i); - /* Compute lengths of the segments. Those are used to make sure that the lengths don't - * change. */ - Vector<float, 16> segment_lengths(curve_points.size() - 1); - for (const int segment_i : IndexRange(curve_points.size() - 1)) { - const float3 &p1 = positions[curve_points[segment_i]]; - const float3 &p2 = positions[curve_points[segment_i] + 1]; - const float length = math::distance(p1, p2); - segment_lengths[segment_i] = length; - } bool curve_changed = false; - for (const int point_i : curve_points.drop_front(1)) { - const float3 old_position = positions[point_i]; + const IndexRange points = curves_->range_for_curve(curve_i); + for (const int point_i : points.drop_front(1)) { + const float3 old_pos_cu = positions_cu[point_i]; /* Find the position of the point in screen space. */ - float2 old_position_screen; - ED_view3d_project_float_v2_m4( - region, old_position, old_position_screen, projection.values); - - /* Project the point onto the line drawn by the mouse. Note, it's projected on the - * infinite line, not only on the line segment. */ - float2 old_position_screen_proj; - /* t is 0 when the point is closest to the previous mouse position and 1 when it's - * closest to the current mouse position. */ - const float t = closest_to_line_v2( - old_position_screen_proj, old_position_screen, mouse_prev, mouse_cur); - - /* Compute the distance to the mouse line segment. */ - const float2 old_position_screen_proj_segment = mouse_prev + - std::clamp(t, 0.0f, 1.0f) * mouse_diff; - const float distance_screen = math::distance(old_position_screen, - old_position_screen_proj_segment); - if (distance_screen > brush_radius) { + float2 old_pos_re; + ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values); + + const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2( + old_pos_re, brush_pos_prev_re_, brush_pos_re_); + if (distance_to_brush_sq_re > brush_radius_sq_re) { /* Ignore the point because it's too far away. */ continue; } - /* Compute a falloff that is based on how far along the point along the last stroke - * segment is. */ - const float t_overshoot = brush_radius / mouse_diff_len; - const float t_falloff = 1.0f - std::max(t, 0.0f) / (1.0f + t_overshoot); + + const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re); /* A falloff that is based on how far away the point is from the stroke. */ - const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius); - /* Combine the different falloffs and brush strength. */ - const float weight = brush_strength * t_falloff * radius_falloff; + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_re, brush_radius_re_); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; /* Offset the old point position in screen space and transform it back into 3D space. */ - const float2 new_position_screen = old_position_screen + mouse_diff * weight; - float3 new_position; + const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight; + float3 new_position_wo; ED_view3d_win_to_3d( - v3d, region, ob_mat * old_position, new_position_screen, new_position); - new_position = ob_imat * new_position; - positions[point_i] = new_position; + v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo); + const float3 new_position_cu = world_to_curves_mat_ * new_position_wo; + positions_cu[point_i] = new_position_cu; curve_changed = true; } - if (!curve_changed) { - continue; + if (curve_changed) { + local_changed_curves.append(curve_i); } - /* Ensure that the length of each segment stays the same. */ - for (const int segment_i : IndexRange(curve_points.size() - 1)) { - const float3 &p1 = positions[curve_points[segment_i]]; - float3 &p2 = positions[curve_points[segment_i] + 1]; - const float3 direction = math::normalize(p2 - p1); - const float desired_length = segment_lengths[segment_i]; - p2 = p1 + direction * desired_length; + } + }); + } + + /** + * Do combing in 3D space. + */ + void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves) + { + MutableSpan<float3> positions_cu = curves_->positions(); + + float4x4 projection; + ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values); + + float3 brush_start_wo, brush_end_wo; + ED_view3d_win_to_3d(v3d_, + region_, + curves_to_world_mat_ * self_->brush_3d_.position_cu, + brush_pos_prev_re_, + brush_start_wo); + ED_view3d_win_to_3d(v3d_, + region_, + curves_to_world_mat_ * self_->brush_3d_.position_cu, + brush_pos_re_, + brush_end_wo); + const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo; + const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo; + + const float3 brush_diff_cu = brush_end_cu - brush_start_cu; + + const float brush_radius_cu = self_->brush_3d_.radius_cu; + const float brush_radius_sq_cu = pow2f(brush_radius_cu); + + threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) { + Vector<int> &local_changed_curves = r_changed_curves.local(); + for (const int curve_i : curves_range) { + bool curve_changed = false; + const IndexRange points = curves_->range_for_curve(curve_i); + for (const int point_i : points.drop_front(1)) { + const float3 pos_old_cu = positions_cu[point_i]; + + /* Compute distance to the brush. */ + const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3( + pos_old_cu, brush_start_cu, brush_end_cu); + if (distance_to_brush_sq_cu > brush_radius_sq_cu) { + /* Ignore the point because it's too far away. */ + continue; + } + + const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu); + + /* A falloff that is based on how far away the point is from the stroke. */ + const float radius_falloff = BKE_brush_curve_strength( + brush_, distance_to_brush_cu, brush_radius_cu); + /* Combine the falloff and brush strength. */ + const float weight = brush_strength_ * radius_falloff; + + /* Update the point position. */ + positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu; + curve_changed = true; + } + if (curve_changed) { + local_changed_curves.append(curve_i); } } }); + } - curves.tag_positions_changed(); - DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); - ED_region_tag_redraw(region); + /** + * Sample depth under mouse by looking at curves and the surface. + */ + void initialize_spherical_brush_reference_point() + { + std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush( + *C_, *object_, brush_pos_re_, brush_radius_re_); + if (brush_3d.has_value()) { + self_->brush_3d_ = *brush_3d; + } + } + + /** + * Remember the initial length of all curve segments. This allows restoring the length after + * combing. + */ + void initialize_segment_lengths() + { + const Span<float3> positions_cu = curves_->positions(); + self_->segment_lengths_cu_.reinitialize(curves_->points_size()); + threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) { + for (const int curve_i : range) { + const IndexRange points = curves_->range_for_curve(curve_i); + for (const int point_i : points.drop_back(1)) { + const float3 &p1_cu = positions_cu[point_i]; + const float3 &p2_cu = positions_cu[point_i + 1]; + const float length_cu = math::distance(p1_cu, p2_cu); + self_->segment_lengths_cu_[point_i] = length_cu; + } + } + }); + } + + /** + * Restore previously stored length for each segment in the changed curves. + */ + void restore_segment_lengths(EnumerableThreadSpecific<Vector<int>> &changed_curves) + { + const Span<float> expected_lengths_cu = self_->segment_lengths_cu_; + MutableSpan<float3> positions_cu = curves_->positions(); + + threading::parallel_for_each(changed_curves, [&](const Vector<int> &changed_curves) { + threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) { + for (const int curve_i : changed_curves.as_span().slice(range)) { + const IndexRange points = curves_->range_for_curve(curve_i); + for (const int segment_i : IndexRange(points.size() - 1)) { + const float3 &p1_cu = positions_cu[points[segment_i]]; + float3 &p2_cu = positions_cu[points[segment_i] + 1]; + const float3 direction = math::normalize(p2_cu - p1_cu); + const float expected_length_cu = expected_lengths_cu[points[segment_i]]; + p2_cu = p1_cu + direction * expected_length_cu; + } + } + }); + }); } }; +void CombOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) +{ + CombOperationExecutor executor; + executor.execute(*this, C, stroke_extension); +} + std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation() { return std::make_unique<CombOperation>(); diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh index d1de69f36b6..d021627921f 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh @@ -2,12 +2,22 @@ #pragma once +#include <optional> + #include "curves_sculpt_intern.h" #include "BLI_math_vector.hh" +#include "BKE_curves.hh" + +struct ARegion; +struct RegionView3D; +struct Object; + namespace blender::ed::sculpt_paint { +using bke::CurvesGeometry; + struct StrokeExtension { bool is_first; float2 mouse_position; @@ -27,4 +37,17 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation(); std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation(); +struct CurvesBrush3D { + float3 position_cu; + float radius_cu; +}; + +/** + * Find 3d brush position based on cursor position for curves sculpting. + */ +std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C, + Object &curves_object, + const float2 &brush_pos_re, + float brush_radius_re); + } // namespace blender::ed::sculpt_paint diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index c05886d1be1..2b55eb379cc 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -962,6 +962,7 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext) trim_mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false); BMO_op_callf(bm, @@ -1214,12 +1215,14 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext) trim_mesh, &((struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BM_mesh_bm_from_me(bm, sculpt_mesh, &((struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 0d65eef29f5..4f884420401 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -147,6 +147,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene me, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, .use_shapekey = true, .active_shapekey = ob->shapenr, })); diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index db3b8e40f09..7171c241534 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -379,6 +379,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BMIter iter; @@ -574,6 +575,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces"); @@ -652,6 +654,7 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode) mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BMIter iter; BMFace *f; @@ -1184,6 +1187,7 @@ static void sculpt_face_set_delete_geometry(Object *ob, mesh, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); BM_mesh_elem_table_init(bm, BM_FACE); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index abde5f52bb0..208928afc1f 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -958,14 +958,11 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma { ImageFormatData *imf = imfptr->data; ID *id = imfptr->owner_id; - PointerRNA display_settings_ptr; - PropertyRNA *prop; const int depth_ok = BKE_imtype_valid_depths(imf->imtype); /* some settings depend on this being a scene that's rendered */ const bool is_render_out = (id && GS(id->name) == ID_SCE); uiLayout *col; - bool show_preview = false; col = uiLayoutColumn(layout, false); @@ -1005,7 +1002,6 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma } if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) { - show_preview = true; uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE); } @@ -1037,18 +1033,22 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE); } - /* color management */ - if (color_management && (!BKE_imtype_requires_linear_float(imf->imtype) || - (show_preview && imf->flag & R_IMF_FLAG_PREVIEW_JPG))) { - prop = RNA_struct_find_property(imfptr, "display_settings"); - display_settings_ptr = RNA_property_pointer_get(imfptr, prop); - - col = uiLayoutColumn(layout, false); - uiItemL(col, IFACE_("Color Management"), ICON_NONE); - - uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE); + /* Override color management */ + if (color_management) { + uiItemS(col); + uiItemR(col, imfptr, "color_management", 0, NULL, ICON_NONE); - uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings"); + if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + if (BKE_imtype_requires_linear_float(imf->imtype)) { + PointerRNA linear_settings_ptr = RNA_pointer_get(imfptr, "linear_colorspace_settings"); + uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE); + } + else { + PointerRNA display_settings_ptr = RNA_pointer_get(imfptr, "display_settings"); + uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE); + uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings"); + } + } } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 1a7fb67954e..1c4a1d7e8c9 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1737,7 +1737,7 @@ static int image_save_options_init(Main *bmain, if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { /* imtype */ - BKE_image_format_copy(&opts->im_format, &scene->r.im_format); + BKE_image_format_init_for_write(&opts->im_format, scene, NULL); is_depth_set = true; if (!BKE_image_is_multiview(ima)) { /* In case multiview is disabled, @@ -1759,8 +1759,12 @@ static int image_save_options_init(Main *bmain, /* use the multiview image settings as the default */ opts->im_format.stereo3d_format = *ima->stereo3d_format; opts->im_format.views_format = ima->views_format; + + BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene); } + opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE; + if (ima->source == IMA_SRC_TILED) { BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath)); BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); @@ -1810,13 +1814,6 @@ static int image_save_options_init(Main *bmain, STR_CONCAT(opts->filepath, len, ".<UDIM>"); } } - - /* color management */ - BKE_color_managed_display_settings_copy(&opts->im_format.display_settings, - &scene->display_settings); - - BKE_color_managed_view_settings_free(&opts->im_format.view_settings); - BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings); } BKE_image_release_ibuf(ima, ibuf, lock); @@ -2006,15 +2003,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) ImageSaveData *isd = op->customdata; PointerRNA imf_ptr; const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview"); + const bool use_color_management = RNA_boolean_get(op->ptr, "save_as_render"); - /* image template */ - RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr); - uiTemplateImageSettings(layout, &imf_ptr, false); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* main draw call */ uiDefAutoButsRNA( layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false); + uiItemS(layout); + + /* image template */ + RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr); + uiTemplateImageSettings(layout, &imf_ptr, use_color_management); + /* multiview template */ if (is_multiview) { uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 1c278de28d0..956bb581ee6 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -18,6 +18,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_image_format.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" @@ -274,28 +275,14 @@ static void compo_startjob(void *cjv, /* 1 is do_previews */ if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) { - ntreeCompositExecTree(cj->scene, - ntree, - &cj->scene->r, - false, - true, - &scene->view_settings, - &scene->display_settings, - ""); + ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, ""); } else { LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) { continue; } - ntreeCompositExecTree(cj->scene, - ntree, - &cj->scene->r, - false, - true, - &scene->view_settings, - &scene->display_settings, - srv->name); + ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, srv->name); } } diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index a50dde68d28..8b03047b1dd 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -1785,6 +1785,11 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, const ListBase *lb, const int x) { + const float pad_x = 2.0f * UI_DPI_FAC; + const float pad_y = 0.5f * U.pixelsize; + const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x); + const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y); + LISTBASE_FOREACH (const TreeElement *, te, lb) { const TreeStoreElem *tselem = TREESTORE(te); if (TSELEM_OPEN(tselem, space_outliner)) { @@ -1805,10 +1810,6 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, PropertyRNA *prop = &override_elem.override_rna_prop; const PropertyType prop_type = RNA_property_type(prop); - const float pad_x = 1 * UI_DPI_FAC; - const float max_width = OL_RNA_COL_SIZEX - 2 * pad_x; - const float height = UI_UNIT_Y - U.pixelsize; - uiBut *auto_but = uiDefAutoButR(block, ptr, prop, @@ -1816,9 +1817,9 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, (prop_type == PROP_ENUM) ? nullptr : "", ICON_NONE, x + pad_x, - te->ys, - max_width, - height); + te->ys + pad_y, + item_max_width, + item_height); /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons * need to be handled. */ if (auto_but) { @@ -1828,7 +1829,8 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, if (!auto_but) { /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension * arrays? */ - uiDefAutoButsArrayR(block, ptr, prop, ICON_NONE, x, te->ys, max_width, height); + uiDefAutoButsArrayR( + block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height); } } } @@ -3915,7 +3917,7 @@ void draw_outliner(const bContext *C) block, region, space_outliner, &space_outliner->tree, true); UI_block_emboss_set(block, UI_EMBOSS); - const int x = region->v2d.cur.xmax - OL_RNA_COL_SIZEX; + const int x = region->v2d.cur.xmax - right_column_width; outliner_draw_separator(region, x); outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x); UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 73155a3b52f..6f55acff6a2 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1550,12 +1550,16 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -static Base *object_mouse_select_menu(bContext *C, - ViewContext *vc, - const GPUSelectResult *buffer, - const int hits, - const int mval[2], - const struct SelectPick_Params *params) +/** + * \return True when a menu was activated. + */ +static bool object_mouse_select_menu(bContext *C, + ViewContext *vc, + const GPUSelectResult *buffer, + const int hits, + const int mval[2], + const struct SelectPick_Params *params, + Base **r_basact) { int base_count = 0; bool ok; @@ -1596,13 +1600,16 @@ static Base *object_mouse_select_menu(bContext *C, } CTX_DATA_END; + *r_basact = NULL; + if (base_count == 0) { - return NULL; + return false; } if (base_count == 1) { Base *base = (Base *)linklist.list->link; BLI_linklist_free(linklist.list, NULL); - return base; + *r_basact = base; + return false; } /* UI, full in static array values that we later use in an enum function */ @@ -1631,7 +1638,7 @@ static Base *object_mouse_select_menu(bContext *C, WM_operator_properties_free(&ptr); BLI_linklist_free(linklist.list, NULL); - return NULL; + return true; } static int bone_select_menu_exec(bContext *C, wmOperator *op) @@ -1735,6 +1742,10 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } + +/** + * \return True when a menu was activated. + */ static bool bone_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, @@ -2189,6 +2200,49 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, return basact; } +static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const int mval[2]) +{ + ARegion *region = vc->region; + ViewLayer *view_layer = vc->view_layer; + View3D *v3d = vc->v3d; + + Base *oldbasact = BASACT(view_layer); + + const float mval_fl[2] = {(float)mval[0], (float)mval[1]}; + float dist = ED_view3d_select_dist_px() * 1.3333f; + Base *basact = NULL; + + /* Put the active object at a disadvantage to cycle through other objects. */ + const float penalty_dist = 10.0f * UI_DPI_FAC; + Base *base = startbase; + while (base) { + if (BASE_SELECTABLE(v3d, base)) { + float screen_co[2]; + if (ED_view3d_project_float_global( + region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == + V3D_PROJ_RET_OK) { + float dist_test = len_manhattan_v2v2(mval_fl, screen_co); + if (base == oldbasact) { + dist_test += penalty_dist; + } + if (dist_test < dist) { + dist = dist_test; + basact = base; + } + } + } + base = base->next; + + if (base == NULL) { + base = FIRSTBASE(view_layer); + } + if (base == startbase) { + break; + } + } + return basact; +} + static Base *ed_view3d_give_base_under_cursor_ex(bContext *C, const int mval[2], int *r_material_slot) @@ -2365,184 +2419,203 @@ static bool ed_object_select_pick_camera_track(bContext *C, return changed || found; } +/** + * Cursor selection picking for object & pose-mode. + * + * \param mval: Region relative cursor coordinates. + * \param params: Selection parameters. + * \param center: Select by the cursors on-screen distances to the center/origin + * instead of the geometry any other contents of the item being selected. + * This could be used to select by bones by their origin too, currently it's only used for objects. + * \param enumerate: Show a menu for objects at the cursor location. + * Otherwise fall-through to non-menu selection. + * \param object_only: Only select objects (not bones / track markers). + */ static bool ed_object_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params, - bool obcenter, - bool enumerate, - bool object) + const bool center, + const bool enumerate, + const bool object_only) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; /* Setup view context for argument to callbacks. */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - const ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - View3D *v3d = CTX_wm_view3d(C); - /* Don't set when the context has no active object (hidden), see: T60807. */ - const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL; - Base *base, *startbase = NULL, *basact = NULL; - const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT; - const bool is_obedit = (vc.obedit != NULL); - float dist = ED_view3d_select_dist_px() * 1.3333f; - const float mval_fl[2] = {(float)mval[0], (float)mval[1]}; - - /* Handle setting the new base active */ - bool use_activate_selected_base = false; + Scene *scene = vc.scene; + View3D *v3d = vc.v3d; - /* When enabled, don't attempt any further selection. */ - bool handled = false; - bool changed = false; + /* Menu activation may find a base to make active (if it only finds a single item to select). */ + Base *basact_override = NULL; - if (object) { + const bool is_obedit = (vc.obedit != NULL); + if (object_only) { /* Signal for #view3d_opengl_select to skip edit-mode objects. */ vc.obedit = NULL; } - /* In pose-mode we don't want to change the object selection (unless exiting pose mode). */ - const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE); - - /* Always start list from `basact` when cycling the selection. */ - startbase = FIRSTBASE(view_layer); - if (oldbasact && oldbasact->next) { - startbase = oldbasact->next; - } - - /* This block uses the control key to make the object selected - * by its center point rather than its contents */ - - /* In edit-mode do not activate. */ - if (obcenter) { - - /* NOTE: shift+alt goes to group-flush-selecting. */ - if (enumerate) { - basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, params); + /* Set for GPU depth buffer picking, leave NULL when selecting by center. */ + struct { + GPUSelectResult buffer[MAXPICKELEMS]; + int hits; + bool do_nearest; + bool has_bones; + } *gpu = NULL; + + /* First handle menu selection, early exit if a menu opens + * since this takes ownership of the selection action. + * + * Even when there is no menu `basact_override` may be set to avoid having to re-find + * the item under the cursor. */ + + if (center == false) { + gpu = MEM_mallocN(sizeof(*gpu), __func__); + gpu->do_nearest = false; + gpu->has_bones = false; + + /* If objects have pose-mode set, the bones are in the same selection buffer. */ + const eV3DSelectObjectFilter select_filter = ((object_only == false) ? + ED_view3d_select_filter_from_mode(scene, + vc.obact) : + VIEW3D_SELECT_FILTER_NOP); + gpu->hits = mixed_bones_object_selectbuffer_extended(&vc, + gpu->buffer, + ARRAY_SIZE(gpu->buffer), + mval, + select_filter, + true, + enumerate, + &gpu->do_nearest); + gpu->has_bones = (object_only && gpu->hits > 0) ? + false : + selectbuffer_has_bones(gpu->buffer, gpu->hits); + } + + /* First handle menu selection, early exit when a menu was opened. + * Otherwise fall through to regular selection. */ + if (enumerate) { + bool has_menu = false; + if (center) { + if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) { + has_menu = true; + } } else { - /* Put the active object at a disadvantage to cycle through other objects. */ - const float penalty_dist = 10.0f * U.dpi_fac; - base = startbase; - while (base) { - if (BASE_SELECTABLE(v3d, base)) { - float screen_co[2]; - if (ED_view3d_project_float_global( - region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == - V3D_PROJ_RET_OK) { - float dist_test = len_manhattan_v2v2(mval_fl, screen_co); - if (base == oldbasact) { - dist_test += penalty_dist; - } - if (dist_test < dist) { - dist = dist_test; - basact = base; - } - } + if (gpu->hits != 0) { + if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) { + has_menu = true; } - base = base->next; - - if (base == NULL) { - base = FIRSTBASE(view_layer); - } - if (base == startbase) { - break; + else if (object_mouse_select_menu( + C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) { + has_menu = true; } } } - if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - if (is_obedit == false) { - if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) { - if (object_mode == OB_MODE_OBJECT) { - struct Main *bmain = CTX_data_main(C); - ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object); - } - if (!BKE_object_is_mode_compat(basact->object, object_mode)) { - basact = NULL; - } - } + + /* Let the menu handle any further actions. */ + if (has_menu) { + if (gpu != NULL) { + MEM_freeN(gpu); } + return false; } } - else { - GPUSelectResult buffer[MAXPICKELEMS]; - bool do_nearest; - // TIMEIT_START(select_time); + /* No menu, continue with selection. */ - /* if objects have pose-mode set, the bones are in the same selection buffer */ - const eV3DSelectObjectFilter select_filter = ((object == false) ? - ED_view3d_select_filter_from_mode(scene, - vc.obact) : - VIEW3D_SELECT_FILTER_NOP); - const int hits = mixed_bones_object_selectbuffer_extended( - &vc, buffer, ARRAY_SIZE(buffer), mval, select_filter, true, enumerate, &do_nearest); + ViewLayer *view_layer = vc.view_layer; + /* Don't set when the context has no active object (hidden), see: T60807. */ + const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL; + /* Always start list from `basact` when cycling the selection. */ + Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer); + + /* The next object's base to make active. */ + Base *basact = NULL; + const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT; - // TIMEIT_END(select_time); + /* When enabled, don't attempt any further selection. */ + bool handled = false; - const bool has_bones = (object && hits > 0) ? false : selectbuffer_has_bones(buffer, hits); + /* Split `changed` into data-types so their associated updates can be properly performed. + * This is also needed as multiple changes may happen at once. + * Selecting a pose-bone or track can also select the object for e.g. */ + bool changed_object = false; + bool changed_pose = false; + bool changed_track = false; - if (hits > 0) { - /* NOTE: bundles are handling in the same way as bones. */ + /* Handle setting the new base active (even when `handled == true`). */ + bool use_activate_selected_base = false; - /* NOTE: shift+alt goes to group-flush-selecting. */ - if (enumerate) { - if (has_bones && bone_mouse_select_menu(C, buffer, hits, false, params)) { - handled = true; - } - else { - basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, params); - } - } - else { - basact = mouse_select_eval_buffer( - &vc, buffer, hits, startbase, has_bones, do_nearest, NULL); - } + if (center) { + if (basact_override) { + basact = basact_override; + } + else { + basact = mouse_select_object_center(&vc, startbase, mval); + } + } + else { + if (basact_override) { + basact = basact_override; + } + else { + basact = + (gpu->hits > 0) ? + mouse_select_eval_buffer( + &vc, gpu->buffer, gpu->hits, startbase, gpu->has_bones, gpu->do_nearest, NULL) : + NULL; } - if ((handled == false) && - (((hits > 0) && has_bones) || - /* Special case, even when there are no hits, pose logic may de-select all bones. */ - ((hits == 0) && is_pose_mode))) { + /* Select pose-bones or camera-tracks. */ + if (((gpu->hits > 0) && gpu->has_bones) || + /* Special case, even when there are no hits, pose logic may de-select all bones. */ + ((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) { - if (basact && (has_bones && (basact->object->type == OB_CAMERA))) { + if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) { MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); if (clip != NULL) { - if (ed_object_select_pick_camera_track(C, scene, basact, clip, buffer, hits, params)) { + if (ed_object_select_pick_camera_track( + C, scene, basact, clip, gpu->buffer, gpu->hits, params)) { ED_object_base_select(basact, BA_SELECT); - /* Don't set `handled` here as the object activation may be necessary. */ - changed = true; + changed_object = true; + + changed_track = true; } else { /* Fallback to regular object selection if no new bundles were selected, * allows to select object parented to reconstruction object. */ basact = mouse_select_eval_buffer( - &vc, buffer, hits, startbase, false, do_nearest, NULL); + &vc, gpu->buffer, gpu->hits, startbase, false, gpu->do_nearest, NULL); } } } else if (ED_armature_pose_select_pick_with_buffer(view_layer, v3d, basact ? basact : (Base *)oldbasact, - buffer, - hits, + gpu->buffer, + gpu->hits, params, - do_nearest)) { + gpu->do_nearest)) { + + changed_pose = true; + /* When there is no `baseact` this will have operated on `oldbasact`, - * no object operations are needed. */ + * allowing #SelectPick_Params.deselect_all work in pose-mode. + * In this case no object operations are needed. */ if (basact != NULL) { - /* then bone is found */ - /* we make the armature selected: - * not-selected active object in pose-mode won't work well for tools */ + /* By convention the armature-object is selected when in pose-mode. + * While leaving it unselected will work, leaving pose-mode would leave the object + * active + unselected which isn't ideal when performing other actions on the object. */ ED_object_base_select(basact, BA_SELECT); + changed_object = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - /* In weight-paint, we use selected bone to select vertex-group, - * so don't switch to new active object. */ + /* In weight-paint, we use selected bone to select vertex-group. + * In this case the active object mustn't change as it would leave weight-paint mode. */ if (oldbasact) { if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) { /* Prevent activating. @@ -2553,7 +2626,7 @@ static bool ed_object_select_pick(bContext *C, handled = true; } - else if (is_pose_mode && (basact->object->mode & OB_MODE_POSE)) { + else if ((object_mode & OB_MODE_POSE) && (basact->object->mode & OB_MODE_POSE)) { /* Within pose-mode, keep the current selection when switching pose bones, * this is noticeable when in pose mode with multiple objects at once. * Where selecting the bone of a different object would de-select this one. @@ -2578,36 +2651,36 @@ static bool ed_object_select_pick(bContext *C, handled = true; } } + } + if (handled == false) { if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - if ((handled == false) && (is_obedit == false)) { + /* No special logic in edit-mode. */ + if (is_obedit == false) { if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) { if (object_mode == OB_MODE_OBJECT) { - struct Main *bmain = CTX_data_main(C); + struct Main *bmain = vc.bmain; ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object); } if (!BKE_object_is_mode_compat(basact->object, object_mode)) { basact = NULL; } } - } - } - } - if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - /* Disallow switching modes, - * special exception for edit-mode - vertex-parent operator. */ - if ((handled == false) && (is_obedit == false)) { - if (oldbasact && basact) { - if ((oldbasact->object->mode != basact->object->mode) && - (oldbasact->object->mode & basact->object->mode) == 0) { - basact = NULL; + /* Disallow switching modes, + * special exception for edit-mode - vertex-parent operator. */ + if (basact && oldbasact) { + if ((oldbasact->object->mode != basact->object->mode) && + (oldbasact->object->mode & basact->object->mode) == 0) { + basact = NULL; + } } } } } - /* Ensure code above doesn't change the active base. */ + /* Ensure code above doesn't change the active base. This code is already fairly involved, + * it's best if changing the active object is localized to a single place. */ BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL)); bool found = (basact != NULL); @@ -2620,20 +2693,22 @@ static bool ed_object_select_pick(bContext *C, else if (found || params->deselect_all) { /* Deselect everything. */ /* `basact` may be NULL. */ - changed |= object_deselect_all_except(view_layer, basact); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + if (object_deselect_all_except(view_layer, basact)) { + changed_object = true; + } } } } - /* so, do we have something selected? */ if ((handled == false) && found) { - changed = true; if (vc.obedit) { - /* Only do the select (use for setting vertex parents & hooks). */ + /* Only do the select (use for setting vertex parents & hooks). + * In edit-mode do not activate. */ object_deselect_all_except(view_layer, basact); ED_object_base_select(basact, BA_SELECT); + + changed_object = true; } /* Also prevent making it active on mouse selection. */ else if (BASE_SELECTABLE(v3d, basact)) { @@ -2661,11 +2736,8 @@ static bool ed_object_select_pick(bContext *C, break; } case SEL_OP_SET: { - /* When enabled, this puts other objects out of multi pose-mode. */ - if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) { - object_deselect_all_except(view_layer, basact); - ED_object_base_select(basact, BA_SELECT); - } + object_deselect_all_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); break; } case SEL_OP_AND: { @@ -2673,52 +2745,37 @@ static bool ed_object_select_pick(bContext *C, break; } } - } - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + changed_object = true; + } } + /* Perform the activation even when 'handled', since this is used to ensure + * the object from the pose-bone selected is also activated. */ if (use_activate_selected_base && (basact != NULL)) { - changed = true; + changed_object = true; ED_object_base_activate(C, basact); /* adds notifier */ if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) { WM_toolsystem_update_from_context_view3d(C); } } - if (changed) { - if (use_activate_selected_base) { - /* Set special modes for grease pencil - * The grease pencil modes are not real modes, but a hack to make the interface - * consistent, so need some tricks to keep UI synchronized */ - /* XXX(@aligorith): This stuff needs reviewing. */ - if (false && (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || - (basact->object->type == OB_GPENCIL))) { - /* set cursor */ - if (ELEM(basact->object->mode, - OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, - OB_MODE_WEIGHT_GPENCIL, - OB_MODE_VERTEX_GPENCIL)) { - ED_gpencil_toggle_brush_cursor(C, true, NULL); - } - else { - /* TODO: maybe is better use restore. */ - ED_gpencil_toggle_brush_cursor(C, false, NULL); - } - } - } + if (changed_object) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (vc.obact && vc.obact->mode & OB_MODE_POSE) { - ED_outliner_select_sync_from_pose_bone_tag(C); - } - else { - ED_outliner_select_sync_from_object_tag(C); - } + ED_outliner_select_sync_from_object_tag(C); } - return changed; + if (changed_pose) { + ED_outliner_select_sync_from_pose_bone_tag(C); + } + + if (gpu != NULL) { + MEM_freeN(gpu); + } + + return (changed_object || changed_pose || changed_track); } /** @@ -2815,11 +2872,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op) bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); /* Only force object select for edit-mode to support vertex parenting, * or paint-select to allow pose bone select with vert/face select. */ - bool object = (RNA_boolean_get(op->ptr, "object") && - (obedit || BKE_paint_select_elem_test(obact) || - /* so its possible to select bones in weight-paint mode (LMB select) */ - (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) && - BKE_object_pose_armature_get(obact)))); + bool object_only = (RNA_boolean_get(op->ptr, "object") && + (obedit || BKE_paint_select_elem_test(obact) || + /* so its possible to select bones in weight-paint mode (LMB select) */ + (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) && + BKE_object_pose_armature_get(obact)))); /* This could be called "changed_or_found" since this is true when there is an element * under the cursor to select, even if it happens that the selection & active state doesn't @@ -2832,7 +2889,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); - if (object) { + if (object_only) { obedit = NULL; obact = NULL; @@ -2842,7 +2899,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) center = false; } - if (obedit && object == false) { + if (obedit && object_only == false) { if (obedit->type == OB_MESH) { changed = EDBM_select_pick(C, mval, ¶ms); } @@ -2884,7 +2941,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) changed = ed_wpaint_vertex_select_pick(C, mval, ¶ms, obact); } else { - changed = ed_object_select_pick(C, mval, ¶ms, center, enumerate, object); + changed = ed_object_select_pick(C, mval, ¶ms, center, enumerate, object_only); } /* Pass-through flag may be cleared, see #WM_operator_flag_only_pass_through_on_press. */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 8b7133892ff..87053fe03d1 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -440,6 +440,44 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_object_active, void *data); +static bool snap_object_is_snappable(const SnapObjectContext *sctx, + const eSnapSelect snap_select, + const Base *base_act, + const Base *base, + const bool is_in_object_mode) +{ + if (!BASE_VISIBLE(sctx->runtime.v3d, base)) { + return false; + } + + if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { + return true; + } + + if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) { + return false; + } + + if (snap_select == SNAP_NOT_ACTIVE) { + return base_act == base; + } + + if (snap_select == SNAP_NOT_SELECTED) { + if (is_in_object_mode) { + return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)); + } + + /* What is selectable or not is part of the object and depends on the mode. */ + return true; + } + + if (snap_select == SNAP_SELECTABLE) { + return (base->flag & BASE_SELECTABLE) != 0; + } + + return true; +} + /** * Walks through all objects in the scene to create the list of objects to snap. */ @@ -458,38 +496,13 @@ static void iter_snap_objects(SnapObjectContext *sctx, return; } + const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { - if (!BASE_VISIBLE(sctx->runtime.v3d, base)) { - continue; - } - - if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) { - /* pass */ - } - else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) { + if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) { continue; } const bool is_object_active = (base == base_act); - if (snap_select == SNAP_NOT_ACTIVE) { - if (is_object_active) { - continue; - } - } - else if (snap_select == SNAP_NOT_SELECTED) { - if (is_object_active && base->object->mode != OB_MODE_OBJECT) { - /* Pass. Consider the selection of elements being edited. */ - } - else if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) { - continue; - } - } - else if (snap_select == SNAP_SELECTABLE) { - if (!(base->flag & BASE_SELECTABLE)) { - continue; - } - } - Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base->object); if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) { ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 938b798f4b6..ed4aa6985c4 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -2388,12 +2388,11 @@ void UV_OT_select_all(wmOperatorType *ot) /** \name Mouse Select Operator * \{ */ -static int uv_mouse_select_multi(bContext *C, - Object **objects, - uint objects_len, - const float co[2], - const bool extend, - const bool deselect_all) +static bool uv_mouse_select_multi(bContext *C, + Object **objects, + uint objects_len, + const float co[2], + const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); const ARegion *region = CTX_wm_region(C); @@ -2477,117 +2476,145 @@ static int uv_mouse_select_multi(bContext *C, } } - if (!found_item) { - if (deselect_all) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + bool found = found_item; + bool changed = false; + + bool is_selected = false; + if (found) { + Object *obedit = hit.ob; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (selectmode == UV_SELECT_FACE) { + is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset); + } + else if (selectmode == UV_SELECT_EDGE) { + is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset); + } + else { /* Vertex or island. */ + is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + } + } + if (params->sel_op == SEL_OP_SET) { + if ((found && params->select_passthrough) && is_selected) { + found = false; + } + else if (found || params->deselect_all) { + /* Deselect everything. */ + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; uv_select_tag_update_for_object(depsgraph, ts, obedit); } - - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; + changed = true; } - return OPERATOR_CANCELLED; } - Object *obedit = hit.ob; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + if (found) { + Object *obedit = hit.ob; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - /* do selection */ - if (selectmode == UV_SELECT_ISLAND) { - if (!extend) { - uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit); - } - /* Current behavior of 'extend' - * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi(scene, objects, objects_len, &hit, false, false, extend, false); - } - else if (extend) { - bool select = true; - if (selectmode == UV_SELECT_VERTEX) { - /* (de)select uv vertex */ - select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* (de)select edge */ - select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* (de)select face */ - select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); - uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset); - flush = -1; + if (selectmode == UV_SELECT_ISLAND) { + const bool extend = params->sel_op == SEL_OP_ADD; + const bool deselect = params->sel_op == SEL_OP_SUB; + const bool toggle = params->sel_op == SEL_OP_XOR; + /* Current behavior of 'extend' + * is actually toggling, so pass extend flag as 'toggle' here */ + uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false); + /* TODO: check if this actually changed. */ + changed = true; } + else { + BLI_assert(ELEM(selectmode, UV_SELECT_VERTEX, UV_SELECT_EDGE, UV_SELECT_FACE)); + bool select_value = false; + switch (params->sel_op) { + case SEL_OP_ADD: { + select_value = true; + break; + } + case SEL_OP_SUB: { + select_value = false; + break; + } + case SEL_OP_XOR: { + select_value = !is_selected; + break; + } + case SEL_OP_SET: { + /* Deselect has already been performed. */ + select_value = true; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } + } - /* de-selecting an edge may deselect a face too - validate */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (select == false) { - BM_select_history_validate(em->bm); + if (selectmode == UV_SELECT_FACE) { + uvedit_face_select_set_with_sticky( + scene, em, hit.efa, select_value, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + uvedit_edge_select_set_with_sticky( + scene, em, hit.l, select_value, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_VERTEX) { + uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, cd_loop_uv_offset); + flush = 1; + } + else { + BLI_assert_unreachable(); } - } - /* (de)select sticky uv nodes */ - if (sticky != SI_STICKY_DISABLE) { - flush = select ? 1 : -1; - } - } - else { - const bool select = true; - /* deselect all */ - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + /* De-selecting an edge may deselect a face too - validate. */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (select_value == false) { + BM_select_history_validate(em->bm); + } + } - if (selectmode == UV_SELECT_VERTEX) { - /* select vertex */ - uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* select edge */ - uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* select face */ - uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset); - flush = 1; + /* (de)select sticky UV nodes. */ + if (sticky != SI_STICKY_DISABLE) { + flush = select_value ? 1 : -1; + } + + changed = true; } - } - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (flush != 0) { - EDBM_selectmode_flush(em); + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (flush != 0) { + EDBM_selectmode_flush(em); + } + } + else { + /* Setting the selection implies a single element, which doesn't need to be flushed. */ + if (params->sel_op != SEL_OP_SET) { + ED_uvedit_selectmode_flush(scene, em); + } } - } - /* #extend=false implies single vertex selection, which doesn't need to be flushed. */ - else if (extend) { - ED_uvedit_selectmode_flush(scene, em); } - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obiter = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obiter); + if (changed && found) { + /* Only update the `hit` object as de-selecting all will have refreshed the others. */ + Object *obedit = hit.ob; + uv_select_tag_update_for_object(depsgraph, ts, obedit); } - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; + return changed || found; } -static int uv_mouse_select(bContext *C, - const float co[2], - const bool extend, - const bool deselect_all) +static bool uv_mouse_select(bContext *C, const float co[2], const struct SelectPick_Params *params) { ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all); + bool changed = uv_mouse_select_multi(C, objects, objects_len, co, params); MEM_freeN(objects); - return ret; + return changed; } static int uv_select_exec(bContext *C, wmOperator *op) @@ -2595,10 +2622,20 @@ static int uv_select_exec(bContext *C, wmOperator *op) float co[2]; RNA_float_get_array(op->ptr, "location", co); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const struct SelectPick_Params params = { + .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle")), + .deselect_all = RNA_boolean_get(op->ptr, "deselect_all"), + .select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough"), + }; - return uv_mouse_select(C, co, extend, deselect_all); + const bool changed = uv_mouse_select(C, co, ¶ms); + + if (changed) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -2629,18 +2666,8 @@ void UV_OT_select(wmOperatorType *ot) /* properties */ PropertyRNA *prop; - prop = RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, - "deselect_all", - false, - "Deselect On Nothing", - "Deselect all when nothing under the cursor"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + WM_operator_properties_mouse_select(ot); prop = RNA_def_float_vector( ot->srna, diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 3ed99052753..63300656fda 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -2969,6 +2969,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) me, (&(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); /* select all uv loops first - pack parameters needs this to make sure charts are registered */ ED_uvedit_select_all(bm); diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt index 2a5a2d0d957..c2fad9fef3a 100644 --- a/source/blender/freestyle/CMakeLists.txt +++ b/source/blender/freestyle/CMakeLists.txt @@ -508,8 +508,6 @@ set(SRC intern/view_map/ViewMapAdvancedIterators.h intern/view_map/ViewMapBuilder.cpp intern/view_map/ViewMapBuilder.h - intern/view_map/ViewMapIO.cpp - intern/view_map/ViewMapIO.h intern/view_map/ViewMapIterators.h intern/view_map/ViewMapTesselator.cpp intern/view_map/ViewMapTesselator.h diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index 024bc80f3fa..cc815b5317f 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -36,7 +36,6 @@ extern "C" { #include "../view_map/SteerableViewMap.h" #include "../view_map/ViewMap.h" -#include "../view_map/ViewMapIO.h" #include "../view_map/ViewMapTesselator.h" #include "../winged_edge/Curvature.h" @@ -1099,13 +1098,10 @@ void Controller::init_options() Config::Path *cpath = Config::Path::getInstance(); // Directories - ViewMapIO::Options::setModelsPath(cpath->getModelsPath()); TextureManager::Options::setPatternsPath(cpath->getPatternsPath()); TextureManager::Options::setBrushesPath(cpath->getModelsPath()); // ViewMap Format - ViewMapIO::Options::rmFlags(ViewMapIO::Options::FLOAT_VECTORS); - ViewMapIO::Options::rmFlags(ViewMapIO::Options::NO_OCCLUDERS); setComputeSteerableViewMapFlag(false); // Visibility diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index 63585df97a9..96bab8c2028 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -31,6 +31,13 @@ #include "BPy_ViewMap.h" #include "BPy_ViewShape.h" +#include "BKE_appdir.h" +#include "DNA_scene_types.h" +#include "FRS_freestyle.h" +#include "RNA_access.h" +#include "RNA_prototypes.h" +#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */ + #ifdef __cplusplus extern "C" { #endif @@ -39,13 +46,6 @@ extern "C" { //------------------------ MODULE FUNCTIONS ---------------------------------- -#include "BKE_appdir.h" -#include "DNA_scene_types.h" -#include "FRS_freestyle.h" -#include "RNA_access.h" -#include "RNA_prototypes.h" -#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */ - static char Freestyle_getCurrentScene___doc__[] = ".. function:: getCurrentScene()\n" "\n" diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp deleted file mode 100644 index 47d9e61ba2f..00000000000 --- a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp +++ /dev/null @@ -1,1294 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup freestyle - * \brief Functions to manage I/O for the view map - */ - -#include <climits> - -#include "ViewMapIO.h" - -#ifdef IRIX -# define WRITE(n) Internal::write<sizeof((n))>(out, (const char *)(&(n))) -# define READ(n) Internal::read<sizeof((n))>(in, (char *)(&(n))) -#else -# define WRITE(n) out.write((const char *)(&(n)), sizeof((n))) -# define READ(n) in.read((char *)(&(n)), sizeof((n))) -#endif - -#define WRITE_IF_NON_NULL(ptr) \ - if (ptr) { \ - WRITE((ptr)->userdata); \ - } \ - else { \ - WRITE(ZERO); \ - } \ - (void)0 - -#define READ_IF_NON_NULL(ptr, array) \ - READ(tmp); \ - if (tmp) { \ - (ptr) = (array)[tmp]; \ - } \ - else { \ - (ptr) = NULL; \ - } \ - (void)0 - -namespace Freestyle::ViewMapIO { - -namespace Internal { - -static ViewMap *g_vm; - -//////////////////// 'load' Functions //////////////////// - -inline int load(istream &in, Vec3r &v) -{ - if (Options::getFlags() & Options::FLOAT_VECTORS) { - float tmp; - READ(tmp); - v[0] = tmp; - READ(tmp); - v[1] = tmp; - READ(tmp); - v[2] = tmp; - } - else { - Vec3r::value_type tmp; - READ(tmp); - v[0] = tmp; - READ(tmp); - v[1] = tmp; - READ(tmp); - v[2] = tmp; - } - return 0; -} - -inline int load(istream &in, Polygon3r &p) -{ - unsigned tmp; - - // Id - READ(tmp); - p.setId(tmp); - - // vertices (List) - vector<Vec3r> tmp_vec; - Vec3r v; - READ(tmp); - for (unsigned int i = 0; i < tmp; i++) { - load(in, v); - tmp_vec.push_back(v); - } - p.setVertices(tmp_vec); - - // min & max - // Already computed (in the SetVertices() method) - - return 0; -} - -inline int load(istream &in, FrsMaterial &m) -{ - float tmp_array[4]; - int i; - - // Diffuse - for (i = 0; i < 4; i++) { - READ(tmp_array[i]); - } - m.setDiffuse(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); - - // Specular - for (i = 0; i < 4; i++) { - READ(tmp_array[i]); - } - m.setSpecular(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); - - // Ambient - for (i = 0; i < 4; i++) { - READ(tmp_array[i]); - } - m.setAmbient(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); - - // Emission - for (i = 0; i < 4; i++) { - READ(tmp_array[i]); - } - m.setEmission(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); - - // Shininess - READ(tmp_array[0]); - m.setShininess(tmp_array[0]); - - return 0; -} - -static int load(istream &in, ViewShape *vs) -{ - if (!vs || !vs->sshape()) { - return 1; - } - - // SShape - - // -> Id - Id::id_type id1, id2; - READ(id1); - READ(id2); - vs->sshape()->setId(Id(id1, id2)); - - // -> Importance - float importance; - READ(importance); - vs->sshape()->setImportance(importance); - - // -> BBox - // Not necessary (only used during view map computatiom) - - unsigned i, size, tmp; - - // -> Material - READ(size); - vector<FrsMaterial> frs_materials; - FrsMaterial m; - for (i = 0; i < size; ++i) { - load(in, m); - frs_materials.push_back(m); - } - vs->sshape()->setFrsMaterials(frs_materials); - - // -> VerticesList (List) - READ(size); - for (i = 0; i < size; i++) { - SVertex *sv; - READ_IF_NON_NULL(sv, g_vm->SVertices()); - vs->sshape()->AddNewVertex(sv); - } - - // -> Chains (List) - READ(size); - for (i = 0; i < size; i++) { - FEdge *fe; - READ_IF_NON_NULL(fe, g_vm->FEdges()); - vs->sshape()->AddChain(fe); - } - - // -> EdgesList (List) - READ(size); - for (i = 0; i < size; i++) { - FEdge *fe; - READ_IF_NON_NULL(fe, g_vm->FEdges()); - vs->sshape()->AddEdge(fe); - } - - // ViewEdges (List) - READ(size); - for (i = 0; i < size; i++) { - ViewEdge *ve; - READ_IF_NON_NULL(ve, g_vm->ViewEdges()); - vs->AddEdge(ve); - } - - // ViewVertices (List) - READ(size); - for (i = 0; i < size; i++) { - ViewVertex *vv; - READ_IF_NON_NULL(vv, g_vm->ViewVertices()); - vs->AddVertex(vv); - } - - return 0; -} - -static int load(istream &in, FEdge *fe) -{ - if (!fe) { - return 1; - } - - bool b; - - FEdgeSmooth *fesmooth = nullptr; - FEdgeSharp *fesharp = nullptr; - if (fe->isSmooth()) { - fesmooth = dynamic_cast<FEdgeSmooth *>(fe); - } - else { - fesharp = dynamic_cast<FEdgeSharp *>(fe); - } - - // Id - Id::id_type id1, id2; - READ(id1); - READ(id2); - fe->setId(Id(id1, id2)); - - // Nature - Nature::EdgeNature nature; - READ(nature); - fe->setNature(nature); - -#if 0 // hasVisibilityPoint - bool b; - READ(b); - fe->setHasVisibilityPoint(b); -#endif - - Vec3r v; - unsigned int matindex; - -#if 0 - // VisibilityPointA - load(in, v); - fe->setVisibilityPointA(v); - - // VisibilityPointB - load(in, v); - fe->setVisibilityPointB(v); -#endif - - if (fe->isSmooth()) { - // Normal - load(in, v); - fesmooth->setNormal(v); - - // Material - READ(matindex); - fesmooth->setFrsMaterialIndex(matindex); - } - else { - // aNormal - load(in, v); - fesharp->setNormalA(v); - - // bNormal - load(in, v); - fesharp->setNormalB(v); - - // Materials - READ(matindex); - fesharp->setaFrsMaterialIndex(matindex); - READ(matindex); - fesharp->setbFrsMaterialIndex(matindex); - } - - unsigned tmp; - - // VertexA - SVertex *sva; - READ_IF_NON_NULL(sva, g_vm->SVertices()); - fe->setVertexA(sva); - - // VertexB - SVertex *svb; - READ_IF_NON_NULL(svb, g_vm->SVertices()); - fe->setVertexB(svb); - - // NextEdge - FEdge *nfe; - READ_IF_NON_NULL(nfe, g_vm->FEdges()); - fe->setNextEdge(nfe); - - // PreviousEdge - FEdge *pfe; - READ_IF_NON_NULL(pfe, g_vm->FEdges()); - fe->setPreviousEdge(pfe); - - // ViewEdge - ViewEdge *ve; - READ_IF_NON_NULL(ve, g_vm->ViewEdges()); - fe->setViewEdge(ve); - - // Face - // Not necessary (only used during view map computatiom) - - Polygon3r p; - - // aFace - load(in, p); - fe->setaFace(p); - - // occludeeEmpty - READ(b); - fe->setOccludeeEmpty(b); - - // occludeeIntersection - load(in, v); - fe->setOccludeeIntersection(v); - - return 0; -} - -static int load(istream &in, SVertex *sv) -{ - if (!sv) { - return 1; - } - - // Id - Id::id_type id1, id2; - READ(id1); - READ(id2); - sv->setId(Id(id1, id2)); - - Vec3r v; - - // Point3D - load(in, v); - sv->setPoint3D(v); - - // Point2D - load(in, v); - sv->setPoint2D(v); - - unsigned tmp; - - // Shape - ViewShape *vs; - READ_IF_NON_NULL(vs, g_vm->ViewShapes()); - sv->setShape(vs->sshape()); - - // pViewVertex - ViewVertex *vv; - READ_IF_NON_NULL(vv, g_vm->ViewVertices()); - sv->setViewVertex(vv); - - unsigned i, size; - - // Normals (List) - READ(size); - for (i = 0; i < size; i++) { - load(in, v); - sv->AddNormal(v); - } - - // FEdges (List) - READ(size); - FEdge *fe; - for (i = 0; i < size; i++) { - READ_IF_NON_NULL(fe, g_vm->FEdges()); - sv->AddFEdge(fe); - } - - return 0; -} - -static int load(istream &in, ViewEdge *ve) -{ - if (!ve) { - return 1; - } - - unsigned tmp; - - // Id - Id::id_type id1, id2; - READ(id1); - READ(id2); - ve->setId(Id(id1, id2)); - - // Nature - Nature::EdgeNature nature; - READ(nature); - ve->setNature(nature); - - // QI - READ(tmp); - ve->setQI(tmp); - - // Shape - ViewShape *vs; - READ_IF_NON_NULL(vs, g_vm->ViewShapes()); - ve->setShape(vs); - - // aShape - ViewShape *avs; - READ_IF_NON_NULL(avs, g_vm->ViewShapes()); - ve->setaShape(avs); - - // FEdgeA - FEdge *fea; - READ_IF_NON_NULL(fea, g_vm->FEdges()); - ve->setFEdgeA(fea); - - // FEdgeB - FEdge *feb; - READ_IF_NON_NULL(feb, g_vm->FEdges()); - ve->setFEdgeB(feb); - - // A - ViewVertex *vva; - READ_IF_NON_NULL(vva, g_vm->ViewVertices()); - ve->setA(vva); - - // B - ViewVertex *vvb; - READ_IF_NON_NULL(vvb, g_vm->ViewVertices()); - ve->setB(vvb); - - // Occluders (List) - if (!(Options::getFlags() & Options::NO_OCCLUDERS)) { - unsigned size; - READ(size); - ViewShape *vso; - for (unsigned int i = 0; i < size; i++) { - READ_IF_NON_NULL(vso, g_vm->ViewShapes()); - ve->AddOccluder(vso); - } - } - - return 0; -} - -static int load(istream &in, ViewVertex *vv) -{ - if (!vv) { - return 1; - } - - unsigned tmp; - bool b; - - // Nature - Nature::VertexNature nature; - READ(nature); - vv->setNature(nature); - - if (vv->getNature() & Nature::T_VERTEX) { - TVertex *tv = dynamic_cast<TVertex *>(vv); - - // Id - Id::id_type id1, id2; - READ(id1); - READ(id2); - tv->setId(Id(id1, id2)); - - // FrontSVertex - SVertex *fsv; - READ_IF_NON_NULL(fsv, g_vm->SVertices()); - tv->setFrontSVertex(fsv); - - // BackSVertex - SVertex *bsv; - READ_IF_NON_NULL(bsv, g_vm->SVertices()); - tv->setBackSVertex(bsv); - - // FrontEdgeA - ViewEdge *fea; - READ_IF_NON_NULL(fea, g_vm->ViewEdges()); - READ(b); - tv->setFrontEdgeA(fea, b); - - // FrontEdgeB - ViewEdge *feb; - READ_IF_NON_NULL(feb, g_vm->ViewEdges()); - READ(b); - tv->setFrontEdgeB(feb, b); - - // BackEdgeA - ViewEdge *bea; - READ_IF_NON_NULL(bea, g_vm->ViewEdges()); - READ(b); - tv->setBackEdgeA(bea, b); - - // BackEdgeB - ViewEdge *beb; - READ_IF_NON_NULL(beb, g_vm->ViewEdges()); - READ(b); - tv->setBackEdgeB(beb, b); - } - else if (vv->getNature() & Nature::NON_T_VERTEX) { - NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv); - - // SVertex - SVertex *sv; - READ_IF_NON_NULL(sv, g_vm->SVertices()); - ntv->setSVertex(sv); - - // ViewEdges (List) - unsigned size; - READ(size); - ViewEdge *ve; - for (unsigned int i = 0; i < size; i++) { - READ_IF_NON_NULL(ve, g_vm->ViewEdges()); - READ(b); - ntv->AddViewEdge(ve, b); - } - } - - return 0; -} - -//////////////////// 'save' Functions //////////////////// - -inline int save(ostream &out, const Vec3r &v) -{ - if (Options::getFlags() & Options::FLOAT_VECTORS) { - float tmp; - - tmp = v[0]; - WRITE(tmp); - tmp = v[1]; - WRITE(tmp); - tmp = v[2]; - WRITE(tmp); - } - else { - Vec3r::value_type tmp; - - tmp = v[0]; - WRITE(tmp); - tmp = v[1]; - WRITE(tmp); - tmp = v[2]; - WRITE(tmp); - } - return 0; -} - -inline int save(ostream &out, const Polygon3r &p) -{ - unsigned tmp; - - // Id - tmp = p.getId(); - WRITE(tmp); - - // vertices (List) - tmp = p.getVertices().size(); - WRITE(tmp); - for (vector<Vec3r>::const_iterator i = p.getVertices().begin(); i != p.getVertices().end(); - i++) { - save(out, *i); - } - - // min & max - // Do not need to be saved - - return 0; -} - -inline int save(ostream &out, const FrsMaterial &m) -{ - unsigned i; - - // Diffuse - for (i = 0; i < 4; i++) { - WRITE(m.diffuse()[i]); - } - - // Specular - for (i = 0; i < 4; i++) { - WRITE(m.specular()[i]); - } - - // Ambient - for (i = 0; i < 4; i++) { - WRITE(m.ambient()[i]); - } - - // Emission - for (i = 0; i < 4; i++) { - WRITE(m.emission()[i]); - } - - // Shininess - float shininess = m.shininess(); - WRITE(shininess); - - return 0; -} - -static int save(ostream &out, ViewShape *vs) -{ - if (!vs || !vs->sshape()) { - cerr << "Warning: null ViewShape" << endl; - return 1; - } - - unsigned tmp; - - // SShape - - // -> Id - Id::id_type id = vs->sshape()->getId().getFirst(); - WRITE(id); - id = vs->sshape()->getId().getSecond(); - WRITE(id); - - // -> Importance - float importance = vs->sshape()->importance(); - WRITE(importance); - - // -> BBox - // Not necessary (only used during view map computatiom) - - // -> Material - unsigned int size = vs->sshape()->frs_materials().size(); - WRITE(size); - for (unsigned int i = 0; i < size; ++i) { - save(out, vs->sshape()->frs_material(i)); - } - - // -> VerticesList (List) - tmp = vs->sshape()->getVertexList().size(); - WRITE(tmp); - for (vector<SVertex *>::const_iterator i1 = vs->sshape()->getVertexList().begin(); - i1 != vs->sshape()->getVertexList().end(); - i1++) { - WRITE_IF_NON_NULL(*i1); - } - - // -> Chains (List) - tmp = vs->sshape()->getChains().size(); - WRITE(tmp); - for (vector<FEdge *>::const_iterator i2 = vs->sshape()->getChains().begin(); - i2 != vs->sshape()->getChains().end(); - i2++) { - WRITE_IF_NON_NULL(*i2); - } - - // -> EdgesList (List) - tmp = vs->sshape()->getEdgeList().size(); - WRITE(tmp); - for (vector<FEdge *>::const_iterator i3 = vs->sshape()->getEdgeList().begin(); - i3 != vs->sshape()->getEdgeList().end(); - i3++) { - WRITE_IF_NON_NULL(*i3); - } - - // ViewEdges (List) - tmp = vs->edges().size(); - WRITE(tmp); - for (vector<ViewEdge *>::const_iterator i4 = vs->edges().begin(); i4 != vs->edges().end(); - i4++) { - WRITE_IF_NON_NULL(*i4); - } - - // ViewVertices (List) - tmp = vs->vertices().size(); - WRITE(tmp); - for (vector<ViewVertex *>::const_iterator i5 = vs->vertices().begin(); - i5 != vs->vertices().end(); - i5++) { - WRITE_IF_NON_NULL(*i5); - } - - return 0; -} - -static int save(ostream &out, FEdge *fe) -{ - if (!fe) { - cerr << "Warning: null FEdge" << endl; - return 1; - } - - FEdgeSmooth *fesmooth = dynamic_cast<FEdgeSmooth *>(fe); - FEdgeSharp *fesharp = dynamic_cast<FEdgeSharp *>(fe); - - // Id - Id::id_type id = fe->getId().getFirst(); - WRITE(id); - id = fe->getId().getSecond(); - WRITE(id); - - // Nature - Nature::EdgeNature nature = fe->getNature(); - WRITE(nature); - - bool b; - -#if 0 - // hasVisibilityPoint - b = fe->hasVisibilityPoint(); - WRITE(b); - - // VisibilityPointA - save(out, fe->visibilityPointA()); - - // VisibilityPointB - save(out, fe->visibilityPointB()); -#endif - - unsigned index; - if (fe->isSmooth()) { - // normal - save(out, fesmooth->normal()); - // material - index = fesmooth->frs_materialIndex(); - WRITE(index); - } - else { - // aNormal - save(out, fesharp->normalA()); - // bNormal - save(out, fesharp->normalB()); - // aMaterial - index = fesharp->aFrsMaterialIndex(); - WRITE(index); - // bMaterial - index = fesharp->bFrsMaterialIndex(); - WRITE(index); - } - - // VertexA - WRITE_IF_NON_NULL(fe->vertexA()); - - // VertexB - WRITE_IF_NON_NULL(fe->vertexB()); - - // NextEdge - WRITE_IF_NON_NULL(fe->nextEdge()); - - // PreviousEdge - WRITE_IF_NON_NULL(fe->previousEdge()); - - // ViewEdge - WRITE_IF_NON_NULL(fe->viewedge()); - - // Face - // Not necessary (only used during view map computatiom) - - // aFace - save(out, (Polygon3r &)fe->aFace()); - - // occludeeEmpty - b = fe->getOccludeeEmpty(); - WRITE(b); - - // occludeeIntersection - save(out, fe->getOccludeeIntersection()); - - return 0; -} - -static int save(ostream &out, SVertex *sv) -{ - if (!sv) { - cerr << "Warning: null SVertex" << endl; - return 1; - } - - unsigned tmp; - - // Id - Id::id_type id = sv->getId().getFirst(); - WRITE(id); - id = sv->getId().getSecond(); - WRITE(id); - - Vec3r v; - - // Point3D - v = sv->point3D(); - save(out, sv->point3D()); - - // Point2D - v = sv->point2D(); - save(out, v); - - // Shape - WRITE_IF_NON_NULL(sv->shape()); - - // pViewVertex - WRITE_IF_NON_NULL(sv->viewvertex()); - - // Normals (List) - // NOTE: the 'size()' method of a set doesn't seem to return the actual size of the given set, so - // we have to hack it... - set<Vec3r>::const_iterator i; - for (i = sv->normals().begin(), tmp = 0; i != sv->normals().end(); i++, tmp++) { - /* pass */ - } - WRITE(tmp); - for (i = sv->normals().begin(); i != sv->normals().end(); i++) { - save(out, *i); - } - - // FEdges (List) - tmp = sv->fedges().size(); - WRITE(tmp); - for (vector<FEdge *>::const_iterator j = sv->fedges_begin(); j != sv->fedges_end(); j++) { - WRITE_IF_NON_NULL(*j); - } - - return 0; -} - -static int save(ostream &out, ViewEdge *ve) -{ - if (!ve) { - cerr << "Warning: null ViewEdge" << endl; - return 1; - } - - unsigned tmp; - - // Id - Id::id_type id = ve->getId().getFirst(); - WRITE(id); - id = ve->getId().getSecond(); - WRITE(id); - - // Nature - Nature::EdgeNature nature = ve->getNature(); - WRITE(nature); - - // QI - unsigned qi = ve->qi(); - WRITE(qi); - - // Shape - WRITE_IF_NON_NULL(ve->shape()); - - // aShape - WRITE_IF_NON_NULL(ve->aShape()); - - // FEdgeA - WRITE_IF_NON_NULL(ve->fedgeA()); - - // FEdgeB - WRITE_IF_NON_NULL(ve->fedgeB()); - - // A - WRITE_IF_NON_NULL(ve->A()); - - // B - WRITE_IF_NON_NULL(ve->B()); - - // Occluders (List) - if (!(Options::getFlags() & Options::NO_OCCLUDERS)) { - tmp = ve->occluders().size(); - WRITE(tmp); - for (vector<ViewShape *>::const_iterator i = ve->occluders().begin(); - i != ve->occluders().end(); - i++) { - WRITE_IF_NON_NULL((*i)); - } - } - - return 0; -} - -static int save(ostream &out, ViewVertex *vv) -{ - if (!vv) { - cerr << "Warning: null ViewVertex" << endl; - return 1; - } - - // Nature - Nature::VertexNature nature = vv->getNature(); - WRITE(nature); - - if (vv->getNature() & Nature::T_VERTEX) { - TVertex *tv = dynamic_cast<TVertex *>(vv); - - // Id - Id::id_type id = tv->getId().getFirst(); - WRITE(id); - id = tv->getId().getSecond(); - WRITE(id); - - // FrontSVertex - WRITE_IF_NON_NULL(tv->frontSVertex()); - - // BackSVertex - WRITE_IF_NON_NULL(tv->backSVertex()); - - // FrontEdgeA - WRITE_IF_NON_NULL(tv->frontEdgeA().first); - WRITE(tv->frontEdgeA().second); - - // FrontEdgeB - WRITE_IF_NON_NULL(tv->frontEdgeB().first); - WRITE(tv->frontEdgeB().second); - - // BackEdgeA - WRITE_IF_NON_NULL(tv->backEdgeA().first); - WRITE(tv->backEdgeA().second); - - // BackEdgeB - WRITE_IF_NON_NULL(tv->backEdgeB().first); - WRITE(tv->backEdgeB().second); - } - else if (vv->getNature() & Nature::NON_T_VERTEX) { - NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv); - - // SVertex - WRITE_IF_NON_NULL(ntv->svertex()); - - // ViewEdges (List) - unsigned size = ntv->viewedges().size(); - WRITE(size); - vector<ViewVertex::directedViewEdge>::const_iterator i = ntv->viewedges().begin(); - for (; i != ntv->viewedges().end(); i++) { - WRITE_IF_NON_NULL(i->first); - WRITE(i->second); - } - } - else { - cerr << "Warning: unexpected ViewVertex nature" << endl; - return 1; - } - - return 0; -} - -} // End of namespace Internal - -//////////////////// "Public" 'load' and 'save' functions //////////////////// - -#define SET_PROGRESS(n) \ - if (pb) { \ - pb->setProgress((n)); \ - } \ - (void)0 - -int load(istream &in, ViewMap *vm, ProgressBar *pb) -{ - if (!vm) { - return 1; - } - - // soc unused - unsigned tmp; - int err = 0; - Internal::g_vm = vm; - - // Management of the progress bar (if present) - if (pb) { - pb->reset(); - pb->setLabelText("Loading View Map..."); - pb->setTotalSteps(6); - pb->setProgress(0); - } - - // Read and set the options - unsigned char flags; - READ(flags); - Options::setFlags(flags); - - // Read the size of the five ViewMap's lists (with some extra information for the ViewVertices) - // and instantiate them (with default costructors) - unsigned vs_s, fe_s, fe_rle1, fe_rle2, sv_s, ve_s, vv_s, vv_rle1, vv_rle2; - READ(vs_s); - READ(fe_s); - - if (fe_s) { - bool b; - READ(b); - /* NOLINTNEXTLINE: bugprone-infinite-loop */ - for (READ(fe_rle1), fe_rle2 = 0; fe_rle1 <= fe_s; fe_rle2 = fe_rle1, READ(fe_rle1)) { - if (b) { - for (unsigned int i = fe_rle2; i < fe_rle1; i++) { - FEdgeSmooth *fes = new FEdgeSmooth; - vm->AddFEdge(fes); - } - b = !b; - } - else if (!b) { - for (unsigned int i = fe_rle2; i < fe_rle1; i++) { - FEdgeSharp *fes = new FEdgeSharp; - vm->AddFEdge(fes); - } - b = !b; - } - } - } - - READ(sv_s); - READ(ve_s); - READ(vv_s); - - if (vv_s) { - Nature::VertexNature nature; - READ(nature); - /* NOLINTNEXTLINE: bugprone-infinite-loop */ - for (READ(vv_rle1), vv_rle2 = 0; vv_rle1 <= vv_s; vv_rle2 = vv_rle1, READ(vv_rle1)) { - if (nature & Nature::T_VERTEX) { - for (unsigned int i = vv_rle2; i < vv_rle1; i++) { - TVertex *tv = new TVertex(); - vm->AddViewVertex(tv); - } - nature = Nature::NON_T_VERTEX; - } - else if (nature & Nature::NON_T_VERTEX) { - for (unsigned int i = vv_rle2; i < vv_rle1; i++) { - NonTVertex *ntv = new NonTVertex(); - vm->AddViewVertex(ntv); - } - nature = Nature::T_VERTEX; - } - } - } - - for (unsigned int i0 = 0; i0 < vs_s; i0++) { - SShape *ss = new SShape(); - ViewShape *vs = new ViewShape(); - vs->setSShape(ss); - ss->setViewShape(vs); - vm->AddViewShape(vs); - } -#if 0 - for (unsigned int i1 = 0; i1 < fe_s; i1++) { - FEdge *fe = new FEdge(); - vm->AddFEdge(fe); - } -#endif - for (unsigned int i2 = 0; i2 < sv_s; i2++) { - SVertex *sv = new SVertex(); - vm->AddSVertex(sv); - } - for (unsigned int i3 = 0; i3 < ve_s; i3++) { - ViewEdge *ve = new ViewEdge(); - vm->AddViewEdge(ve); - } - - // Read the values for all the objects created above - SET_PROGRESS(1); - for (vector<ViewShape *>::const_iterator i4 = vm->ViewShapes().begin(); - i4 != vm->ViewShapes().end(); - i4++) { - err += Internal::load(in, *i4); - } - SET_PROGRESS(2); - for (vector<FEdge *>::const_iterator i5 = vm->FEdges().begin(); i5 != vm->FEdges().end(); i5++) { - err += Internal::load(in, *i5); - } - SET_PROGRESS(3); - for (vector<SVertex *>::const_iterator i6 = vm->SVertices().begin(); i6 != vm->SVertices().end(); - i6++) { - err += Internal::load(in, *i6); - } - SET_PROGRESS(4); - for (vector<ViewEdge *>::const_iterator i7 = vm->ViewEdges().begin(); - i7 != vm->ViewEdges().end(); - i7++) { - err += Internal::load(in, *i7); - } - SET_PROGRESS(5); - for (vector<ViewVertex *>::const_iterator i8 = vm->ViewVertices().begin(); - i8 != vm->ViewVertices().end(); - i8++) { - err += Internal::load(in, *i8); - } - SET_PROGRESS(6); - - // Read the shape id to index mapping - unsigned map_s; - READ(map_s); - unsigned id, index; - for (unsigned int i4 = 0; i4 < map_s; ++i4) { - READ(id); - READ(index); - vm->shapeIdToIndexMap()[id] = index; - } - - return err; -} - -int save(ostream &out, ViewMap *vm, ProgressBar *pb) -{ - if (!vm) { - return 1; - } - - int err = 0; - - // Management of the progress bar (if present) - if (pb) { - pb->reset(); - pb->setLabelText("Saving View Map..."); - pb->setTotalSteps(6); - pb->setProgress(0); - } - - // For every object, initialize its userdata member to its index in the ViewMap list - for (unsigned int i0 = 0; i0 < vm->ViewShapes().size(); i0++) { - vm->ViewShapes()[i0]->userdata = POINTER_FROM_UINT(i0); - vm->ViewShapes()[i0]->sshape()->userdata = POINTER_FROM_UINT(i0); - } - for (unsigned int i1 = 0; i1 < vm->FEdges().size(); i1++) { - vm->FEdges()[i1]->userdata = POINTER_FROM_UINT(i1); - } - for (unsigned int i2 = 0; i2 < vm->SVertices().size(); i2++) { - vm->SVertices()[i2]->userdata = POINTER_FROM_UINT(i2); - } - for (unsigned int i3 = 0; i3 < vm->ViewEdges().size(); i3++) { - vm->ViewEdges()[i3]->userdata = POINTER_FROM_UINT(i3); - } - for (unsigned int i4 = 0; i4 < vm->ViewVertices().size(); i4++) { - vm->ViewVertices()[i4]->userdata = POINTER_FROM_UINT(i4); - } - - // Write the current options - unsigned char flags = Options::getFlags(); - WRITE(flags); - - // Write the size of the five lists (with some extra information for the ViewVertices) - unsigned size; - size = vm->ViewShapes().size(); - WRITE(size); - size = vm->FEdges().size(); - WRITE(size); - if (size) { - bool b = vm->FEdges()[0]->isSmooth(); - WRITE(b); - for (unsigned int i = 0; i < size; i++) { - while (i < size && (vm->FEdges()[i]->isSmooth() == b)) { - i++; - } - if (i < size) { - WRITE(i); - b = !b; - } - } - WRITE(size); - size++; - WRITE(size); - } - size = vm->SVertices().size(); - WRITE(size); - size = vm->ViewEdges().size(); - WRITE(size); - size = vm->ViewVertices().size(); - WRITE(size); - if (size) { - Nature::VertexNature nature = vm->ViewVertices()[0]->getNature(); - WRITE(nature); - nature &= ~Nature::VIEW_VERTEX; - for (unsigned int i = 0; i < size; i++) { - while (i < size && (vm->ViewVertices()[i]->getNature() & nature)) { - i++; - } - if (i < size) { - WRITE(i); - nature = vm->ViewVertices()[i]->getNature() & ~Nature::VIEW_VERTEX; - } - } - WRITE(size); - size++; - WRITE(size); - } - - // Write all the elts of the ViewShapes List - SET_PROGRESS(1); - for (vector<ViewShape *>::const_iterator i5 = vm->ViewShapes().begin(); - i5 != vm->ViewShapes().end(); - i5++) { - err += Internal::save(out, *i5); - } - SET_PROGRESS(2); - for (vector<FEdge *>::const_iterator i6 = vm->FEdges().begin(); i6 != vm->FEdges().end(); i6++) { - err += Internal::save(out, *i6); - } - SET_PROGRESS(3); - for (vector<SVertex *>::const_iterator i7 = vm->SVertices().begin(); i7 != vm->SVertices().end(); - i7++) { - err += Internal::save(out, *i7); - } - SET_PROGRESS(4); - for (vector<ViewEdge *>::const_iterator i8 = vm->ViewEdges().begin(); - i8 != vm->ViewEdges().end(); - i8++) { - err += Internal::save(out, *i8); - } - SET_PROGRESS(5); - for (vector<ViewVertex *>::const_iterator i9 = vm->ViewVertices().begin(); - i9 != vm->ViewVertices().end(); - i9++) { - err += Internal::save(out, *i9); - } - - // Write the shape id to index mapping - size = vm->shapeIdToIndexMap().size(); - WRITE(size); - unsigned int id, index; - for (ViewMap::id_to_index_map::iterator mit = vm->shapeIdToIndexMap().begin(), - mitend = vm->shapeIdToIndexMap().end(); - mit != mitend; - ++mit) { - id = mit->first; - index = mit->second; - WRITE(id); - WRITE(index); - } - - // Reset 'userdata' members - for (vector<ViewShape *>::const_iterator j0 = vm->ViewShapes().begin(); - j0 != vm->ViewShapes().end(); - j0++) { - (*j0)->userdata = nullptr; - (*j0)->sshape()->userdata = nullptr; - } - for (vector<FEdge *>::const_iterator j1 = vm->FEdges().begin(); j1 != vm->FEdges().end(); j1++) { - (*j1)->userdata = nullptr; - } - for (vector<SVertex *>::const_iterator j2 = vm->SVertices().begin(); j2 != vm->SVertices().end(); - j2++) { - (*j2)->userdata = nullptr; - } - for (vector<ViewEdge *>::const_iterator j3 = vm->ViewEdges().begin(); - j3 != vm->ViewEdges().end(); - j3++) { - (*j3)->userdata = nullptr; - } - for (vector<ViewVertex *>::const_iterator j4 = vm->ViewVertices().begin(); - j4 != vm->ViewVertices().end(); - j4++) { - (*j4)->userdata = nullptr; - } - SET_PROGRESS(6); - - return err; -} - -//////////////////// Options //////////////////// - -namespace Options { - -namespace Internal { - -static unsigned char g_flags = 0; -static string g_models_path; - -} // End of namespace Internal - -void setFlags(const unsigned char flags) -{ - Internal::g_flags = flags; -} - -void addFlags(const unsigned char flags) -{ - Internal::g_flags |= flags; -} - -void rmFlags(const unsigned char flags) -{ - Internal::g_flags &= ~flags; -} - -unsigned char getFlags() -{ - return Internal::g_flags; -} - -void setModelsPath(const string &path) -{ - Internal::g_models_path = path; -} - -string getModelsPath() -{ - return Internal::g_models_path; -} - -} // namespace Options - -} // namespace Freestyle::ViewMapIO diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h deleted file mode 100644 index 4796b28a38a..00000000000 --- a/source/blender/freestyle/intern/view_map/ViewMapIO.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup freestyle - * \brief Functions to manage I/O for the view map - */ - -#include <fstream> -#include <string> - -#include "ViewMap.h" - -#include "../system/FreestyleConfig.h" -#include "../system/ProgressBar.h" - -namespace Freestyle { - -namespace ViewMapIO { - -static const unsigned ZERO = UINT_MAX; - -int load(istream &in, ViewMap *vm, ProgressBar *pb = NULL); - -int save(ostream &out, ViewMap *vm, ProgressBar *pb = NULL); - -namespace Options { - -static const unsigned char FLOAT_VECTORS = 1; -static const unsigned char NO_OCCLUDERS = 2; - -void setFlags(unsigned char flags); - -void addFlags(unsigned char flags); - -void rmFlags(unsigned char flags); - -unsigned char getFlags(); - -void setModelsPath(const string &path); - -string getModelsPath(); - -}; // namespace Options - -#ifdef IRIX - -namespace Internal { - -template<unsigned S> ostream &write(ostream &out, const char *str) -{ - out.put(str[S - 1]); - return write<S - 1>(out, str); -} - -template<> ostream &write<1>(ostream &out, const char *str) -{ - return out.put(str[0]); -} - -template<> ostream &write<0>(ostream &out, const char *) -{ - return out; -} - -template<unsigned S> istream &read(istream &in, char *str) -{ - in.get(str[S - 1]); - return read<S - 1>(in, str); -} - -template<> istream &read<1>(istream &in, char *str) -{ - return in.get(str[0]); -} - -template<> istream &read<0>(istream &in, char *) -{ - return in; -} - -} // End of namespace Internal - -#endif // IRIX - -} // End of namespace ViewMapIO - -} /* namespace Freestyle */ diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 2f648d7ed4b..c96321b67aa 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -1753,6 +1753,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu obi->original_me, &((struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, })); } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 45e614991ca..190454c8dfe 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -2,10 +2,10 @@ # Copyright 2006 Blender Foundation. All rights reserved. # WITH_OPENGL limits the visibility of the opengl headers to just GPU and bg_gpu, -# to more easily highlight codepadths in other libraries that need to be refactored, +# to more easily highlight code-paths in other libraries that need to be refactored, # bf_gpu is allowed to have opengl regardless of this option. -if(NOT WITH_OPENGL) +if(NOT WITH_OPENGL AND NOT WITH_METAL_BACKEND) add_definitions(-DWITH_OPENGL) endif() @@ -13,6 +13,7 @@ set(INC . intern opengl + metal ../blenkernel ../blenlib ../bmesh @@ -78,27 +79,6 @@ set(SRC intern/gpu_vertex_format.cc intern/gpu_viewport.c - opengl/gl_backend.cc - opengl/gl_batch.cc - opengl/gl_compute.cc - opengl/gl_context.cc - opengl/gl_debug.cc - opengl/gl_debug_layer.cc - opengl/gl_drawlist.cc - opengl/gl_framebuffer.cc - opengl/gl_immediate.cc - opengl/gl_index_buffer.cc - opengl/gl_query.cc - opengl/gl_shader.cc - opengl/gl_shader_interface.cc - opengl/gl_shader_log.cc - opengl/gl_state.cc - opengl/gl_storage_buffer.cc - opengl/gl_texture.cc - opengl/gl_uniform_buffer.cc - opengl/gl_vertex_array.cc - opengl/gl_vertex_buffer.cc - GPU_batch.h GPU_batch_presets.h GPU_batch_utils.h @@ -129,6 +109,7 @@ set(SRC GPU_vertex_buffer.h GPU_vertex_format.h GPU_viewport.h + GPU_storage_buffer.h intern/gpu_backend.hh intern/gpu_batch_private.hh @@ -153,10 +134,35 @@ set(SRC intern/gpu_shader_interface.hh intern/gpu_shader_private.hh intern/gpu_state_private.hh + intern/gpu_storage_buffer_private.hh intern/gpu_texture_private.hh intern/gpu_uniform_buffer_private.hh intern/gpu_vertex_buffer_private.hh intern/gpu_vertex_format_private.h +) + +set(OPENGL_SRC + + opengl/gl_backend.cc + opengl/gl_batch.cc + opengl/gl_compute.cc + opengl/gl_context.cc + opengl/gl_debug.cc + opengl/gl_debug_layer.cc + opengl/gl_drawlist.cc + opengl/gl_framebuffer.cc + opengl/gl_immediate.cc + opengl/gl_index_buffer.cc + opengl/gl_query.cc + opengl/gl_shader.cc + opengl/gl_shader_interface.cc + opengl/gl_shader_log.cc + opengl/gl_state.cc + opengl/gl_storage_buffer.cc + opengl/gl_texture.cc + opengl/gl_uniform_buffer.cc + opengl/gl_vertex_array.cc + opengl/gl_vertex_buffer.cc opengl/gl_backend.hh opengl/gl_batch.hh @@ -172,12 +178,29 @@ set(SRC opengl/gl_shader.hh opengl/gl_shader_interface.hh opengl/gl_state.hh + opengl/gl_storage_buffer.hh opengl/gl_texture.hh opengl/gl_uniform_buffer.hh opengl/gl_vertex_array.hh opengl/gl_vertex_buffer.hh ) +set(METAL_SRC + metal/mtl_backend.mm + + metal/mtl_backend.hh + metal/mtl_capabilities.hh +) + +# Select Backend source based on availability +if(WITH_OPENGL) + list(APPEND SRC ${OPENGL_SRC}) +endif() + +if(WITH_METAL_BACKEND) + list(APPEND SRC ${METAL_SRC}) +endif() + set(LIB ${BLENDER_GL_LIBRARIES} ) @@ -190,6 +213,7 @@ endif() set(GLSL_SRC GPU_shader_shared.h + shaders/opengl/glsl_shader_defines.glsl shaders/gpu_shader_depth_only_frag.glsl shaders/gpu_shader_uniform_color_frag.glsl diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index 85433913456..f3b7f8c29bf 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -11,18 +11,15 @@ #include "GPU_batch.h" #include "GPU_common.h" +#include "GPU_platform.h" #ifdef __cplusplus extern "C" { #endif -typedef enum eGPUBackendType { - GPU_BACKEND_NONE = 0, - GPU_BACKEND_OPENGL, -} eGPUBackendType; - void GPU_backend_init(eGPUBackendType backend); void GPU_backend_exit(void); +bool GPU_backend_supported(eGPUBackendType type); eGPUBackendType GPU_backend_get_type(void); @@ -49,6 +46,14 @@ GPUContext *GPU_context_active_get(void); void GPU_context_main_lock(void); void GPU_context_main_unlock(void); +/* GPU Begin/end work blocks */ +void GPU_render_begin(void); +void GPU_render_end(void); + +/* For operations which need to run exactly once per frame -- even if there are no render updates. + */ +void GPU_render_step(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h index d5a0fcfa921..d999216c7ff 100644 --- a/source/blender/gpu/GPU_platform.h +++ b/source/blender/gpu/GPU_platform.h @@ -12,6 +12,13 @@ /* GPU platform support */ +typedef enum eGPUBackendType { + GPU_BACKEND_NONE = 0, + GPU_BACKEND_OPENGL = 1 << 0, + GPU_BACKEND_METAL = 1 << 1, + GPU_BACKEND_ANY = 0xFFFFFFFFu +} eGPUBackendType; + /* GPU Types */ typedef enum eGPUDeviceType { GPU_DEVICE_NVIDIA = (1 << 0), @@ -51,8 +58,13 @@ extern "C" { #endif /* GPU Types */ - +/* TODO: Verify all use-cases of GPU_type_matches to determine which graphics API it should apply + * to, and replace with `GPU_type_matches_ex` where appropriate. */ bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver); +bool GPU_type_matches_ex(eGPUDeviceType device, + eGPUOSType os, + eGPUDriverType driver, + eGPUBackendType backend); eGPUSupportLevel GPU_platform_support_level(void); const char *GPU_platform_vendor(void); diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index ad906c74980..6e07e6c3229 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -49,6 +49,12 @@ class GPUBackend { virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0; virtual StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) = 0; virtual VertBuf *vertbuf_alloc() = 0; + + /* Render Frame Coordination -- + * Used for performing per-frame actions globally */ + virtual void render_begin() = 0; + virtual void render_end() = 0; + virtual void render_step() = 0; }; } // namespace gpu diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index d645d82a879..4a951eb8458 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -20,11 +20,13 @@ namespace blender::gpu { */ struct GPUCapabilities { int max_texture_size = 0; + int max_texture_3d_size = 0; int max_texture_layers = 0; int max_textures = 0; int max_textures_vert = 0; int max_textures_geom = 0; int max_textures_frag = 0; + int max_samplers = 0; int max_work_group_count[3] = {0, 0, 0}; int max_work_group_size[3] = {0, 0, 0}; int max_uniforms_vert = 0; @@ -41,6 +43,8 @@ struct GPUCapabilities { bool compute_shader_support = false; bool shader_storage_buffer_objects_support = false; bool shader_image_load_store_support = false; + bool transform_feedback_support = false; + /* OpenGL related workarounds. */ bool mip_render_workaround = false; bool depth_blitting_workaround = false; @@ -48,6 +52,10 @@ struct GPUCapabilities { bool broken_amd_driver = false; bool use_hq_normals_workaround = false; /* Vulkan related workarounds. */ + + /* Metal related workarounds. */ + /* Minimum per-vertex stride in bytes (For a vertex buffer). */ + int minimum_per_vertex_stride = 1; }; extern GPUCapabilities GCaps; diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 60e95e09a99..c6eaf7defdc 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -13,7 +13,9 @@ */ /* TODO: Create cmake option. */ -#define WITH_OPENGL_BACKEND 1 +#if WITH_OPENGL +# define WITH_OPENGL_BACKEND 1 +#endif #include "BLI_assert.h" #include "BLI_utildefines.h" @@ -32,6 +34,9 @@ # include "gl_backend.hh" # include "gl_context.hh" #endif +#ifdef WITH_METAL_BACKEND +# include "mtl_backend.hh" +#endif #include <mutex> #include <vector> @@ -141,21 +146,76 @@ void GPU_context_main_unlock() /** \} */ /* -------------------------------------------------------------------- */ +/** \name GPU Begin/end work blocks + * + * Used to explicitly define a per-frame block within which GPU work will happen. + * Used for global autoreleasepool flushing in Metal + * \{ */ + +void GPU_render_begin() +{ + GPUBackend *backend = GPUBackend::get(); + BLI_assert(backend); + backend->render_begin(); +} +void GPU_render_end() +{ + GPUBackend *backend = GPUBackend::get(); + BLI_assert(backend); + backend->render_end(); +} +void GPU_render_step() +{ + GPUBackend *backend = GPUBackend::get(); + BLI_assert(backend); + backend->render_step(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Backend selection * \{ */ static GPUBackend *g_backend; +bool GPU_backend_supported(eGPUBackendType type) +{ + switch (type) { + case GPU_BACKEND_OPENGL: +#ifdef WITH_OPENGL_BACKEND + return true; +#else + return false; +#endif + case GPU_BACKEND_METAL: +#ifdef WITH_METAL_BACKEND + return MTLBackend::metal_is_supported(); +#else + return false; +#endif + default: + BLI_assert(false && "No backend specified"); + return false; + } +} + void GPU_backend_init(eGPUBackendType backend_type) { BLI_assert(g_backend == nullptr); + BLI_assert(GPU_backend_supported(backend_type)); switch (backend_type) { -#if WITH_OPENGL_BACKEND +#ifdef WITH_OPENGL_BACKEND case GPU_BACKEND_OPENGL: g_backend = new GLBackend; break; #endif +#ifdef WITH_METAL_BACKEND + case GPU_BACKEND_METAL: + g_backend = new MTLBackend; + break; +#endif default: BLI_assert(0); break; @@ -172,9 +232,18 @@ void GPU_backend_exit() eGPUBackendType GPU_backend_get_type() { + +#ifdef WITH_OPENGL_BACKEND if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) { return GPU_BACKEND_OPENGL; } +#endif + +#ifdef WITH_METAL_BACKEND + if (g_backend && dynamic_cast<MTLBackend *>(g_backend) != nullptr) { + return GPU_BACKEND_METAL; + } +#endif return GPU_BACKEND_NONE; } diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc index 969a3033c6f..d108dd468a0 100644 --- a/source/blender/gpu/intern/gpu_platform.cc +++ b/source/blender/gpu/intern/gpu_platform.cc @@ -65,6 +65,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device, eGPUOSType os_type, eGPUDriverType driver_type, eGPUSupportLevel gpu_support_level, + eGPUBackendType backend, const char *vendor_str, const char *renderer_str, const char *version_str) @@ -83,6 +84,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device, this->version = BLI_strdup(version_str); this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str); this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str); + this->backend = backend; } void GPUPlatformGlobal::clear() @@ -143,8 +145,17 @@ const char *GPU_platform_gpu_name() bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) { + return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY); +} + +bool GPU_type_matches_ex(eGPUDeviceType device, + eGPUOSType os, + eGPUDriverType driver, + eGPUBackendType backend) +{ BLI_assert(GPG.initialized); - return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver); + return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver) && + (GPG.backend & backend); } /** \} */ diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh index a6c400ad319..6e6c24a8662 100644 --- a/source/blender/gpu/intern/gpu_platform_private.hh +++ b/source/blender/gpu/intern/gpu_platform_private.hh @@ -23,12 +23,14 @@ class GPUPlatformGlobal { char *version = nullptr; char *support_key = nullptr; char *gpu_name = nullptr; + eGPUBackendType backend = GPU_BACKEND_NONE; public: void init(eGPUDeviceType gpu_device, eGPUOSType os_type, eGPUDriverType driver_type, eGPUSupportLevel gpu_support_level, + eGPUBackendType backend, const char *vendor_str, const char *renderer_str, const char *version_str); diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index ac8e98a4a21..b434cfbbb0e 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -88,6 +88,16 @@ static void standard_defines(Vector<const char *> &sources) else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) { sources.append("#define OS_UNIX\n"); } + /* API Definition */ + eGPUBackendType backend = GPU_backend_get_type(); + switch (backend) { + case GPU_BACKEND_OPENGL: + sources.append("#define GPU_OPENGL\n"); + break; + default: + BLI_assert(false && "Invalid GPU Backend Type"); + break; + } if (GPU_crappy_amd_driver()) { sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n"); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index b5a572bccbe..7bffafd7f9d 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -505,7 +505,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, bool display_colorspace, bool do_overlay_merge) { - if (viewport->color_render_tx == NULL) { + const int view = 0; + + if (viewport->color_render_tx[view] == NULL) { return; } @@ -527,7 +529,7 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, }; gpu_viewport_draw_colormanaged( - viewport, 0, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); + viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); /* This one is from the offscreen. Don't free it with the viewport. */ viewport->depth_tx = NULL; diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh new file mode 100644 index 00000000000..78f638d23f5 --- /dev/null +++ b/source/blender/gpu/metal/mtl_backend.hh @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_vector.hh" + +#include "gpu_backend.hh" +#include "mtl_capabilities.hh" + +namespace blender { +namespace gpu { + +class Batch; +class DrawList; +class FrameBuffer; +class IndexBuf; +class QueryPool; +class Shader; +class Texture; +class UniformBuf; +class VertBuf; +class MTLContext; + +class MTLBackend : public GPUBackend { + friend class MTLContext; + + public: + /* Capabilities. */ + static MTLCapabilities capabilities; + + inline ~MTLBackend() + { + MTLBackend::platform_exit(); + } + + static bool metal_is_supported(); + inline static MTLBackend *get() + { + return static_cast<MTLBackend *>(GPUBackend::get()); + } + + void samplers_update() override; + inline void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override + { + /* Placeholder */ + } + + /* MTL Allocators need to be implemented in separate .mm files, due to allocation of Objective-C + * objects. */ + Context *context_alloc(void *ghost_window) override; + Batch *batch_alloc() override; + DrawList *drawlist_alloc(int list_length) override; + FrameBuffer *framebuffer_alloc(const char *name) override; + IndexBuf *indexbuf_alloc() override; + QueryPool *querypool_alloc() override; + Shader *shader_alloc(const char *name) override; + Texture *texture_alloc(const char *name) override; + UniformBuf *uniformbuf_alloc(int size, const char *name) override; + VertBuf *vertbuf_alloc() override; + + /* Render Frame Coordination. */ + void render_begin() override; + void render_end() override; + void render_step() override; + bool is_inside_render_boundary(); + + private: + static void platform_init(MTLContext *ctx); + static void platform_exit(); + + static void capabilities_init(MTLContext *ctx); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm new file mode 100644 index 00000000000..e1da371bd0b --- /dev/null +++ b/source/blender/gpu/metal/mtl_backend.mm @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#include "BKE_global.h" + +#include "gpu_backend.hh" +#include "mtl_backend.hh" + +#include "gpu_capabilities_private.hh" +#include "gpu_platform_private.hh" + +#include <Cocoa/Cocoa.h> +#include <Metal/Metal.h> +#include <QuartzCore/QuartzCore.h> + +namespace blender { +namespace gpu { + +/* Global per-thread AutoReleasePool. */ +thread_local NSAutoreleasePool *g_autoreleasepool = nil; +thread_local int g_autoreleasepool_depth = 0; + +/* -------------------------------------------------------------------- */ +/** \name Metal Backend + * \{ */ + +void MTLBackend::samplers_update(){ + /* Placeholder -- Handled in MTLContext. */ +}; + +Context *MTLBackend::context_alloc(void *ghost_window) +{ + /* TODO(Metal): Implement MTLContext. */ + return nullptr; +}; + +Batch *MTLBackend::batch_alloc() +{ + /* TODO(Metal): Implement MTLBatch. */ + return nullptr; +}; + +DrawList *MTLBackend::drawlist_alloc(int list_length) +{ + /* TODO(Metal): Implement MTLDrawList. */ + return nullptr; +}; + +FrameBuffer *MTLBackend::framebuffer_alloc(const char *name) +{ + /* TODO(Metal): Implement MTLFrameBuffer. */ + return nullptr; +}; + +IndexBuf *MTLBackend::indexbuf_alloc() +{ + /* TODO(Metal): Implement MTLIndexBuf. */ + return nullptr; +}; + +QueryPool *MTLBackend::querypool_alloc() +{ + /* TODO(Metal): Implement MTLQueryPool. */ + return nullptr; +}; + +Shader *MTLBackend::shader_alloc(const char *name) +{ + /* TODO(Metal): Implement MTLShader. */ + return nullptr; +}; + +Texture *MTLBackend::texture_alloc(const char *name) +{ + /* TODO(Metal): Implement MTLTexture. */ + return nullptr; +} + +UniformBuf *MTLBackend::uniformbuf_alloc(int size, const char *name) +{ + /* TODO(Metal): Implement MTLUniformBuf. */ + return nullptr; +}; + +VertBuf *MTLBackend::vertbuf_alloc() +{ + /* TODO(Metal): Implement MTLVertBuf. */ + return nullptr; +} + +void MTLBackend::render_begin() +{ + /* All Rendering must occur within a render boundary */ + /* Track a call-count for nested calls, used to ensure we are inside an + * autoreleasepool from all rendering path. */ + BLI_assert(g_autoreleasepool_depth >= 0); + + if (g_autoreleasepool == nil) { + g_autoreleasepool = [[NSAutoreleasePool alloc] init]; + } + g_autoreleasepool_depth++; + BLI_assert(g_autoreleasepool_depth > 0); +} + +void MTLBackend::render_end() +{ + /* If call-count reaches zero, drain auto release pool. + * Ensures temporary objects are freed within a frame's lifetime. */ + BLI_assert(g_autoreleasepool != nil); + g_autoreleasepool_depth--; + BLI_assert(g_autoreleasepool_depth >= 0); + + if (g_autoreleasepool_depth == 0) { + [g_autoreleasepool drain]; + g_autoreleasepool = nil; + } +} + +void MTLBackend::render_step() +{ + /* Placeholder */ +} + +bool MTLBackend::is_inside_render_boundary() +{ + return (g_autoreleasepool != nil); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Platform + * \{ */ + +/* For Metal, platform_init needs to be called after MTLContext initialization. */ +void MTLBackend::platform_init(MTLContext *ctx) +{ + if (GPG.initialized) { + return; + } + + eGPUDeviceType device = GPU_DEVICE_UNKNOWN; + eGPUOSType os = GPU_OS_ANY; + eGPUDriverType driver = GPU_DRIVER_ANY; + eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED; + + BLI_assert(ctx); + id<MTLDevice> mtl_device = nil; /*ctx->device; TODO(Metal): Implement MTLContext. */ + BLI_assert(device); + + NSString *gpu_name = [mtl_device name]; + const char *vendor = [gpu_name UTF8String]; + const char *renderer = "Metal API"; + const char *version = "1.2"; + printf("METAL API - DETECTED GPU: %s\n", vendor); + + /* macOS is the only supported platform, but check to ensure we are not building with Metal + * enablement on another platform. */ +#ifdef _WIN32 + os = GPU_OS_WIN; +#elif defined(__APPLE__) + os = GPU_OS_MAC; +#else + os = GPU_OS_UNIX; +#endif + + BLI_assert(os == GPU_OS_MAC && "Platform must be macOS"); + + /* Determine Vendor from name. */ + if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) { + device = GPU_DEVICE_ATI; + driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "NVIDIA")) { + device = GPU_DEVICE_NVIDIA; + driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "Intel")) { + device = GPU_DEVICE_INTEL; + driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(vendor, "Apple") || strstr(vendor, "APPLE")) { + /* Apple Silicon. */ + device = GPU_DEVICE_APPLE; + driver = GPU_DRIVER_OFFICIAL; + } + else if (strstr(renderer, "Apple Software Renderer")) { + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; + } + else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) { + device = GPU_DEVICE_SOFTWARE; + driver = GPU_DRIVER_SOFTWARE; + } + else { + printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n"); + printf("Detected configuration:\n"); + printf("Vendor: %s\n", vendor); + printf("Renderer: %s\n", renderer); + } + + GPG.init(device, os, driver, support_level, GPU_BACKEND_METAL, vendor, renderer, version); +} + +void MTLBackend::platform_exit() +{ + BLI_assert(GPG.initialized); + GPG.clear(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Capabilities + * \{ */ +MTLCapabilities MTLBackend::capabilities = {}; + +static const char *mtl_extensions_get_null(int i) +{ + return nullptr; +} + +bool supports_barycentric_whitelist(id<MTLDevice> device) +{ + NSString *gpu_name = [device name]; + BLI_assert([gpu_name length]); + const char *vendor = [gpu_name UTF8String]; + + /* Verify GPU support. */ + bool supported_gpu = [device supportsFamily:MTLGPUFamilyMac2]; + bool should_support_barycentrics = false; + + /* Known good configs. */ + if (strstr(vendor, "AMD") || strstr(vendor, "Apple") || strstr(vendor, "APPLE")) { + should_support_barycentrics = true; + } + + /* Explicit support for Intel-based platforms. */ + if ((strstr(vendor, "Intel") || strstr(vendor, "INTEL"))) { + should_support_barycentrics = true; + } + return supported_gpu && should_support_barycentrics; +} + +bool MTLBackend::metal_is_supported() +{ + /* Device compatibility information using Metal Feature-set tables. + * See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */ + + NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; + + /* Metal Viewport requires macOS Version 10.15 onwards. */ + bool supported_os_version = version.majorVersion >= 11 || + (version.majorVersion == 10 ? version.minorVersion >= 15 : false); + if (!supported_os_version) { + printf( + "OS Version too low to run minimum required metal version. Required at least 10.15, got " + "%ld.%ld \n", + (long)version.majorVersion, + (long)version.minorVersion); + return false; + } + + if (@available(macOS 10.15, *)) { + id<MTLDevice> device = MTLCreateSystemDefaultDevice(); + + /* Debug: Enable low power GPU with Environment Var: METAL_FORCE_INTEL. */ + static const char *forceIntelStr = getenv("METAL_FORCE_INTEL"); + bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false; + + if (forceIntel) { + NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices(); + for (id<MTLDevice> _device in allDevices) { + if (_device.lowPower) { + device = _device; + } + } + } + + /* Metal Viewport requires argument buffer tier-2 support and Barycentric Coordinates. + * These are available on most hardware configurations supporting Metal 2.2. */ + bool supports_argument_buffers_tier2 = ([device argumentBuffersSupport] == + MTLArgumentBuffersTier2); + bool supports_barycentrics = [device supportsShaderBarycentricCoordinates] || + supports_barycentric_whitelist(device); + bool supported_metal_version = [device supportsFamily:MTLGPUFamilyMac2]; + + bool result = supports_argument_buffers_tier2 && supports_barycentrics && + supported_os_version && supported_metal_version; + + if (!supports_argument_buffers_tier2) { + printf("[Metal] Device does not support argument buffers tier 2\n"); + } + if (!supports_barycentrics) { + printf("[Metal] Device does not support barycentrics coordinates\n"); + } + if (!supported_metal_version) { + printf("[Metal] Device does not support metal 2.2 or higher\n"); + } + + if (result) { + printf("Device with name %s supports metal minimum requirements\n", + [[device name] UTF8String]); + } + + return result; + } + return false; +} + +void MTLBackend::capabilities_init(MTLContext *ctx) +{ + BLI_assert(ctx); + id<MTLDevice> device = nil; /*ctx->device TODO(Metal): Implement MTLContext. */ + BLI_assert(device); + + /* Initialize Capabilities. */ + MTLBackend::capabilities.supports_argument_buffers_tier2 = ([device argumentBuffersSupport] == + MTLArgumentBuffersTier2); + MTLBackend::capabilities.supports_family_mac1 = [device supportsFamily:MTLGPUFamilyMac1]; + MTLBackend::capabilities.supports_family_mac2 = [device supportsFamily:MTLGPUFamilyMac2]; + MTLBackend::capabilities.supports_family_mac_catalyst1 = [device + supportsFamily:MTLGPUFamilyMacCatalyst1]; + MTLBackend::capabilities.supports_family_mac_catalyst2 = [device + supportsFamily:MTLGPUFamilyMacCatalyst2]; + + /* Common Global Capabilities. */ + GCaps.max_texture_size = ([device supportsFamily:MTLGPUFamilyApple3] || + MTLBackend::capabilities.supports_family_mac1) ? + 16384 : + 8192; + GCaps.max_texture_3d_size = 2048; + GCaps.max_texture_layers = 2048; + GCaps.max_textures = (MTLBackend::capabilities.supports_family_mac1) ? + 128 : + (([device supportsFamily:MTLGPUFamilyApple4]) ? 96 : 31); + if (GCaps.max_textures <= 32) { + BLI_assert(false); + } + GCaps.max_samplers = (MTLBackend::capabilities.supports_argument_buffers_tier2) ? 1024 : 16; + + GCaps.max_textures_vert = GCaps.max_textures; + GCaps.max_textures_geom = 0; /* N/A geometry shaders not supported. */ + GCaps.max_textures_frag = GCaps.max_textures; + + /* Conservative uniform data limit is 4KB per-stage -- This is the limit of setBytes. + * MTLBuffer path is also supported but not as efficient. */ + GCaps.max_uniforms_vert = 1024; + GCaps.max_uniforms_frag = 1024; + + GCaps.max_batch_indices = 1 << 31; + GCaps.max_batch_vertices = 1 << 31; + GCaps.max_vertex_attribs = 31; + GCaps.max_varying_floats = 60; + + /* Feature support */ + GCaps.mem_stats_support = false; + GCaps.shader_image_load_store_support = ([device supportsFamily:MTLGPUFamilyApple3] || + MTLBackend::capabilities.supports_family_mac1 || + MTLBackend::capabilities.supports_family_mac2); + GCaps.compute_shader_support = false; /* TODO(Metal): Add compute support. */ + GCaps.shader_storage_buffer_objects_support = + false; /* TODO(Metal): implement Storage Buffer support.*/ + + /* Maximum buffer bindings: 31. Consider required slot for uniforms/UBOs/Vertex attributes. + * Can use argument buffers if a higher limit is required. */ + GCaps.max_shader_storage_buffer_bindings = 24; + + if (GCaps.compute_shader_support) { + GCaps.max_work_group_count[0] = 65535; + GCaps.max_work_group_count[1] = 65535; + GCaps.max_work_group_count[2] = 65535; + + /* In Metal, total_thread_count is 512 or 1024, such that + * threadgroup `width*height*depth <= total_thread_count` */ + unsigned int max_threads_per_threadgroup_per_dim = + ([device supportsFamily:MTLGPUFamilyApple4] || + MTLBackend::capabilities.supports_family_mac1) ? + 1024 : + 512; + GCaps.max_work_group_size[0] = max_threads_per_threadgroup_per_dim; + GCaps.max_work_group_size[1] = max_threads_per_threadgroup_per_dim; + GCaps.max_work_group_size[2] = max_threads_per_threadgroup_per_dim; + } + + GCaps.transform_feedback_support = true; + + /* OPENGL Related workarounds -- none needed for Metal. */ + GCaps.extensions_len = 0; + GCaps.extension_get = mtl_extensions_get_null; + GCaps.mip_render_workaround = false; + GCaps.depth_blitting_workaround = false; + GCaps.use_main_context_workaround = false; + GCaps.broken_amd_driver = false; + + /* Metal related workarounds. */ + /* Minimum per-vertex stride is 4 bytes in Metal. + * A bound vertex buffer must contribute at least 4 bytes per vertex. */ + GCaps.minimum_per_vertex_stride = 4; +} + +/** \} */ + +} // gpu +} // blender diff --git a/source/blender/gpu/metal/mtl_capabilities.hh b/source/blender/gpu/metal/mtl_capabilities.hh new file mode 100644 index 00000000000..5563008e87d --- /dev/null +++ b/source/blender/gpu/metal/mtl_capabilities.hh @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +namespace blender { +namespace gpu { + +/*** Derived from: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf ***/ +/** Upper Bound/Fixed Limits **/ + +#define METAL_MAX_TEXTURE_SLOTS 128 +#define METAL_MAX_SAMPLER_SLOTS METAL_MAX_TEXTURE_SLOTS +#define METAL_MAX_UNIFORM_BUFFER_BINDINGS 31 +#define METAL_MAX_VERTEX_INPUT_ATTRIBUTES 31 +#define METAL_MAX_UNIFORMS_PER_BLOCK 64 + +/* Context-specific limits -- populated in 'MTLBackend::platform_init' */ +typedef struct MTLCapabilities { + + /* Variable Limits & feature sets. */ + int max_color_render_targets = 4; /* Minimum = 4 */ + int buffer_alignment_for_textures = 256; /* Upper bound = 256 bytes */ + int minimum_buffer_offset_alignment = 256; /* Upper bound = 256 bytes */ + + /* Capabilities */ + bool supports_vertex_amplification = false; + bool supports_texture_swizzle = true; + bool supports_cubemaps = true; + bool supports_layered_rendering = true; + bool supports_memory_barriers = false; + bool supports_sampler_border_color = false; + bool supports_argument_buffers_tier2 = false; + + /* GPU Family */ + bool supports_family_mac1 = false; + bool supports_family_mac2 = false; + bool supports_family_mac_catalyst1 = false; + bool supports_family_mac_catalyst2 = false; + +} MTLCapabilities; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 883f9403920..2c9cbdb99d8 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -140,7 +140,7 @@ void GLBackend::platform_init() } } - GPG.init(device, os, driver, support_level, vendor, renderer, version); + GPG.init(device, os, driver, support_level, GPU_BACKEND_OPENGL, vendor, renderer, version); } void GLBackend::platform_exit() @@ -418,6 +418,12 @@ static void detect_workarounds() (strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) { GCaps.shader_storage_buffer_objects_support = false; } + + /* Metal-related Workarounds. */ + + /* Minimum Per-Vertex stride is 1 byte for OpenGL. */ + GCaps.minimum_per_vertex_stride = 1; + } // namespace blender::gpu /** Internal capabilities. */ diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index e72726d9c7b..29249111294 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -136,6 +136,11 @@ class GLBackend : public GPUBackend { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); } + /* Render Frame Coordination */ + void render_begin(void) override{}; + void render_end(void) override{}; + void render_step(void) override{}; + private: static void platform_init(); static void platform_exit(); diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index c0182306047..5a55a2e8020 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -24,6 +24,8 @@ using namespace blender; using namespace blender::gpu; using namespace blender::gpu::shader; +extern "C" char datatoc_glsl_shader_defines_glsl[]; + /* -------------------------------------------------------------------- */ /** \name Creation / Destruction * \{ */ @@ -760,7 +762,7 @@ bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info static char *glsl_patch_default_get() { /** Used for shader patching. Init once. */ - static char patch[1024] = "\0"; + static char patch[2048] = "\0"; if (patch[0] != '\0') { return patch; } @@ -827,6 +829,9 @@ static char *glsl_patch_default_get() STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]); STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]); + /* GLSL Backend Lib. */ + STR_CONCAT(patch, slen, datatoc_glsl_shader_defines_glsl); + BLI_assert(slen < sizeof(patch)); return patch; } diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index a461d834790..109bb65fcb7 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -27,7 +27,7 @@ GLStorageBuf::GLStorageBuf(size_t size, GPUUsageType usage, const char *name) : StorageBuf(size, name) { usage_ = usage; - /* Do not create ubo GL buffer here to allow allocation from any thread. */ + /* Do not create UBO GL buffer here to allow allocation from any thread. */ BLI_assert(size <= GLContext::max_ssbo_size); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl index 9851e08fe2e..353bf1481da 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl @@ -23,15 +23,15 @@ void main() /* Use pos to select the right swizzle (instead of gl_VertexID) * in order to workaround an OSX driver bug. */ - if (pos == vec2(0.0, 0.0)) { + if (all(equal(pos, vec2(0.0, 0.0)))) { rect.xy = rect.xz; tex.xy = tex.xz; } - else if (pos == vec2(0.0, 1.0)) { + else if (all(equal(pos, vec2(0.0, 1.0)))) { rect.xy = rect.xw; tex.xy = tex.xw; } - else if (pos == vec2(1.0, 1.0)) { + else if (all(equal(pos, vec2(1.0, 1.0)))) { rect.xy = rect.yw; tex.xy = tex.yw; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl index d9a5aeeef46..903c602c5d6 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl @@ -15,6 +15,32 @@ void main() { vec2 uv; vec2 co; + +#ifdef GPU_METAL +/* Metal API does not support Triangle fan primitive topology. + * When this shader is called using Triangle-Strip, vertex ID's + * are in a different order. */ +# define GPU_PRIM_TRI_STRIP +#endif + +#ifdef GPU_PRIM_TRI_STRIP + if (gl_VertexID == 0) { + co = rect_geom.xw; + uv = rect_icon.xw; + } + else if (gl_VertexID == 1) { + co = rect_geom.xy; + uv = rect_icon.xy; + } + else if (gl_VertexID == 2) { + co = rect_geom.zw; + uv = rect_icon.zw; + } + else { + co = rect_geom.zy; + uv = rect_icon.zy; + } +#else if (gl_VertexID == 0) { co = rect_geom.xy; uv = rect_icon.xy; @@ -31,6 +57,7 @@ void main() co = rect_geom.zy; uv = rect_icon.zy; } +#endif gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f); texCoord_interp = uv; diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index 80b93baf20a..3a39cd8b847 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -53,7 +53,7 @@ flat out float lineWidth; noperspective out float butCo; flat out float discardFac; -# ifdef OS_MAC +# if defined(OS_MAC) && defined(GPU_OPENGL) in float dummy; # endif #endif diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl index 2314dbbc5d5..d77f073b7de 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -32,8 +32,8 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) void main() { - fragColor = texture(image_texture, texCoord_interp.st); - vec4 overlay_col = texture(overlays_texture, texCoord_interp.st); + fragColor = texture(image_texture, texCoord_interp.xy); + vec4 overlay_col = texture(overlays_texture, texCoord_interp.xy); if (overlay) { fragColor = clamp(fragColor, 0.0, 1.0); diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl index 4ef3ff1a8d0..617c02ac079 100644 --- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl @@ -43,7 +43,7 @@ bool test(int bit) vec2 line_thresholds(float width) { - return vec2(max(0, width - line_falloff), width); + return vec2(max(0.0, width - line_falloff), width); } void main() diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl index c339d3cbabb..f958a81b1eb 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -52,7 +52,7 @@ bool is_inside_box(ivec2 v) float texture_1D_custom_bilinear_filter(vec2 uv) { - vec2 texel_2d = uv * glyph_dim + 0.5; + vec2 texel_2d = uv * vec2(glyph_dim) + vec2(0.5); ivec2 texel_2d_near = ivec2(texel_2d) - 1; int frag_offset = glyph_offset + texel_2d_near.y * glyph_dim.x + texel_2d_near.x; @@ -100,7 +100,7 @@ void main() fragColor.a = texture_1D_custom_bilinear_filter(texCoord_interp); } else { - vec2 texel = 1.0 / glyph_dim; + vec2 texel = 1.0 / vec2(glyph_dim); fragColor.a = 0.0; if (interp_size == 1) { diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl index 5b01fea5266..63d73733c2f 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -28,8 +28,9 @@ void main() vec2 interp_offset = float(interp_size) / abs(pos.zw - pos.xy); texCoord_interp = mix(-interp_offset, 1.0 + interp_offset, quad); - vec2 final_pos = mix( - pos.xy + ivec2(-interp_size, interp_size), pos.zw + ivec2(interp_size, -interp_size), quad); + vec2 final_pos = mix(vec2(ivec2(pos.xy) + ivec2(-interp_size, interp_size)), + vec2(ivec2(pos.zw) + ivec2(interp_size, -interp_size)), + quad); gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 0.0, 1.0); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl index f3eae653f95..92762db5ff4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl @@ -1,7 +1,10 @@ -void node_light_falloff( - float strength, float tsmooth, out float quadratic, out float linear, out float constant) +void node_light_falloff(float strength, + float tsmooth, + out float quadratic, + out float linear, + out float falloff_constant) { quadratic = strength; linear = strength; - constant = strength; + falloff_constant = strength; } diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl new file mode 100644 index 00000000000..a5fce2e71c3 --- /dev/null +++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl @@ -0,0 +1,17 @@ +/* Backend Functions. */ +#define select(A, B, mask) mix(A, B, mask) + +bool is_zero(vec2 A) +{ + return all(equal(A, vec2(0.0))); +} + +bool is_zero(vec3 A) +{ + return all(equal(A, vec3(0.0))); +} + +bool is_zero(vec4 A) +{ + return all(equal(A, vec4(0.0))); +} diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 7434db732fd..7cf2c02e657 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -19,6 +19,7 @@ extern "C" { struct ColorManagedColorspaceSettings; struct ColorManagedDisplaySettings; struct ColorManagedViewSettings; +struct ColorManagedOutputSettings; struct ColormanageProcessor; struct EnumPropertyItem; struct ImBuf; @@ -52,6 +53,7 @@ bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace); bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace); bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace); bool IMB_colormanagement_space_name_is_data(const char *name); +bool IMB_colormanagement_space_name_is_scene_linear(const char *name); /** * Convert a float RGB triplet to the correct luminance weighted average. @@ -238,23 +240,10 @@ void IMB_colormanagement_imbuf_make_display_space( * in image format write callback and if float_colorspace is not NULL, no color * space transformation should be applied on this buffer. */ -struct ImBuf *IMB_colormanagement_imbuf_for_write( - struct ImBuf *ibuf, - bool save_as_render, - bool allocate_result, - const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings, - const struct ImageFormatData *image_format_data); - -void IMB_colormanagement_buffer_make_display_space( - float *buffer, - unsigned char *display_buffer, - int width, - int height, - int channels, - float dither, - const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings); +struct ImBuf *IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf, + bool save_as_render, + bool allocate_result, + const struct ImageFormatData *image_format); /** \} */ diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index 42941ace40b..c89b15480a2 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -33,6 +33,9 @@ typedef struct ColorSpace { struct OCIO_ConstCPUProcessorRcPtr *to_scene_linear; struct OCIO_ConstCPUProcessorRcPtr *from_scene_linear; + char (*aliases)[MAX_COLORSPACE_NAME]; + int num_aliases; + bool is_invertible; bool is_data; diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index e60df0ca1c9..2e8c5cc4a40 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -504,7 +504,18 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace); is_data = OCIO_colorSpaceIsData(ocio_colorspace); - colormanage_colorspace_add(name, description, is_invertible, is_data); + ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data); + + colorspace->num_aliases = OCIO_colorSpaceGetNumAliases(ocio_colorspace); + if (colorspace->num_aliases > 0) { + colorspace->aliases = MEM_callocN(sizeof(*colorspace->aliases) * colorspace->num_aliases, + "ColorSpace aliases"); + for (int i = 0; i < colorspace->num_aliases; i++) { + BLI_strncpy(colorspace->aliases[i], + OCIO_colorSpaceGetAlias(ocio_colorspace, i), + MAX_COLORSPACE_NAME); + } + } OCIO_colorSpaceRelease(ocio_colorspace); } @@ -587,6 +598,7 @@ static void colormanage_free_config(void) } /* free color space itself */ + MEM_SAFE_FREE(colorspace->aliases); MEM_freeN(colorspace); colorspace = colorspace_next; @@ -1394,6 +1406,12 @@ bool IMB_colormanagement_space_name_is_data(const char *name) return (colorspace && colorspace->is_data); } +bool IMB_colormanagement_space_name_is_scene_linear(const char *name) +{ + ColorSpace *colorspace = colormanage_colorspace_get_named(name); + return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace)); +} + const float *IMB_colormanagement_get_xyz_to_rgb() { return &imbuf_xyz_to_rgb[0][0]; @@ -2431,15 +2449,12 @@ void IMB_colormanagement_imbuf_make_display_space( ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, - const ImageFormatData *image_format_data) + const ImageFormatData *imf) { ImBuf *colormanaged_ibuf = ibuf; - bool do_colormanagement; - bool is_movie = BKE_imtype_is_movie(image_format_data->imtype); - bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype); - bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA; + const bool is_movie = BKE_imtype_is_movie(imf->imtype); + const bool requires_linear_float = BKE_imtype_requires_linear_float(imf->imtype); + const bool do_alpha_under = imf->planes != R_IMF_PLANES_RGBA; if (ibuf->rect_float && ibuf->rect && (ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) { @@ -2447,9 +2462,13 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID); } - do_colormanagement = save_as_render && (is_movie || !requires_linear_float); + const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float); + const bool do_colormanagement_linear = save_as_render && requires_linear_float && + imf->linear_colorspace_settings.name[0] && + !IMB_colormanagement_space_name_is_scene_linear( + imf->linear_colorspace_settings.name); - if (do_colormanagement || do_alpha_under) { + if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) { if (allocate_result) { colormanaged_ibuf = IMB_dupImBuf(ibuf); } @@ -2502,15 +2521,15 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, } } - if (do_colormanagement) { + if (do_colormanagement_display) { + /* Color management with display and view transform. */ bool make_byte = false; /* for proper check whether byte buffer is required by a format or not * should be pretty safe since this image buffer is supposed to be used for * saving only and ftype would be overwritten a bit later by BKE_imbuf_write */ - colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format_data->imtype, - &colormanaged_ibuf->foptions); + colormanaged_ibuf->ftype = BKE_imtype_to_ftype(imf->imtype, &colormanaged_ibuf->foptions); /* if file format isn't able to handle float buffer itself, * we need to allocate byte buffer and store color managed @@ -2525,15 +2544,36 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, /* perform color space conversions */ colormanagement_imbuf_make_display_space( - colormanaged_ibuf, view_settings, display_settings, make_byte); + colormanaged_ibuf, &imf->view_settings, &imf->display_settings, make_byte); if (colormanaged_ibuf->rect_float) { /* float buffer isn't linear anymore, * image format write callback should check for this flag and assume * no space conversion should happen if ibuf->float_colorspace != NULL */ - colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings, - display_settings); + colormanaged_ibuf->float_colorspace = display_transform_get_colorspace( + &imf->view_settings, &imf->display_settings); + } + } + else if (do_colormanagement_linear) { + /* Color management transform to another linear color space. */ + if (!colormanaged_ibuf->rect_float) { + IMB_float_from_rect(colormanaged_ibuf); + imb_freerectImBuf(colormanaged_ibuf); + } + + if (colormanaged_ibuf->rect_float) { + const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name : + global_role_scene_linear; + const char *to_colorspace = imf->linear_colorspace_settings.name; + + IMB_colormanagement_transform(colormanaged_ibuf->rect_float, + colormanaged_ibuf->x, + colormanaged_ibuf->y, + colormanaged_ibuf->channels, + from_colorspace, + to_colorspace, + false); } } @@ -2544,45 +2584,6 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, return colormanaged_ibuf; } -void IMB_colormanagement_buffer_make_display_space( - float *buffer, - unsigned char *display_buffer, - int width, - int height, - int channels, - float dither, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings) -{ - ColormanageProcessor *cm_processor; - size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float); - float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space"); - - /* TODO(sergey): Convert float directly to byte buffer. */ - - memcpy(display_buffer_float, buffer, float_buffer_size); - - cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); - - processor_transform_apply_threaded( - NULL, display_buffer_float, width, height, channels, cm_processor, true, false); - - IMB_buffer_byte_from_float(display_buffer, - display_buffer_float, - channels, - dither, - IB_PROFILE_SRGB, - IB_PROFILE_SRGB, - true, - width, - height, - width, - width); - - MEM_freeN(display_buffer_float); - IMB_colormanagement_processor_free(cm_processor); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -3064,6 +3065,12 @@ ColorSpace *colormanage_colorspace_get_named(const char *name) if (STREQ(colorspace->name, name)) { return colorspace; } + + for (int i = 0; i < colorspace->num_aliases; i++) { + if (STREQ(colorspace->aliases[i], name)) { + return colorspace; + } + } } return NULL; diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index a9ade9b02fa..d0c10bd7f76 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -111,7 +111,7 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader, bool ABC_mesh_topology_changed(struct CacheReader *reader, struct Object *ob, - struct Mesh *existing_mesh, + const struct Mesh *existing_mesh, float time, const char **err_str); diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 11693eeb4de..bbb196dc383 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -158,6 +158,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) BMeshCreateParams bmesh_create_params{}; BMeshFromMeshParams bmesh_from_mesh_params{}; bmesh_from_mesh_params.calc_face_normal = true; + bmesh_from_mesh_params.calc_vert_normal = true; BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 1d00b55ca78..47f4dd2ea5d 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -658,7 +658,7 @@ bool AbcMeshReader::accepts_object_type( return true; } -bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel) +bool AbcMeshReader::topology_changed(const Mesh *existing_mesh, const ISampleSelector &sample_sel) { IPolyMeshSchema::Sample sample; try { diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h index 9f871d260a7..f97525297b7 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.h +++ b/source/blender/io/alembic/intern/abc_reader_mesh.h @@ -30,7 +30,7 @@ class AbcMeshReader final : public AbcObjectReader { const char *velocity_name, float velocity_scale, const char **err_str) override; - bool topology_changed(Mesh *existing_mesh, + bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel) override; private: diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index 72aec8f4336..dac0890e7c5 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -140,7 +140,7 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh, return existing_mesh; } -bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/, +bool AbcObjectReader::topology_changed(const Mesh * /*existing_mesh*/, const Alembic::Abc::ISampleSelector & /*sample_sel*/) { /* The default implementation of read_mesh() just returns the original mesh, so never changes the diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h index d33eabfbee5..5898d1bd529 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.h +++ b/source/blender/io/alembic/intern/abc_reader_object.h @@ -139,7 +139,7 @@ class AbcObjectReader { const char *velocity_name, float velocity_scale, const char **err_str); - virtual bool topology_changed(Mesh *existing_mesh, + virtual bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel); /** Reads the object matrix and sets up an object transform if animated. */ diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index 769285c247f..c9c982aad6c 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -801,8 +801,11 @@ Mesh *ABC_read_mesh(CacheReader *reader, existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str); } -bool ABC_mesh_topology_changed( - CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str) +bool ABC_mesh_topology_changed(CacheReader *reader, + Object *ob, + const Mesh *existing_mesh, + const float time, + const char **err_str) { AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str); if (abc_reader == nullptr) { diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp index 2c9f16c7624..3b21d423df5 100644 --- a/source/blender/io/collada/GeometryExporter.cpp +++ b/source/blender/io/collada/GeometryExporter.cpp @@ -120,7 +120,7 @@ void GeometryExporter::operator()(Object *ob) /* skip the basis */ kb = kb->next; for (; kb; kb = kb->next) { - BKE_keyblock_convert_to_mesh(kb, me); + BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert); export_key_mesh(ob, me, kb); } } diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 79ac5be35f8..8d7ada4a600 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -411,6 +411,7 @@ void bc_triangulate_mesh(Mesh *me) BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params); BMeshFromMeshParams bm_from_me_params{}; bm_from_me_params.calc_face_normal = true; + bm_from_me_params.calc_vert_normal = true; BM_mesh_bm_from_me(bm, me, &bm_from_me_params); BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr); diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h index 6dcad2ffac8..b73279250f2 100644 --- a/source/blender/io/usd/intern/usd_reader_geom.h +++ b/source/blender/io/usd/intern/usd_reader_geom.h @@ -24,7 +24,7 @@ class USDGeomReader : public USDXformReader { int read_flag, const char **err_str) = 0; - virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */) + virtual bool topology_changed(const Mesh * /* existing_mesh */, double /* motionSampleTime */) { return true; } diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 1f97c7b48b3..646d1ba1fde 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -232,7 +232,7 @@ bool USDMeshReader::valid() const return static_cast<bool>(mesh_prim_); } -bool USDMeshReader::topology_changed(Mesh *existing_mesh, const double motionSampleTime) +bool USDMeshReader::topology_changed(const Mesh *existing_mesh, const double motionSampleTime) { /* TODO(makowalski): Is it the best strategy to cache the mesh * geometry in this function? This needs to be revisited. */ diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index fdd814f56d4..5e33ce8b5e8 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -53,7 +53,7 @@ class USDMeshReader : public USDGeomReader { int read_flag, const char **err_str) override; - bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override; + bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override; private: void process_normals_vertex_varying(Mesh *mesh); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index a7508f01b0f..fb9074999f9 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -89,8 +89,13 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval() if (export_mesh_eval_->totpoly <= 0) { return {export_mesh_eval_, false}; } - const struct BMeshCreateParams bm_create_params = {0u}; - const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0}; + const BMeshCreateParams bm_create_params = {0u}; + BMeshFromMeshParams bm_convert_params{}; + bm_convert_params.calc_face_normal = true; + bm_convert_params.calc_vert_normal = true; + bm_convert_params.add_key_index = false; + bm_convert_params.use_shapekey = false; + /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be * triangulated here. */ const int triangulate_min_verts = 4; @@ -207,7 +212,10 @@ void OBJMesh::calc_poly_order() blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) { int mat_a = mpolys[a].mat_nr; int mat_b = mpolys[b].mat_nr; - return mat_a < mat_b; + if (mat_a != mat_b) { + return mat_a < mat_b; + } + return a < b; }); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index be8f9f938a3..24c120ae860 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -429,6 +429,8 @@ typedef struct ImageFormatData { Stereo3dFormat stereo3d_format; /* color management */ + char color_management; + char _pad1[7]; ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; ColorManagedColorspaceSettings linear_colorspace_settings; @@ -527,6 +529,10 @@ enum { R_IMF_TIFF_CODEC_NONE = 3, }; +/** #ImageFormatData.color_management */ +#define R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE 0 +#define R_IMF_COLOR_MANAGEMENT_OVERRIDE 1 + typedef struct BakeData { struct ImageFormatData im_format; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index d4c38060e1b..3ebcae5f947 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -179,7 +179,7 @@ typedef enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */ + * FREE FLAGS: 2, 9, 11, 13, 14, 15. */ typedef enum PropertyFlag { /** * Editable means the property is editable in the user diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 373aec975c2..840674c7bc6 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -605,6 +605,11 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, { ID *id = ptr->owner_id; + if (!id) { + /* Happens for color space settings on operators. */ + return; + } + if (GS(id->name) == ID_IM) { Image *ima = (Image *)id; diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index f31e72ce652..b7be5293578 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -43,22 +43,19 @@ static void rna_Nurb_valid_message(Nurb *nu, int direction, int *result_len, con int pnts; short order, flag; - const char *dir; if (direction == 0) { pnts = nu->pntsu; order = nu->orderu; flag = nu->flagu; - dir = "U"; } else { pnts = nu->pntsv; order = nu->orderv; flag = nu->flagv; - dir = "V"; } char buf[64]; - if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, dir, buf, sizeof(buf))) { + if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, direction, buf, sizeof(buf))) { const int buf_len = strlen(buf); *r_result = BLI_strdupn(buf, buf_len); *result_len = buf_len; diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index ce0598d355d..dab3cd68d4c 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -2446,8 +2446,10 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "cfl_condition"); RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text( - prop, "CFL", "Maximal velocity per cell (higher value results in greater timesteps)"); + RNA_def_property_ui_text(prop, + "CFL", + "Maximal velocity per cell (greater CFL numbers will minimize the " + "number of simulation steps and the computation time.)"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset"); prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 92e3254765c..55d365f9827 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -25,7 +25,9 @@ #ifdef RNA_RUNTIME # include "BKE_image.h" +# include "BKE_image_format.h" # include "BKE_main.h" +# include "BKE_scene.h" # include <errno.h> # include "IMB_colormanagement.h" @@ -68,19 +70,23 @@ static void rna_Image_save_render( else { ImBuf *write_ibuf; - write_ibuf = IMB_colormanagement_imbuf_for_write( - ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format); + ImageFormatData image_format; + BKE_image_format_init_for_write(&image_format, scene, NULL); - write_ibuf->planes = scene->r.im_format.planes; + write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &image_format); + + write_ibuf->planes = image_format.planes; write_ibuf->dither = scene->r.dither_intensity; - if (!BKE_imbuf_write(write_ibuf, path, &scene->r.im_format)) { + if (!BKE_imbuf_write(write_ibuf, path, &image_format)) { BKE_reportf(reports, RPT_ERROR, "Could not write image: %s, '%s'", strerror(errno), path); } if (write_ibuf != ibuf) { IMB_freeImBuf(write_ibuf); } + + BKE_image_format_free(&image_format); } BKE_image_release_ibuf(image, ibuf, lock); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 807fc27268d..eec1ce60089 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -393,7 +393,15 @@ char *rna_TextureSlot_path(struct PointerRNA *ptr); char *rna_Node_ImageUser_path(struct PointerRNA *ptr); /* Set U.is_dirty and redraw. */ + +/** + * Use single function so we can more easily break-point it. + */ void rna_userdef_is_dirty_update_impl(void); +/** + * Use as a fallback update handler to ensure #U.runtime.is_dirty is set. + * So the preferences are saved when modified. + */ void rna_userdef_is_dirty_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); /* API functions */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 6d04d141f8e..9400e34d193 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -20,6 +20,7 @@ #include "DNA_view3d_types.h" #include "DNA_world_types.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "BLI_listbase.h" @@ -29,6 +30,7 @@ #include "BKE_armature.h" #include "BKE_editmesh.h" +#include "BKE_idtype.h" #include "BKE_paint.h" #include "BKE_volume.h" @@ -1440,6 +1442,35 @@ static const EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(bContext } # endif + +static bool rna_ImageFormatSettings_has_linear_colorspace_get(PointerRNA *ptr) +{ + ImageFormatData *imf = (ImageFormatData *)ptr->data; + return BKE_imtype_requires_linear_float(imf->imtype); +} + +static void rna_ImageFormatSettings_color_management_set(PointerRNA *ptr, int value) +{ + ImageFormatData *imf = (ImageFormatData *)ptr->data; + + if (imf->color_management != value) { + imf->color_management = value; + + /* Copy from scene when enabling override. */ + if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + ID *owner_id = ptr->owner_id; + if (owner_id && GS(owner_id->name) == ID_NT) { + /* For compositing nodes, find the corresponding scene. */ + const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(owner_id); + owner_id = type_info->owner_get(G_MAIN, owner_id); + } + if (owner_id && GS(owner_id->name) == ID_SCE) { + BKE_image_format_color_management_copy_from_scene(imf, (Scene *)owner_id); + } + } + } +} + static int rna_SceneRender_file_ext_length(PointerRNA *ptr) { RenderData *rd = (RenderData *)ptr->data; @@ -5458,6 +5489,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) }; # endif + static const EnumPropertyItem color_management_items[] = { + {R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE, "FOLLOW_SCENE", 0, "Follow Scene", ""}, + {R_IMF_COLOR_MANAGEMENT_OVERRIDE, "OVERRIDE", 0, "Override", ""}, + {0, NULL, 0, NULL, NULL}, + }; + StructRNA *srna; PropertyRNA *prop; @@ -5616,17 +5653,32 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3D"); /* color management */ + prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, color_management_items); + RNA_def_property_ui_text( + prop, "Color Management", "Which color management settings to use for file saving"); + RNA_def_property_enum_funcs(prop, NULL, "rna_ImageFormatSettings_color_management_set", NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "view_settings"); RNA_def_property_struct_type(prop, "ColorManagedViewSettings"); RNA_def_property_ui_text( prop, "View Settings", "Color management settings applied on image before saving"); prop = RNA_def_property(srna, "display_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "display_settings"); RNA_def_property_struct_type(prop, "ColorManagedDisplaySettings"); RNA_def_property_ui_text( prop, "Display Settings", "Settings of device saved image would be displayed on"); + + prop = RNA_def_property(srna, "linear_colorspace_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); + RNA_def_property_ui_text(prop, "Color Space Settings", "Output color space settings"); + + prop = RNA_def_property(srna, "has_linear_colorspace", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ImageFormatSettings_has_linear_colorspace_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Has Linear Color Space", "File format expects linear color space"); } static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) @@ -6161,7 +6213,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 0, 3); - RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair"); + RNA_def_property_ui_text(prop, "Additional Subdivision", "Additional subdivision along the hair"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); /* Performance */ diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 3c8f1ee28c9..56d1b48811a 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -21,6 +21,7 @@ #include "BLI_utildefines.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_paint.h" #include "RNA_define.h" @@ -191,8 +192,23 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr) { + ID *id = ptr->owner_id; TexMapping *texmap = ptr->data; BKE_texture_mapping_init(texmap); + + if (GS(id->name) == ID_NT) { + bNodeTree *ntree = (bNodeTree *)ptr->owner_id; + /* Try to find and tag the node that this #TexMapping belongs to. */ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + /* This assumes that the #TexMapping is stored at the beginning of the node storage. This is + * generally true, see #NodeTexBase. If the assumption happens to be false, there might be a + * missing update. */ + if (node->storage == texmap) { + BKE_ntree_update_tag_node_property(ntree, node); + } + } + } + rna_Texture_update(bmain, scene, ptr); } diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 30a4268e5a0..a0d53701e26 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -208,7 +208,6 @@ static void rna_userdef_version_get(PointerRNA *ptr, int *value) /** Mark the preferences as being changed so they are saved on exit. */ # define USERDEF_TAG_DIRTY rna_userdef_is_dirty_update_impl() -/** Use single function so we can more easily break-point it. */ void rna_userdef_is_dirty_update_impl(void) { /* We can't use 'ptr->data' because this update function @@ -219,14 +218,11 @@ void rna_userdef_is_dirty_update_impl(void) } } -/** - * Use as a fallback update handler, - * never use 'ptr' unless its type is checked. - */ void rna_userdef_is_dirty_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { + /* WARNING: never use 'ptr' unless its type is checked. */ rna_userdef_is_dirty_update_impl(); } diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 88984a652d7..a5e5bf36dcd 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -61,7 +61,7 @@ set(SRC intern/MOD_meshcache_pc2.c intern/MOD_meshcache_util.c intern/MOD_meshdeform.c - intern/MOD_meshsequencecache.c + intern/MOD_meshsequencecache.cc intern/MOD_mirror.c intern/MOD_multires.c intern/MOD_nodes.cc diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 4b2dfd7d493..b237f952287 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -412,7 +412,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, } Object *end_cap_ob = amd->end_cap; if (end_cap_ob && end_cap_ob != ctx->object) { - if (start_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) { + if (end_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) { vgroup_end_cap_remap = BKE_object_defgroup_index_map_create( end_cap_ob, ctx->object, &vgroup_end_cap_remap_len); } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index cbad4ccd662..b6cceade4e2 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -111,6 +111,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * &(struct BMeshCreateParams){0}, &(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, .add_key_index = false, .use_shapekey = false, .active_shapekey = 0, diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 52773e6d3ef..915428f99da 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -244,6 +244,7 @@ static BMesh *BMD_mesh_bm_create( BMeshFromMeshParams bmesh_from_mesh_params{}; bmesh_from_mesh_params.calc_face_normal = true; + bmesh_from_mesh_params.calc_vert_normal = true; BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params); if (UNLIKELY(*r_is_flip)) { diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 8434446a074..67515478be5 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -91,6 +91,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * DecimateModifierData *dmd = (DecimateModifierData *)md; Mesh *mesh = meshData, *result = NULL; BMesh *bm; + bool calc_vert_normal; bool calc_face_normal; float *vweights = NULL; @@ -107,18 +108,21 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * return mesh; } calc_face_normal = true; + calc_vert_normal = true; break; case MOD_DECIM_MODE_UNSUBDIV: if (dmd->iter == 0) { return mesh; } calc_face_normal = false; + calc_vert_normal = false; break; case MOD_DECIM_MODE_DISSOLVE: if (dmd->angle == 0.0f) { return mesh; } calc_face_normal = true; + calc_vert_normal = false; break; default: return mesh; @@ -160,6 +164,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * &(struct BMeshCreateParams){0}, &(struct BMeshFromMeshParams){ .calc_face_normal = calc_face_normal, + .calc_vert_normal = calc_vert_normal, .cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX}, diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 3570bdda5a9..14431e5ff2e 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -57,6 +57,7 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd) &(struct BMeshCreateParams){0}, &(struct BMeshFromMeshParams){ .calc_face_normal = calc_face_normals, + .calc_vert_normal = false, .add_key_index = false, .use_shapekey = false, .active_shapekey = 0, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.cc index 14af22645e3..c30ab622842 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc @@ -60,11 +60,11 @@ static void initData(ModifierData *md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier)); - mcmd->cache_file = NULL; + mcmd->cache_file = nullptr; mcmd->object_path[0] = '\0'; mcmd->read_flag = MOD_MESHSEQ_READ_ALL; @@ -80,13 +80,13 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla BKE_modifier_copydata_generic(md, target, flag); - tmcmd->reader = NULL; + tmcmd->reader = nullptr; tmcmd->reader_object_path[0] = '\0'; } static void freeData(ModifierData *md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); if (mcmd->reader) { mcmd->reader_object_path[0] = '\0'; @@ -98,10 +98,10 @@ static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); /* leave it up to the modifier to check the file is valid on calculation */ - return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0'); + return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0'); } static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh) @@ -145,17 +145,17 @@ static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh) static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { #if defined(WITH_USD) || defined(WITH_ALEMBIC) - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); /* Only used to check whether we are operating on org data or not... */ - Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL; + Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr; Mesh *org_mesh = mesh; Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); CacheFile *cache_file = mcmd->cache_file; const float frame = DEG_get_ctime(ctx->depsgraph); const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); - const char *err_str = NULL; + const char *err_str = nullptr; if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) { STRNCPY(mcmd->reader_object_path, mcmd->object_path); @@ -196,7 +196,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } } - if (me != NULL) { + if (me != nullptr) { MVert *mvert = mesh->mvert; MEdge *medge = mesh->medge; MPoly *mpoly = mesh->mpoly; @@ -205,15 +205,16 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * flags) and duplicate those too. */ if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) { /* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */ - mesh = (Mesh *)BKE_id_copy_ex(NULL, - &mesh->id, - NULL, - LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | - LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW); + mesh = reinterpret_cast<Mesh *>( + BKE_id_copy_ex(nullptr, + &mesh->id, + nullptr, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW)); } } - Mesh *result = NULL; + Mesh *result = nullptr; switch (cache_file->type) { case CACHEFILE_TYPE_ALEMBIC: { @@ -250,8 +251,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BKE_modifier_set_error(ctx->object, md, "%s", err_str); } - if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) { - BKE_id_free(NULL, mesh); + if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) { + BKE_id_free(nullptr, mesh); mesh = org_mesh; } @@ -265,9 +266,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode) { #if defined(WITH_USD) || defined(WITH_ALEMBIC) - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); /* Do not evaluate animations if using the render engine procedural. */ - return (mcmd->cache_file != NULL) && + return (mcmd->cache_file != nullptr) && !BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode); #else UNUSED_VARS(scene, md, dag_eval_mode); @@ -277,16 +278,16 @@ static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mod static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); - walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER); + walk(userData, ob, reinterpret_cast<ID **>(&mcmd->cache_file), IDWALK_CB_USER); } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); - if (mcmd->cache_file != NULL) { + if (mcmd->cache_file != nullptr) { DEG_add_object_cache_relation( ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File"); } @@ -307,12 +308,13 @@ static void panel_draw(const bContext *C, Panel *panel) uiTemplateCacheFile(layout, C, ptr, "cache_file"); if (has_cache_file) { - uiItemPointerR(layout, ptr, "object_path", &cache_file_ptr, "object_paths", NULL, ICON_NONE); + uiItemPointerR( + layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE); } if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) { - uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE); } modifier_panel_end(layout, ptr); @@ -332,7 +334,7 @@ static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); uiTemplateCacheFileVelocity(layout, &fileptr); - uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE); } static void time_panel_draw(const bContext *UNUSED(C), Panel *panel) @@ -387,27 +389,27 @@ static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register( region_type, eModifierType_MeshSequenceCache, panel_draw); - modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type); + modifier_subpanel_register(region_type, "time", "Time", nullptr, time_panel_draw, panel_type); modifier_subpanel_register(region_type, "render_procedural", "Render Procedural", - NULL, + nullptr, render_procedural_panel_draw, panel_type); modifier_subpanel_register( - region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type); + region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type); modifier_subpanel_register(region_type, "override_layers", "Override Layers", - NULL, + nullptr, override_layers_panel_draw, panel_type); } static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) { - MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md; - msmcd->reader = NULL; + MeshSeqCacheModifierData *msmcd = reinterpret_cast<MeshSeqCacheModifierData *>(md); + msmcd->reader = nullptr; msmcd->reader_object_path[0] = '\0'; } @@ -417,29 +419,30 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* structSize */ sizeof(MeshSeqCacheModifierData), /* srna */ &RNA_MeshSequenceCacheModifier, /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs, + /* flags */ + static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs), /* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */ /* copyData */ copyData, - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, + /* deformVerts */ nullptr, + /* deformMatrices */ nullptr, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyGeometrySet */ NULL, + /* modifyGeometrySet */ nullptr, /* initData */ initData, - /* requiredDataMask */ NULL, + /* requiredDataMask */ nullptr, /* freeData */ freeData, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, + /* dependsOnNormals */ nullptr, /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* foreachTexLink */ nullptr, + /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, + /* blendWrite */ nullptr, /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 79dcdf48402..e560a859735 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -61,6 +61,7 @@ static Mesh *triangulate_mesh(Mesh *mesh, &((struct BMeshCreateParams){0}), &((struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = false, .cd_mask_extra = cd_mask_extra, })); diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 6d95a169319..dae7d19844e 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -69,6 +69,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh * &(struct BMeshCreateParams){0}, &(struct BMeshFromMeshParams){ .calc_face_normal = true, + .calc_vert_normal = true, .add_key_index = false, .use_shapekey = false, .active_shapekey = 0, diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index d5d97f7be2e..3d3450d9252 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -143,8 +143,6 @@ void ntreeCompositExecTree(struct Scene *scene, struct RenderData *rd, int rendering, int do_previews, - const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings, const char *view_name); /** diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index 7522ad1efe6..0b75dd9cef3 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -206,14 +206,12 @@ void ntreeCompositExecTree(Scene *scene, RenderData *rd, int rendering, int do_preview, - const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, const char *view_name) { #ifdef WITH_COMPOSITOR - COM_execute(rd, scene, ntree, rendering, view_settings, display_settings, view_name); + COM_execute(rd, scene, ntree, rendering, view_name); #else - UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings, view_name); + UNUSED_VARS(scene, ntree, rd, rendering, view_name); #endif UNUSED_VARS(do_preview); diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc index 28de1f48b79..1fd6e62b4c5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc +++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc @@ -303,7 +303,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; node_composit_buts_file_output(layout, C, ptr); - uiTemplateImageSettings(layout, &imfptr, false); + uiTemplateImageSettings(layout, &imfptr, true); /* disable stereo output for multilayer, too much work for something that no one will use */ /* if someone asks for that we can implement it */ @@ -422,12 +422,16 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi ICON_NONE); } - col = uiLayoutColumn(layout, false); - uiLayoutSetActive(col, use_node_format == false); - uiTemplateImageSettings(col, &imfptr, false); + if (!use_node_format) { + const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render"); - if (is_multiview) { - uiTemplateImageFormatViews(layout, &imfptr, nullptr); + col = uiLayoutColumn(layout, false); + uiTemplateImageSettings(col, &imfptr, use_color_management); + + if (is_multiview) { + col = uiLayoutColumn(layout, false); + uiTemplateImageFormatViews(col, &imfptr, nullptr); + } } } } diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index 3718ce6f359..a4fc1a6bfd1 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -15,11 +15,20 @@ namespace blender::nodes::node_fn_rotate_euler_cc { static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b) { + auto enable_axis_angle = [](bNode &node) { + node.custom1 = FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE; + }; + b.is_function_node(); b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value(); - b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER); - b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ); - b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE); + b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER).make_available([](bNode &node) { + node.custom1 = FN_NODE_ROTATE_EULER_TYPE_EULER; + }); + b.add_input<decl::Vector>(N_("Axis")) + .default_value({0.0, 0.0, 1.0}) + .subtype(PROP_XYZ) + .make_available(enable_axis_angle); + b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE).make_available(enable_axis_angle); b.add_output<decl::Vector>(N_("Rotation")); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc index 6c7d7ed375b..38d81c54933 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc @@ -17,6 +17,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveArc) static void node_declare(NodeDeclarationBuilder &b) { + auto enable_points = [](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; + }; + auto enable_radius = [](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS; + }; + b.add_input<decl::Int>(N_("Resolution")) .default_value(16) .min(2) @@ -26,34 +33,41 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input<decl::Vector>(N_("Start")) .default_value({-1.0f, 0.0f, 0.0f}) .subtype(PROP_TRANSLATION) - .description(N_("Position of the first control point")); + .description(N_("Position of the first control point")) + .make_available(enable_points); b.add_input<decl::Vector>(N_("Middle")) .default_value({0.0f, 2.0f, 0.0f}) .subtype(PROP_TRANSLATION) - .description(N_("Position of the middle control point")); + .description(N_("Position of the middle control point")) + .make_available(enable_points); b.add_input<decl::Vector>(N_("End")) .default_value({1.0f, 0.0f, 0.0f}) .subtype(PROP_TRANSLATION) - .description(N_("Position of the last control point")); + .description(N_("Position of the last control point")) + .make_available(enable_points); b.add_input<decl::Float>(N_("Radius")) .default_value(1.0f) .min(0.0f) .subtype(PROP_DISTANCE) - .description(N_("Distance of the points from the origin")); + .description(N_("Distance of the points from the origin")) + .make_available(enable_radius); b.add_input<decl::Float>(N_("Start Angle")) .default_value(0.0f) .subtype(PROP_ANGLE) - .description(N_("Starting angle of the arc")); + .description(N_("Starting angle of the arc")) + .make_available(enable_radius); b.add_input<decl::Float>(N_("Sweep Angle")) .default_value(1.75f * M_PI) .min(-2 * M_PI) .max(2 * M_PI) .subtype(PROP_ANGLE) - .description(N_("Length of the arc")); + .description(N_("Length of the arc")) + .make_available(enable_radius); b.add_input<decl::Float>(N_("Offset Angle")) .default_value(0.0f) .subtype(PROP_ANGLE) - .description(N_("Offset angle of the arc")); + .description(N_("Offset angle of the arc")) + .make_available(enable_points); b.add_input<decl::Bool>(N_("Connect Center")) .default_value(false) .description(N_("Connect the arc at the center")); @@ -64,17 +78,14 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); b.add_output<decl::Vector>(N_("Center")) .description(N_("The center of the circle described by the three points")) - .make_available( - [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; }); + .make_available(enable_points); b.add_output<decl::Vector>(N_("Normal")) .description(N_("The normal direction of the plane described by the three points, pointing " "towards the positive Z axis")) - .make_available( - [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; }); + .make_available(enable_points); b.add_output<decl::Float>(N_("Radius")) .description(N_("The radius of the circle described by the three points")) - .make_available( - [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; }); + .make_available(enable_points); } static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index 2fb9f724130..aa4b3a785f1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -13,6 +13,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle) static void node_declare(NodeDeclarationBuilder &b) { + auto endable_points = [](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS; + }; + auto enable_radius = [](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS; + }; + b.add_input<decl::Int>(N_("Resolution")) .default_value(32) .min(3) @@ -23,28 +30,30 @@ static void node_declare(NodeDeclarationBuilder &b) .subtype(PROP_TRANSLATION) .description( N_("One of the three points on the circle. The point order determines the circle's " - "direction")); + "direction")) + .make_available(endable_points); b.add_input<decl::Vector>(N_("Point 2")) .default_value({0.0f, 1.0f, 0.0f}) .subtype(PROP_TRANSLATION) .description( N_("One of the three points on the circle. The point order determines the circle's " - "direction")); + "direction")) + .make_available(endable_points); b.add_input<decl::Vector>(N_("Point 3")) .default_value({1.0f, 0.0f, 0.0f}) .subtype(PROP_TRANSLATION) .description( N_("One of the three points on the circle. The point order determines the circle's " - "direction")); + "direction")) + .make_available(endable_points); b.add_input<decl::Float>(N_("Radius")) .default_value(1.0f) .min(0.0f) .subtype(PROP_DISTANCE) - .description(N_("Distance of the points from the origin")); + .description(N_("Distance of the points from the origin")) + .make_available(enable_radius); b.add_output<decl::Geometry>(N_("Curve")); - b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) { - node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS; - }); + b.add_output<decl::Vector>(N_("Center")).make_available(endable_points); } static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 2e2f4254752..62dbcc91cc6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -13,21 +13,29 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine) static void node_declare(NodeDeclarationBuilder &b) { + auto enable_direction = [](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION; + }; + b.add_input<decl::Vector>(N_("Start")) .subtype(PROP_TRANSLATION) .description(N_("Position of the first control point")); b.add_input<decl::Vector>(N_("End")) .default_value({0.0f, 0.0f, 1.0f}) .subtype(PROP_TRANSLATION) - .description(N_("Position of the second control point")); + .description(N_("Position of the second control point")) + .make_available([](bNode &node) { + node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS; + }); b.add_input<decl::Vector>(N_("Direction")) .default_value({0.0f, 0.0f, 1.0f}) - .description( - N_("Direction the line is going in. The length of this vector does not matter")); + .description(N_("Direction the line is going in. The length of this vector does not matter")) + .make_available(enable_direction); b.add_input<decl::Float>(N_("Length")) .default_value(1.0f) .subtype(PROP_DISTANCE) - .description(N_("Distance between the two points")); + .description(N_("Distance between the two points")) + .make_available(enable_direction); b.add_output<decl::Geometry>(N_("Curve")); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 8e28a4ba9b9..d9f29d1ef1c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -26,17 +26,35 @@ namespace blender::nodes::node_geo_distribute_points_on_faces_cc { static void node_declare(NodeDeclarationBuilder &b) { + auto enable_random = [](bNode &node) { + node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM; + }; + auto enable_poisson = [](bNode &node) { + node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON; + }; + b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); - b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f); - b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field(); + b.add_input<decl::Float>(N_("Distance Min")) + .min(0.0f) + .subtype(PROP_DISTANCE) + .make_available(enable_poisson); + b.add_input<decl::Float>(N_("Density Max")) + .default_value(10.0f) + .min(0.0f) + .make_available(enable_poisson); + b.add_input<decl::Float>(N_("Density")) + .default_value(10.0f) + .min(0.0f) + .supports_field() + .make_available(enable_random); b.add_input<decl::Float>(N_("Density Factor")) .default_value(1.0f) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR) - .supports_field(); + .supports_field() + .make_available(enable_poisson); b.add_input<decl::Int>(N_("Seed")); b.add_output<decl::Geometry>(N_("Points")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc index f9d9ed75f30..7923ad6264d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc @@ -31,7 +31,8 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input<decl::Vector>(N_("Axis")) .default_value({1.0f, 0.0f, 0.0f}) .supports_field() - .description(N_("Direction in which to scale the element")); + .description(N_("Direction in which to scale the element")) + .make_available([](bNode &node) { node.custom2 = GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS; }); b.add_output<decl::Geometry>(N_("Geometry")); }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index 301410f5126..271dd824d27 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -106,10 +106,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, for (const int i : bezier.positions().index_range()) { if (current_mask < selection.size() && selection[current_mask] == current_point) { if (mode & GEO_NODE_CURVE_HANDLE_LEFT) { - bezier.set_handle_position_left(i, positions_input[i] + offsets_input[i]); + bezier.set_handle_position_left( + i, positions_input[current_point] + offsets_input[current_point]); } else { - bezier.set_handle_position_right(i, positions_input[i] + offsets_input[i]); + bezier.set_handle_position_right( + i, positions_input[current_point] + offsets_input[current_point]); } current_mask++; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index 543e57d38ad..0892e068ce2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -16,8 +16,11 @@ static void set_id_in_component(GeometryComponent &component, const Field<bool> &selection_field, const Field<int> &id_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ? + ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; + GeometryComponentFieldContext field_context{component, domain}; + const int domain_size = component.attribute_domain_size(domain); if (domain_size == 0) { return; } @@ -30,7 +33,7 @@ static void set_id_in_component(GeometryComponent &component, * the field. However, as an optimization, use a faster code path when it already exists. */ if (component.attribute_exists("id")) { OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>( - "id", ATTR_DOMAIN_POINT); + "id", domain); evaluator.add_with_destination(id_field, id_attribute.varray()); evaluator.evaluate(); id_attribute.save(); @@ -41,7 +44,7 @@ static void set_id_in_component(GeometryComponent &component, const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); const VArray<int> &result_ids = evaluator.get_evaluated<int>(0); OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>( - "id", ATTR_DOMAIN_POINT); + "id", domain); result_ids.materialize(selection, id_attribute.as_span()); id_attribute.save(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index 5ded8413cf9..76cdbfb140f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -44,7 +44,13 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh, CustomData_MeshMasks cd_mask_extra = { CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX}; BMeshCreateParams create_params{0}; - BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra}; + BMeshFromMeshParams from_mesh_params{}; + from_mesh_params.calc_face_normal = true; + from_mesh_params.calc_vert_normal = true; + from_mesh_params.add_key_index = true; + from_mesh_params.use_shapekey = true; + from_mesh_params.active_shapekey = 1; + from_mesh_params.cd_mask_extra = cd_mask_extra; BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params); /* Tag faces to be triangulated from the selection mask. */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc index d4a0c092acd..a5ab6db0002 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc @@ -10,6 +10,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "NOD_socket_search_link.hh" + namespace blender::nodes::node_shader_tex_sky_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -229,6 +231,24 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); } +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + if (params.in_out() == SOCK_OUT) { + search_link_ops_for_declarations(params, declaration.outputs()); + return; + } + if (params.node_tree().typeinfo->validate_link( + static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) { + params.add_item(IFACE_("Vector"), [](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeTexSky"); + NodeTexSky *tex = (NodeTexSky *)node.storage; + tex->sun_disc = false; + params.update_and_connect_available_socket(node, "Vector"); + }); + } +} + } // namespace blender::nodes::node_shader_tex_sky_cc /* node type definition */ @@ -247,6 +267,7 @@ void register_node_type_sh_tex_sky() node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky); /* Remove vector input for Nishita sky model. */ node_type_update(&ntype, file_ns::node_shader_update_sky); + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 3f1a9d758ae..a041492fb13 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -17,9 +17,15 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b) b.is_function_node(); b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value(); b.add_input<decl::Vector>(N_("Center")); - b.add_input<decl::Vector>(N_("Axis")).min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f}); + b.add_input<decl::Vector>(N_("Axis")) + .min(-1.0f) + .max(1.0f) + .default_value({0.0f, 0.0f, 1.0f}) + .make_available([](bNode &node) { node.custom1 = NODE_VECTOR_ROTATE_TYPE_AXIS; }); b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE); - b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); + b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).make_available([](bNode &node) { + node.custom1 = NODE_VECTOR_ROTATE_TYPE_EULER_XYZ; + }); b.add_output<decl::Vector>(N_("Vector")); } diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index ccd483083ef..9ceff9b84b6 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -1050,7 +1050,8 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) } PyDoc_STRVAR(bpy_bmesh_from_object_doc, - ".. method:: from_object(object, depsgraph, cage=False, face_normals=True)\n" + ".. method:: from_object(object, depsgraph, cage=False, face_normals=True, " + "vertex_normals=True)\n" "\n" " Initialize this bmesh from existing object data-block (only meshes are currently " "supported).\n" @@ -1060,10 +1061,12 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc, " :arg cage: Get the mesh as a deformed cage.\n" " :type cage: boolean\n" " :arg face_normals: Calculate face normals.\n" + " :arg vertex_normals: Calculate vertex normals.\n" " :type face_normals: boolean\n"); static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"object", "depsgraph", "cage", "face_normals", NULL}; + static const char *kwlist[] = { + "object", "depsgraph", "cage", "face_normals", "vertex_normals", NULL}; PyObject *py_object; PyObject *py_depsgraph; Object *ob, *ob_eval; @@ -1073,6 +1076,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject BMesh *bm; bool use_cage = false; bool use_fnorm = true; + bool use_vert_normal = true; const CustomData_MeshMasks data_masks = CD_MASK_BMESH; BPY_BM_CHECK_OBJ(self); @@ -1086,7 +1090,9 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject PyC_ParseBool, &use_cage, PyC_ParseBool, - &use_fnorm) || + &use_fnorm, + PyC_ParseBool, + &use_vert_normal) || !(ob = PyC_RNA_AsPointer(py_object, "Object")) || !(depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) { return NULL; @@ -1137,6 +1143,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject me_eval, (&(struct BMeshFromMeshParams){ .calc_face_normal = use_fnorm, + .calc_vert_normal = use_vert_normal, })); if (need_free) { @@ -1148,7 +1155,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject PyDoc_STRVAR( bpy_bmesh_from_mesh_doc, - ".. method:: from_mesh(mesh, face_normals=True, use_shape_key=False, shape_key_index=0)\n" + ".. method:: from_mesh(mesh, face_normals=True, vertex_normals=True, use_shape_key=False, " + "shape_key_index=0)\n" "\n" " Initialize this bmesh from existing mesh datablock.\n" "\n" @@ -1168,11 +1176,13 @@ PyDoc_STRVAR( "mesh won't be added.\n"); static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"mesh", "face_normals", "use_shape_key", "shape_key_index", NULL}; + static const char *kwlist[] = { + "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", NULL}; BMesh *bm; PyObject *py_mesh; Mesh *me; bool use_fnorm = true; + bool use_vert_normal = true; bool use_shape_key = false; int shape_key_index = 0; @@ -1186,6 +1196,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject * PyC_ParseBool, &use_fnorm, PyC_ParseBool, + &use_vert_normal, + PyC_ParseBool, &use_shape_key, &shape_key_index) || !(me = PyC_RNA_AsPointer(py_mesh, "Mesh"))) { @@ -1198,6 +1210,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject * me, (&(struct BMeshFromMeshParams){ .calc_face_normal = use_fnorm, + .calc_vert_normal = use_vert_normal, .use_shapekey = use_shape_key, .active_shapekey = shape_key_index + 1, })); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 6c58e2e3a30..6f278c1c771 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -36,6 +36,11 @@ #include "../generic/py_capi_rna.h" #include "../generic/py_capi_utils.h" +/* Disabled duplicating strings because the array can still be freed and + * the strings from it referenced, for now we can't support dynamically + * created strings from Python. */ +// #define USE_ENUM_COPY_STRINGS + /* -------------------------------------------------------------------- */ /** \name Shared Enums & Doc-Strings * \{ */ @@ -1855,7 +1860,7 @@ static bool py_long_as_int(PyObject *py_long, int *r_int) return false; } -#if 0 +#ifdef USE_ENUM_COPY_STRINGS /* copies orig to buf, then sets orig to buf, returns copy length */ static size_t strswapbufcpy(char *buf, const char **orig) { @@ -1898,6 +1903,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast); PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast); int i; +#ifdef USE_ENUM_COPY_STRINGS + Py_ssize_t totbuf = 0; +#endif short default_used = 0; const char *default_str_cmp = NULL; int default_int_cmp = 0; @@ -1986,6 +1994,11 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, } items[i] = tmp; + +#ifdef USE_ENUM_COPY_STRINGS + /* Calculate combine string length. */ + totbuf += id_str_size + name_str_size + desc_str_size + 3; /* 3 is for '\0's */ +#endif } else if (item == Py_None) { /* Only set since the rest is cleared. */ @@ -2030,13 +2043,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, } } - /* disabled duplicating strings because the array can still be freed and - * the strings from it referenced, for now we can't support dynamically - * created strings from python. */ -#if 0 - /* this would all work perfectly _but_ the python strings may be freed - * immediately after use, so we need to duplicate them, ugh. - * annoying because it works most of the time without this. */ +#ifdef USE_ENUM_COPY_STRINGS + /* This would all work perfectly _but_ the python strings may be freed immediately after use, + * so we need to duplicate them, ugh. annoying because it works most of the time without this. */ { EnumPropertyItem *items_dup = MEM_mallocN((sizeof(EnumPropertyItem) * (seq_len + 1)) + (sizeof(char) * totbuf), diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index cac320ad246..0a8668221ad 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -338,8 +338,8 @@ void RE_RenderFrame(struct Render *re, struct Scene *scene, struct ViewLayer *single_layer, struct Object *camera_override, - const int frame, - const float subframe, + int frame, + float subframe, bool write_still); /** * A version of #RE_RenderFrame that saves images to disk. diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h index d297ca19404..85bd06b9940 100644 --- a/source/blender/render/RE_texture_margin.h +++ b/source/blender/render/RE_texture_margin.h @@ -23,7 +23,7 @@ struct Mesh; * \param mask: pixels with a mask value of 1 are not written to. * \param margin: the size of the margin in pixels. * \param me: the mesh to use the polygons of. - * \param mloopuv: the uv data to use. + * \param uv_layer: The UV layer to use. */ void RE_generate_texturemargin_adjacentfaces( struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 0ca2ca82cf7..a6c2e9eb194 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -1212,14 +1212,8 @@ static void do_render_compositor(Render *re) RenderView *rv; for (rv = re->result->views.first; rv; rv = rv->next) { - ntreeCompositExecTree(re->pipeline_scene_eval, - ntree, - &re->r, - true, - G.background == 0, - &re->scene->view_settings, - &re->scene->display_settings, - rv->name); + ntreeCompositExecTree( + re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name); } ntree->stats_draw = NULL; @@ -1960,17 +1954,19 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, return false; } + ImageFormatData image_format; + BKE_image_format_init_for_write(&image_format, scene, NULL); + const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2; const float dither = scene->r.dither_intensity; - if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { int view_id; for (view_id = 0; view_id < totvideos; view_id++) { const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); - IMB_colormanagement_imbuf_for_write( - ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format); + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format); ok &= mh->append_movie(movie_ctx_arr[view_id], rd, @@ -1992,21 +1988,16 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, ImBuf *ibuf_arr[3] = {NULL}; int i; - BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D)); + BLI_assert((totvideos == 1) && (image_format.views_format == R_IMF_VIEWS_STEREO_3D)); for (i = 0; i < 2; i++) { int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id); - IMB_colormanagement_imbuf_for_write(ibuf_arr[i], - true, - false, - &scene->view_settings, - &scene->display_settings, - &scene->r.im_format); + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format); } - ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); + ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]); ok = mh->append_movie(movie_ctx_arr[0], rd, @@ -2024,6 +2015,8 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, } } + BKE_image_format_free(&image_format); + return ok; } diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index 2fe6e6d3caa..ea7fa961f0d 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -414,6 +414,11 @@ RenderResult *render_result_new(Render *re, rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2); rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2); + /* Preview does not support deferred render result allocation. */ + if (re->r.scemode & R_BUTS_PREVIEW) { + render_result_passes_allocated_ensure(rr); + } + return rr; } @@ -988,7 +993,7 @@ void render_result_exr_file_cache_write(Render *re) render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); - BKE_image_render_write_exr(NULL, rr, str, NULL, NULL, -1); + BKE_image_render_write_exr(NULL, rr, str, NULL, true, NULL, -1); } bool render_result_exr_file_cache_read(Render *re) diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 8849b029d46..ddf75f3d664 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -298,7 +298,7 @@ static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle, } if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) { CLOG_WARN(&LOG, - "Strip overlaps with itself or another strip, that is to be shuffled." + "Strip overlaps with itself or another strip, that is to be shuffled. " "This should never happen."); continue; } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 46f7b67c2ba..3c8474b1b6c 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -1037,6 +1037,10 @@ void wm_draw_update(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); GPU_context_main_lock(); + + GPU_render_begin(); + GPU_render_step(); + BKE_image_free_unused_gpu_textures(); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { @@ -1075,6 +1079,7 @@ void wm_draw_update(bContext *C) /* Draw non-windows (surfaces) */ wm_surfaces_iter(C, wm_draw_surface); + GPU_render_end(); GPU_context_main_unlock(); } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 6b7d3045da2..790b08437bd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -4428,6 +4428,9 @@ void WM_event_add_mousemove(wmWindow *win) /** \name Ghost Event Conversion * \{ */ +/** + * \return The WM enum for key or #EVENT_NONE (which should be ignored). + */ static int convert_key(GHOST_TKey key) { if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) { @@ -4451,7 +4454,7 @@ static int convert_key(GHOST_TKey key) case GHOST_kKeyLinefeed: return EVT_LINEFEEDKEY; case GHOST_kKeyClear: - return 0; + return EVENT_NONE; case GHOST_kKeyEnter: return EVT_RETKEY; @@ -4506,9 +4509,9 @@ static int convert_key(GHOST_TKey key) case GHOST_kKeyCapsLock: return EVT_CAPSLOCKKEY; case GHOST_kKeyNumLock: - return 0; + return EVENT_NONE; case GHOST_kKeyScrollLock: - return 0; + return EVENT_NONE; case GHOST_kKeyLeftArrow: return EVT_LEFTARROWKEY; @@ -4520,7 +4523,7 @@ static int convert_key(GHOST_TKey key) return EVT_DOWNARROWKEY; case GHOST_kKeyPrintScreen: - return 0; + return EVENT_NONE; case GHOST_kKeyPause: return EVT_PAUSEKEY; @@ -4562,9 +4565,28 @@ static int convert_key(GHOST_TKey key) case GHOST_kKeyMediaLast: return EVT_MEDIALAST; - default: - return EVT_UNKNOWNKEY; /* #GHOST_kKeyUnknown (this could be asserted). */ + case GHOST_kKeyUnknown: + return EVT_UNKNOWNKEY; + +#if defined(__GNUC__) || defined(__clang__) + /* Ensure all members of this enum are handled, otherwise generate a compiler warning. + * Note that these members have been handled, these ranges are to satisfy the compiler. */ + case GHOST_kKeyF1 ... GHOST_kKeyF24: + case GHOST_kKeyA ... GHOST_kKeyZ: + case GHOST_kKeyNumpad0 ... GHOST_kKeyNumpad9: + case GHOST_kKey0 ... GHOST_kKey9: { + BLI_assert_unreachable(); + break; + } +#else + default: { + break; + } +#endif } + + CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", (int)key); + return EVENT_NONE; } static void wm_eventemulation(wmEvent *event, bool test_only) @@ -5087,6 +5109,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventKeyUp: { GHOST_TEventKeyData *kd = customdata; event.type = convert_key(kd->key); + if (UNLIKELY(event.type == EVENT_NONE)) { + break; + } + event.ascii = kd->ascii; /* Might be not NULL terminated. */ memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); |