diff options
Diffstat (limited to 'source/blender')
653 files changed, 19179 insertions, 14600 deletions
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index b15608703de..dc7f00b63d9 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -80,19 +80,19 @@ void AbcCameraWriter::do_write() m_camera_sample.setNearClippingPlane(cam->clip_start); m_camera_sample.setFarClippingPlane(cam->clip_end); - if (cam->dof_ob) { - Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0], - m_object->loc[1] - cam->dof_ob->loc[1], - m_object->loc[2] - cam->dof_ob->loc[2]); + if (cam->dof.focus_object) { + Imath::V3f v(m_object->loc[0] - cam->dof.focus_object->loc[0], + m_object->loc[1] - cam->dof.focus_object->loc[1], + m_object->loc[2] - cam->dof.focus_object->loc[2]); m_camera_sample.setFocusDistance(v.length()); } else { - m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance); + m_camera_sample.setFocusDistance(cam->dof.focus_distance); } /* Blender camera does not have an fstop param, so try to find a custom prop * instead. */ - m_camera_sample.setFStop(cam->gpu_dof.fstop); + m_camera_sample.setFStop(cam->dof.aperture_fstop); m_camera_sample.setLensSqueezeRatio(1.0); m_camera_schema.set(m_camera_sample); @@ -166,8 +166,8 @@ void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_ bcam->shifty = v_film_offset / apperture_y / film_aspect; bcam->clip_start = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane())); bcam->clip_end = static_cast<float>(cam_sample.getFarClippingPlane()); - bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance()); - bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop()); + bcam->dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance()); + bcam->dof.aperture_fstop = static_cast<float>(cam_sample.getFStop()); m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index 8b8ed6c5c4b..08f8eb8bd8f 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -86,7 +86,7 @@ void AbcTransformWriter::do_write() m_xform, m_xform.getSchema().getTimeSampling()); } - m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW)); + m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEWPORT)); if (!m_first_frame && !m_is_animated) { return; diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index 7ff8514f675..e55cb69a5c6 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -36,6 +36,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con bool BKE_appdir_app_is_portable_install(void); bool BKE_appdir_app_template_any(void); bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len); +bool BKE_appdir_app_template_has_userpref(const char *app_template); void BKE_appdir_app_templates(struct ListBase *templates); /* Initialize path to program executable */ @@ -44,6 +45,9 @@ void BKE_appdir_program_path_init(const char *argv0); const char *BKE_appdir_program_path(void); const char *BKE_appdir_program_dir(void); +/* Return OS fonts directory. */ +bool BKE_appdir_font_folder_default(char *dir); + /* find python executable */ bool BKE_appdir_program_python_search(char *fullpath, const size_t fullpath_len, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index b5da30e725d..6839e13ffe1 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -84,7 +84,9 @@ bool BKE_pose_minmax( int bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail); struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name); -struct GHash *BKE_armature_bone_from_name_map(struct bArmature *arm); + +void BKE_armature_bone_hash_make(struct bArmature *arm); +void BKE_armature_bone_hash_free(struct bArmature *arm); bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index e01f6a6b751..3fae40d6c7b 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 280 -#define BLENDER_SUBVERSION 60 +#define BLENDER_SUBVERSION 71 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index 216bef0d1e3..76c05b0411a 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -62,6 +62,8 @@ struct UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf, bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports); bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports); +bool BKE_blendfile_userdef_write_all(struct ReportList *reports); + struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 10cd129fbf9..caed4959eff 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -139,8 +139,6 @@ bool BKE_camera_view_frame_fit_to_coords(const struct Depsgraph *depsgraph, float r_co[3], float *r_scale); -void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings); - /* Camera multi-view API */ struct Object *BKE_camera_multiview_render(struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 47786629aed..0e093bb086b 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -161,6 +161,8 @@ bool BKE_collection_move(struct Main *bmain, bool BKE_collection_find_cycle(struct Collection *new_ancestor, struct Collection *collection); +bool BKE_collection_has_collection(struct Collection *parent, struct Collection *collection); + /* Iteration callbacks. */ typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 8be43a50be6..0d2998cc51e 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -311,8 +311,23 @@ int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); +/* Gets pointer to the dependency graph. + * If it doesn't exist yet, it will be allocated. + * + * The result dependency graph is NOT guaranteed to be up-to-date neither from relation nor from + * evaluated data points of view. + * + * NOTE: Can not be used if access to a fully evaluated datablock is needed. */ struct Depsgraph *CTX_data_depsgraph(const bContext *C); +/* Gets fully updated and evaluated dependency graph. + * + * All the relations and evaluated objects are guaranteed to be up to date. + * + * NOTE: Will be expensive if there are relations or objects tagged for update. + * NOTE: If there are pending updates depsgraph hooks will be invoked. */ +struct Depsgraph *CTX_data_evaluated_depsgraph(const bContext *C); + /* Will Return NULL if depsgraph is not allocated yet. * Only used by handful of operators which are run on file load. */ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 4eaa0fbe057..df1e7a7baea 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -134,21 +134,11 @@ void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex); void BKE_curve_editNurb_free(struct Curve *cu); struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu); -float *BKE_curve_make_orco(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - int *r_numVerts); float *BKE_curve_surf_make_orco(struct Object *ob); void BKE_curve_bevelList_free(struct ListBase *bev); void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render); -void BKE_curve_bevel_make(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct ListBase *disp, - const bool for_render, - const bool use_render_resolution, - struct LinkNode *ob_cyclic_list); +void BKE_curve_bevel_make(struct Object *ob, struct ListBase *disp); void BKE_curve_forward_diff_bezier( float q0, float q1, float q2, float q3, float *p, int it, int stride); @@ -212,9 +202,9 @@ void BKE_nurb_knot_calc_u(struct Nurb *nu); void BKE_nurb_knot_calc_v(struct Nurb *nu); /* nurb checks if they can be drawn, also clamp order func */ -bool BKE_nurb_check_valid_u(struct Nurb *nu); -bool BKE_nurb_check_valid_v(struct Nurb *nu); -bool BKE_nurb_check_valid_uv(struct Nurb *nu); +bool BKE_nurb_check_valid_u(const struct Nurb *nu); +bool BKE_nurb_check_valid_v(const struct Nurb *nu); +bool BKE_nurb_check_valid_uv(const struct Nurb *nu); bool BKE_nurb_order_clamp_u(struct Nurb *nu); bool BKE_nurb_order_clamp_v(struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 9bf5a2f9971..c57639a8193 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -85,27 +85,18 @@ void BKE_displist_make_surf(struct Depsgraph *depsgraph, struct ListBase *dispbase, struct Mesh **r_final, const bool for_render, - const bool for_orco, - const bool use_render_resolution); + const bool for_orco); void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const bool for_render, - const bool for_orco, - struct LinkNode *ob_cyclic_list); + const bool for_orco); void BKE_displist_make_curveTypes_forRender(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct Mesh **r_final, - const bool for_orco, - const bool use_render_resolution, - struct LinkNode *ob_cyclic_list); -void BKE_displist_make_curveTypes_forOrco(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct ListBase *dispbase, - struct LinkNode *ob_cyclic_list); + const bool for_orco); void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_displist_make_mball_forRender(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 91a558a9ee2..b7280c702d2 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -90,6 +90,7 @@ void BKE_editmesh_color_free(BMEditMesh *em); void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]; void BKE_editmesh_lnorspace_update(BMEditMesh *em); +void BKE_editmesh_ensure_autosmooth(BMEditMesh *em); /* editderivedmesh.c */ /* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index c1232addee3..4c1a115eb23 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -340,6 +340,7 @@ float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, struct ChannelDriver *driver_orig, float evaltime); +bool BKE_fcurve_is_empty(struct FCurve *fcu); /* evaluate fcurve and store value */ float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 2c19c1e2006..9fe8fc3880f 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -107,10 +107,10 @@ typedef struct Global { /** #Global.f */ enum { G_FLAG_RENDER_VIEWPORT = (1 << 0), - G_FLAG_BACKBUFSEL = (1 << 1), G_FLAG_PICKSEL = (1 << 2), /** Support simulating events (for testing). */ G_FLAG_EVENT_SIMULATE = (1 << 3), + G_FLAG_USERPREF_NO_SAVE_ON_EXIT = (1 << 4), G_FLAG_SCRIPT_AUTOEXEC = (1 << 13), /** When this flag is set ignore the prefs #USER_SCRIPT_AUTOEXEC_DISABLE. */ @@ -121,7 +121,8 @@ enum { /** Don't overwrite these flags when reading a file. */ #define G_FLAG_ALL_RUNTIME \ - (G_FLAG_SCRIPT_AUTOEXEC | G_FLAG_SCRIPT_OVERRIDE_PREF | G_FLAG_EVENT_SIMULATE) + (G_FLAG_SCRIPT_AUTOEXEC | G_FLAG_SCRIPT_OVERRIDE_PREF | G_FLAG_EVENT_SIMULATE | \ + G_FLAG_USERPREF_NO_SAVE_ON_EXIT) /** Flags to read from blend file. */ #define G_FLAG_ALL_READFILE 0 diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index e6f3d7b4a99..0eb8df1b19d 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -134,7 +134,8 @@ struct IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user); +void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user); +void IDP_FreePropertyContent(struct IDProperty *prop); void IDP_FreeProperty(struct IDProperty *prop); void IDP_ClearProperty(IDProperty *prop); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 28886a5a195..b9f2123b2bd 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -153,29 +153,6 @@ struct RenderData; struct RenderPass; struct RenderResult; -/* ima->source; where image comes from */ -#define IMA_SRC_CHECK 0 -#define IMA_SRC_FILE 1 -#define IMA_SRC_SEQUENCE 2 -#define IMA_SRC_MOVIE 3 -#define IMA_SRC_GENERATED 4 -#define IMA_SRC_VIEWER 5 - -/* ima->type, how to handle/generate it */ -#define IMA_TYPE_IMAGE 0 -#define IMA_TYPE_MULTILAYER 1 -/* generated */ -#define IMA_TYPE_UV_TEST 2 -/* viewers */ -#define IMA_TYPE_R_RESULT 4 -#define IMA_TYPE_COMPOSITE 5 - -enum { - IMA_GENTYPE_BLANK = 0, - IMA_GENTYPE_GRID = 1, - IMA_GENTYPE_GRID_COLOR = 2, -}; - /* ima->ok */ #define IMA_OK 1 #define IMA_OK_LOADED 2 @@ -340,12 +317,16 @@ void BKE_image_buf_fill_checker_color(unsigned char *rect, unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame); float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame); +/* Image modifications */ +bool BKE_image_is_dirty(struct Image *image); +void BKE_image_mark_dirty(struct Image *image, struct ImBuf *ibuf); + /* Guess offset for the first frame in the sequence */ int BKE_image_sequence_guess_offset(struct Image *image); bool BKE_image_has_anim(struct Image *image); bool BKE_image_has_packedfile(struct Image *image); +bool BKE_image_has_filepath(struct Image *ima); bool BKE_image_is_animated(struct Image *image); -bool BKE_image_is_dirty(struct Image *image); void BKE_image_file_format_set(struct Image *image, int ftype, const struct ImbFormatOptions *options); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index ecee00b1b3f..c410946f438 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -208,12 +208,13 @@ float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); -struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph, - struct Main *bmain, - struct Scene *sce, - struct Object *ob, - const bool apply_modifiers, - const bool calc_undeformed); +/* Create new mesh from the given object at its current state. + * The owner of this mesh is unknown, it is up to the caller to decide. */ +struct Mesh *BKE_mesh_new_from_object(struct Object *object); + +/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database. */ +struct Mesh *BKE_mesh_new_from_object_to_bmain(struct Main *bmain, struct Object *object); + struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_eval, @@ -671,11 +672,9 @@ void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh); /* Draw Cache */ enum { BKE_MESH_BATCH_DIRTY_ALL = 0, - BKE_MESH_BATCH_DIRTY_MAYBE_ALL, BKE_MESH_BATCH_DIRTY_SELECT, BKE_MESH_BATCH_DIRTY_SELECT_PAINT, BKE_MESH_BATCH_DIRTY_SHADING, - BKE_MESH_BATCH_DIRTY_SCULPT_COORDS, BKE_MESH_BATCH_DIRTY_UVEDIT_ALL, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT, }; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 49b35bfccc1..aa4d9696527 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -100,6 +100,8 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode) bool BKE_object_data_is_in_editmode(const struct ID *id); +void BKE_object_update_select_id(struct Main *bmain); + typedef enum eObjectVisibilityResult { OB_VISIBLE_SELF = 1, OB_VISIBLE_PARTICLES = 2, @@ -394,6 +396,15 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob, bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob, const struct RegionView3D *rv3d); +/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though). + * The result is owned by the object. + * + * The mesh will be freed when object is re-evaluated or is destroyed. It is possible to force to + * clear memory sued by this mesh by calling BKE_object_to_mesh_clear(). */ +struct Mesh *BKE_object_to_mesh(struct Object *object); + +void BKE_object_to_mesh_clear(struct Object *object); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index f59288f54bd..315c0224b11 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -34,6 +34,7 @@ struct CCGKey; struct CustomData; struct DMFlagMat; struct GPUBatch; +struct GPU_PBVH_Buffers; struct MLoop; struct MLoopTri; struct MPoly; @@ -48,6 +49,21 @@ typedef struct { float (*co)[3]; } PBVHProxyNode; +typedef enum { + PBVH_Leaf = 1, + + PBVH_UpdateNormals = 2, + PBVH_UpdateBB = 4, + PBVH_UpdateOriginalBB = 8, + PBVH_UpdateDrawBuffers = 16, + PBVH_UpdateRedraw = 32, + + PBVH_RebuildDrawBuffers = 64, + PBVH_FullyHidden = 128, + + PBVH_UpdateTopology = 256, +} PBVHNodeFlags; + /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ @@ -151,13 +167,15 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh, void BKE_pbvh_draw_cb(PBVH *bvh, float (*planes)[4], float (*fnors)[3], - bool fast, - bool wires, - bool only_mask, bool show_vcol, - void (*draw_fn)(void *user_data, struct GPUBatch *batch), + void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), void *user_data); +void BKE_pbvh_draw_debug_cb( + PBVH *bvh, + void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), + void *user_data); + /* PBVH Access */ typedef enum { PBVH_FACES, @@ -202,21 +220,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, /* Node Access */ -typedef enum { - PBVH_Leaf = 1, - - PBVH_UpdateNormals = 2, - PBVH_UpdateBB = 4, - PBVH_UpdateOriginalBB = 8, - PBVH_UpdateDrawBuffers = 16, - PBVH_UpdateRedraw = 32, - - PBVH_RebuildDrawBuffers = 64, - PBVH_FullyHidden = 128, - - PBVH_UpdateTopology = 256, -} PBVHNodeFlags; - void BKE_pbvh_node_mark_update(PBVHNode *node); void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); void BKE_pbvh_node_mark_redraw(PBVHNode *node); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 75ff5eace3c..581df648add 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -240,6 +240,11 @@ void BKE_scene_cursor_quat_to_rot(struct View3DCursor *cursor, const float quat[4], bool use_compat); +void BKE_scene_cursor_to_mat4(const struct View3DCursor *cursor, float mat[4][4]); +void BKE_scene_cursor_from_mat4(struct View3DCursor *cursor, + const float mat[4][4], + bool use_compat); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 93c9c41e482..dcf6d6c3907 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -84,6 +84,9 @@ typedef struct SpaceType { struct wmNotifier *wmn, struct Scene *scene); + /* called when the mouse moves out of the area */ + void (*deactivate)(struct ScrArea *sa); + /* refresh context, called after filereads, ED_area_tag_refresh() */ void (*refresh)(const struct bContext *C, struct ScrArea *sa); @@ -205,6 +208,7 @@ typedef struct PanelType { short region_type; /* For popovers, 0 for default. */ int ui_units_x; + int order; int flag; diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 017c15ebe41..170ab657388 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -100,8 +100,8 @@ typedef struct SeqRenderData { /* special case for OpenGL render */ struct GPUOffScreen *gpu_offscreen; - int gpu_samples; - bool gpu_full_samples; + // int gpu_samples; + // bool gpu_full_samples; } SeqRenderData; void BKE_sequencer_new_render_data(struct Main *bmain, diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h index 0a4ad4cd994..133cf2d6cf5 100644 --- a/source/blender/blenkernel/BKE_workspace.h +++ b/source/blender/blenkernel/BKE_workspace.h @@ -110,6 +110,8 @@ void BKE_workspace_hook_layout_for_workspace_set(struct WorkSpaceInstanceHook *h bool BKE_workspace_owner_id_check(const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL(); +void BKE_workspace_id_tag_all_visible(struct Main *bmain, int tag) ATTR_NONNULL(); + #undef GETTER_ATTRS #undef SETTER_ATTRS diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h index 72817217a0a..3212bad75cb 100644 --- a/source/blender/blenkernel/BKE_writeavi.h +++ b/source/blender/blenkernel/BKE_writeavi.h @@ -53,9 +53,6 @@ typedef struct bMovieHandle { const char *suffix, struct ReportList *reports); void (*end_movie)(void *context_v); - int (*get_next_frame)(void *context_v, - struct RenderData *rd, - struct ReportList *reports); /* optional */ void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 9b321ff4e44..65b837048cb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -822,7 +822,6 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) if (pchan->prop) { IDP_FreeProperty(pchan->prop); - MEM_freeN(pchan->prop); } /* Cached data, for new draw manager rendering code. */ @@ -964,7 +963,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f if (pchan->prop) { /* unlikely but possible it exists */ IDP_FreeProperty(pchan->prop); - MEM_freeN(pchan->prop); pchan->prop = NULL; } if (pchan_from->prop) { @@ -978,6 +976,7 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f } pchan->custom_scale = pchan_from->custom_scale; + pchan->drawflag = pchan_from->drawflag; } /* checks for IK constraint, Spline IK, and also for Follow-Path constraint. diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index 486da61fe68..99ef38722f5 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -81,7 +81,6 @@ void BKE_addon_free(bAddon *addon) { if (addon->prop) { IDP_FreeProperty(addon->prop); - MEM_freeN(addon->prop); } MEM_freeN(addon); } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index cc5cd3b03ae..4a939180fb0 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1893,6 +1893,10 @@ static void animsys_evaluate_fcurves(Depsgraph *depsgraph, if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { continue; } + /* Skip empty curves, as if muted. */ + if (BKE_fcurve_is_empty(fcu)) { + continue; + } PathResolvedRNA anim_rna; if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); @@ -2005,7 +2009,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* calculate then execute each curve */ for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) { /* check if this curve should be skipped */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { PathResolvedRNA anim_rna; if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); @@ -3101,6 +3105,9 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) { continue; } + if (BKE_fcurve_is_empty(fcu)) { + continue; + } /* evaluate the F-Curve's value for the time given in the strip * NOTE: we use the modified time here, since strip's F-Curve Modifiers @@ -3327,6 +3334,9 @@ static void nla_eval_domain_action(PointerRNA *ptr, if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) { continue; } + if (BKE_fcurve_is_empty(fcu)) { + continue; + } NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path); @@ -3608,9 +3618,9 @@ static void animsys_calculate_nla(Depsgraph *depsgraph, * Prepare data necessary to compute correct keyframe values for NLA strips * with non-Replace mode or influence different from 1. * - * \param cache List used to cache contexts for reuse when keying + * \param cache: List used to cache contexts for reuse when keying * multiple channels in one operation. - * \param ptr RNA pointer to the Object with the animation. + * \param ptr: RNA pointer to the Object with the animation. * \return Keyframing context, or NULL if not necessary. */ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *cache, @@ -3652,12 +3662,12 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *ca /** * Apply correction from the NLA context to the values about to be keyframed. * - * \param context Context to use (may be NULL). - * \param prop_ptr Property about to be keyframed. - * \param[in,out] values Array of property values to adjust. - * \param count Number of values in the array. - * \param index Index of the element about to be updated, or -1. - * \param[out] r_force_all Set to true if all channels must be inserted. May be NULL. + * \param context: Context to use (may be NULL). + * \param prop_ptr: Property about to be keyframed. + * \param[in,out] values: Array of property values to adjust. + * \param count: Number of values in the array. + * \param index: Index of the element about to be updated, or -1. + * \param[out] r_force_all: Set to true if all channels must be inserted. May be NULL. * \return False if correction fails due to a division by zero, * or null r_force_all when all channels are required. */ diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 2b4123c74e2..14a20689db0 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -30,6 +30,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utf8.h" #include "BKE_blender_version.h" #include "BKE_appdir.h" /* own include */ @@ -838,6 +839,26 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz return false; } +bool BKE_appdir_app_template_has_userpref(const char *app_template) +{ + /* Test if app template provides a userpref.blend. + * If not, we will share user preferences with the rest of Blender. */ + if (!app_template && app_template[0]) { + return false; + } + + char app_template_path[FILE_MAX]; + if (!BKE_appdir_app_template_id_search( + app_template, app_template_path, sizeof(app_template_path))) { + return false; + } + + char userpref_path[FILE_MAX]; + BLI_path_join( + userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL); + return BLI_exists(userpref_path); +} + void BKE_appdir_app_templates(ListBase *templates) { BLI_listbase_clear(templates); @@ -1004,3 +1025,17 @@ void BKE_tempdir_session_purge(void) BLI_delete(btempdir_session, true, true); } } + +/* Gets a good default directory for fonts */ +bool BKE_appdir_font_folder_default(char *dir) +{ + bool success = false; +#ifdef WIN32 + wchar_t wpath[FILE_MAXDIR]; + success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0); + BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR); +#endif + /* TODO: Values for other platforms. */ + UNUSED_VARS(dir); + return success; +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 60446bf60b6..df22aa1dcfb 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -112,7 +112,6 @@ void BKE_armature_bonelist_free(ListBase *lb) for (bone = lb->first; bone; bone = bone->next) { if (bone->prop) { IDP_FreeProperty(bone->prop); - MEM_freeN(bone->prop); } BKE_armature_bonelist_free(&bone->childbase); } @@ -125,6 +124,7 @@ void BKE_armature_free(bArmature *arm) { BKE_animdata_free(&arm->id, false); + BKE_armature_bone_hash_free(arm); BKE_armature_bonelist_free(&arm->bonebase); /* free editmode data */ @@ -169,25 +169,20 @@ static void copy_bonechildren(Bone *bone_dst, } } -static void copy_bonechildren_custom_handles(Bone *bone_dst, bArmature *arm_dst, GHash **bone_hash) +static void copy_bonechildren_custom_handles(Bone *bone_dst, bArmature *arm_dst) { Bone *bone_dst_child; - /* Lazily create the name -> bone hashtable. */ - if ((bone_dst->bbone_prev || bone_dst->bbone_next) && *bone_hash == NULL) { - *bone_hash = BKE_armature_bone_from_name_map(arm_dst); - } - if (bone_dst->bbone_prev) { - bone_dst->bbone_prev = BLI_ghash_lookup(*bone_hash, bone_dst->bbone_prev->name); + bone_dst->bbone_prev = BKE_armature_find_bone_name(arm_dst, bone_dst->bbone_prev->name); } if (bone_dst->bbone_next) { - bone_dst->bbone_next = BLI_ghash_lookup(*bone_hash, bone_dst->bbone_next->name); + bone_dst->bbone_next = BKE_armature_find_bone_name(arm_dst, bone_dst->bbone_next->name); } for (bone_dst_child = bone_dst->childbase.first; bone_dst_child; bone_dst_child = bone_dst_child->next) { - copy_bonechildren_custom_handles(bone_dst_child, arm_dst, bone_hash); + copy_bonechildren_custom_handles(bone_dst_child, arm_dst); } } @@ -212,6 +207,8 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), /* We never handle usercount here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; + arm_dst->bonehash = NULL; + BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase); /* Duplicate the childrens' lists */ @@ -224,15 +221,11 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), arm_dst->act_bone = bone_dst_act; - /* Fix custom handle references. */ - GHash *bone_hash = NULL; /* lazily created */ + BKE_armature_bone_hash_make(arm_dst); + /* Fix custom handle references. */ for (bone_dst = arm_dst->bonebase.first; bone_dst; bone_dst = bone_dst->next) { - copy_bonechildren_custom_handles(bone_dst, arm_dst, &bone_hash); - } - - if (bone_hash) { - BLI_ghash_free(bone_hash, NULL, NULL); + copy_bonechildren_custom_handles(bone_dst, arm_dst); } arm_dst->edbo = NULL; @@ -274,6 +267,10 @@ Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name) return NULL; } + if (arm->bonehash) { + return BLI_ghash_lookup(arm->bonehash, name); + } + return get_named_bone_bonechildren(&arm->bonebase, name); } @@ -291,7 +288,7 @@ static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase * \note typically #bPose.chanhash us used via #BKE_pose_channel_find_name * this is for the cases we can't use pose channels. */ -GHash *BKE_armature_bone_from_name_map(bArmature *arm) +static GHash *armature_bone_from_name_map(bArmature *arm) { const int bones_count = BKE_armature_bonelist_count(&arm->bonebase); GHash *bone_hash = BLI_ghash_str_new_ex(__func__, bones_count); @@ -299,6 +296,21 @@ GHash *BKE_armature_bone_from_name_map(bArmature *arm) return bone_hash; } +void BKE_armature_bone_hash_make(bArmature *arm) +{ + if (!arm->bonehash) { + arm->bonehash = armature_bone_from_name_map(arm); + } +} + +void BKE_armature_bone_hash_free(bArmature *arm) +{ + if (arm->bonehash) { + BLI_ghash_free(arm->bonehash, NULL, NULL); + arm->bonehash = NULL; + } +} + bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag) { if (bone->flag & flag) { @@ -2417,7 +2429,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected } if (prop_orig) { IDP_FreeProperty(prop_orig); - MEM_freeN(prop_orig); } } } @@ -2458,11 +2469,9 @@ void BKE_pose_clear_pointers(bPose *pose) void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose) { - GHash *bone_hash = BKE_armature_bone_from_name_map(armature); for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name); + pchan->bone = BKE_armature_find_bone_name(armature, pchan->name); } - BLI_ghash_free(bone_hash, NULL, NULL); } /** Find the matching pose channel using the bone name, if not NULL. */ diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index c71c2dc86cf..bf7d81e5d63 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -273,11 +273,12 @@ static void splineik_evaluate_bone( /* first, adjust the point positions on the curve */ float curveLen = tree->points[index] - tree->points[index + 1]; float pointStart = state->curve_position; + float poseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length; float baseScale = 1.0f; if (ikData->yScaleMode == CONSTRAINT_SPLINEIK_YS_ORIGINAL) { /* Carry over the bone Y scale to the curve range. */ - baseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length; + baseScale = poseScale; } float pointEnd = pointStart + curveLen * baseScale * state->curve_scale; @@ -339,8 +340,8 @@ static void splineik_evaluate_bone( sub_v3_v3v3(splineVec, poseTail, poseHead); scaleFac = len_v3(splineVec) / pchan->bone->length; - /* Adjust the scale factor towards the neutral state when rolling off the curve end. */ - scaleFac = interpf(scaleFac, baseScale, tailBlendFac); + /* Extrapolate the full length of the bone as it rolls off the end of the curve. */ + scaleFac = (tailBlendFac < 1e-5f) ? baseScale : scaleFac / tailBlendFac; /* Step 3: compute the shortest rotation needed * to map from the bone rotation to the current axis. @@ -394,24 +395,31 @@ static void splineik_evaluate_bone( } /* step 4: set the scaling factors for the axes */ - { - /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ - mul_v3_fl(poseMat[1], scaleFac); - /* set the scaling factors of the x and z axes from... */ - switch (ikData->xzScaleMode) { - case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: { - /* original scales get used */ - float scale; + /* Always multiply the y-axis by the scaling factor to get the correct length. */ + mul_v3_fl(poseMat[1], scaleFac); + + /* After that, apply x/z scaling modes. */ + if (ikData->xzScaleMode != CONSTRAINT_SPLINEIK_XZS_NONE) { + /* First, apply the original scale if enabled. */ + if (ikData->xzScaleMode == CONSTRAINT_SPLINEIK_XZS_ORIGINAL || + (ikData->flag & CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE) != 0) { + float scale; + + /* x-axis scale */ + scale = len_v3(pchan->pose_mat[0]); + mul_v3_fl(poseMat[0], scale); + /* z-axis scale */ + scale = len_v3(pchan->pose_mat[2]); + mul_v3_fl(poseMat[2], scale); + + /* Adjust the scale factor used for volume preservation + * to consider the pre-IK scaling as the initial volume. */ + scaleFac /= poseScale; + } - /* x-axis scale */ - scale = len_v3(pchan->pose_mat[0]); - mul_v3_fl(poseMat[0], scale); - /* z-axis scale */ - scale = len_v3(pchan->pose_mat[2]); - mul_v3_fl(poseMat[2], scale); - break; - } + /* Apply volume preservation. */ + switch (ikData->xzScaleMode) { case CONSTRAINT_SPLINEIK_XZS_INVERSE: { /* old 'volume preservation' method using the inverse scale */ float scale; @@ -483,14 +491,14 @@ static void splineik_evaluate_bone( break; } } + } - /* finally, multiply the x and z scaling by the radius of the curve too, - * to allow automatic scales to get tweaked still - */ - if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { - mul_v3_fl(poseMat[0], radius); - mul_v3_fl(poseMat[2], radius); - } + /* Finally, multiply the x and z scaling by the radius of the curve too, + * to allow automatic scales to get tweaked still. + */ + if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { + mul_v3_fl(poseMat[0], radius); + mul_v3_fl(poseMat[2], radius); } /* Blend the scaling of the matrix according to the influence. */ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 48b271cf277..9fd3c24092c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -155,7 +155,6 @@ static void keymap_item_free(wmKeyMapItem *kmi) { if (kmi->properties) { IDP_FreeProperty(kmi->properties); - MEM_freeN(kmi->properties); } if (kmi->ptr) { MEM_freeN(kmi->ptr); @@ -212,7 +211,6 @@ static void userdef_free_keyconfig_prefs(UserDef *userdef) kpt = kpt_next) { kpt_next = kpt->next; IDP_FreeProperty(kpt->prop); - MEM_freeN(kpt->prop); MEM_freeN(kpt); } BLI_listbase_clear(&userdef->user_keyconfig_prefs); diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c index 911f3fdc7b2..ad34ef03e04 100644 --- a/source/blender/blenkernel/intern/blender_user_menu.c +++ b/source/blender/blenkernel/intern/blender_user_menu.c @@ -97,7 +97,6 @@ void BKE_blender_user_menu_item_free(bUserMenuItem *umi) bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi; if (umi_op->prop) { IDP_FreeProperty(umi_op->prop); - MEM_freeN(umi_op->prop); } } MEM_freeN(umi); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index d1a3045a829..570c1b9bd4c 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -98,6 +98,25 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene) return false; } +static void setup_app_userdef(BlendFileData *bfd) +{ + if (bfd->user) { + /* only here free userdef themes... */ + BKE_blender_userdef_data_set_and_free(bfd->user); + bfd->user = NULL; + + /* Security issue: any blend file could include a USER block. + * + * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE, + * to load the preferences defined in the users home dir. + * + * This means we will never accidentally (or maliciously) + * enable scripts auto-execution by loading a '.blend' file. + */ + U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; + } +} + /** * Context matching, handle no-ui case * @@ -235,26 +254,10 @@ static void setup_app_data(bContext *C, RNA_property_update_cache_free(); bmain = G_MAIN = bfd->main; + bfd->main = NULL; CTX_data_main_set(C, bmain); - if (bfd->user) { - - /* only here free userdef themes... */ - BKE_blender_userdef_data_set_and_free(bfd->user); - bfd->user = NULL; - - /* Security issue: any blend file could include a USER block. - * - * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE, - * to load the preferences defined in the users home dir. - * - * This means we will never accidentally (or maliciously) - * enable scripts auto-execution by loading a '.blend' file. - */ - U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE; - } - /* case G_FILE_NO_UI or no screens in file */ if (mode != LOAD_UI) { /* leave entire context further unaltered? */ @@ -356,8 +359,20 @@ static void setup_app_data(bContext *C, /* TODO(sergey): Can this be also move above? */ RE_FreeAllPersistentData(); } +} - MEM_freeN(bfd); +static void setup_app_blend_file_data(bContext *C, + BlendFileData *bfd, + const char *filepath, + const struct BlendFileReadParams *params, + ReportList *reports) +{ + if ((params->skip_flags & BLO_READ_SKIP_USERDEF) == 0) { + setup_app_userdef(bfd); + } + if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { + setup_app_data(C, bfd, filepath, params->is_startup, reports); + } } static int handle_subversion_warning(Main *main, ReportList *reports) @@ -400,7 +415,8 @@ int BKE_blendfile_read(bContext *C, retval = BKE_BLENDFILE_READ_FAIL; } else { - setup_app_data(C, bfd, filepath, params->is_startup, reports); + setup_app_blend_file_data(C, bfd, filepath, params, reports); + BLO_blendfiledata_free(bfd); } } else { @@ -422,9 +438,13 @@ bool BKE_blendfile_read_from_memory(bContext *C, bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports); if (bfd) { if (update_defaults) { - BLO_update_defaults_startup_blend(bfd->main, NULL); + if ((params->skip_flags & BLO_READ_SKIP_DATA) == 0) { + BLO_update_defaults_startup_blend(bfd->main, NULL); + } } - setup_app_data(C, bfd, "<memory2>", params->is_startup, reports); + + setup_app_blend_file_data(C, bfd, "<memory2>", params, reports); + BLO_blendfiledata_free(bfd); } else { BKE_reports_prepend(reports, "Loading failed: "); @@ -453,7 +473,8 @@ bool BKE_blendfile_read_from_memfile(bContext *C, BKE_id_free(bfd->main, bfd->main->screens.first); } - setup_app_data(C, bfd, "<memory1>", params->is_startup, reports); + setup_app_blend_file_data(C, bfd, "<memory1>", params, reports); + BLO_blendfiledata_free(bfd); } else { BKE_reports_prepend(reports, "Loading failed: "); @@ -566,6 +587,63 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList * return ok; } +bool BKE_blendfile_userdef_write_all(ReportList *reports) +{ + char filepath[FILE_MAX]; + const char *cfgdir; + bool ok = true; + const bool use_template_userpref = BKE_appdir_app_template_has_userpref(U.app_template); + + if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) { + bool ok_write; + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + + printf("Writing userprefs: '%s' ", filepath); + if (use_template_userpref) { + ok_write = BKE_blendfile_userdef_write_app_template(filepath, reports); + } + else { + ok_write = BKE_blendfile_userdef_write(filepath, reports); + } + + if (ok_write) { + printf("ok\n"); + } + else { + printf("fail\n"); + ok = false; + } + } + else { + BKE_report(reports, RPT_ERROR, "Unable to create userpref path"); + } + + if (use_template_userpref) { + if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) { + /* Also save app-template prefs */ + BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + + printf("Writing userprefs app-template: '%s' ", filepath); + if (BKE_blendfile_userdef_write(filepath, reports) != 0) { + printf("ok\n"); + } + else { + printf("fail\n"); + ok = false; + } + } + else { + BKE_report(reports, RPT_ERROR, "Unable to create app-template userpref path"); + ok = false; + } + } + + if (ok) { + U.runtime.is_dirty = false; + } + return ok; +} + WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 6f0c1891b05..fa7af53df2d 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -450,7 +450,10 @@ void BKE_bpath_traverse_id( Image *ima; ima = (Image *)id; if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { - if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + /* Skip empty file paths, these are typically from generated images and + * don't make sense to add directories to until the image has been saved + * once to give it a meaningful value. */ + if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) && ima->name[0]) { if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) { if (!BKE_image_has_packedfile(ima) && diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index e28f1fc566f..78d965564e6 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -501,9 +501,46 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->gradient_s[0] = 1.0f; brush->gpencil_settings->gradient_s[1] = 1.0f; + /* Soft brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Soft"); + deft = brush; /* save default brush */ + brush->size = 300.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 0.4f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = 0.98f; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + brush->gpencil_settings->gradient_f = 0.211f; + brush->gpencil_settings->gradient_s[0] = 1.0f; + brush->gpencil_settings->gradient_s[1] = 0.91f; + /* Fill brush */ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); - brush->size = 1.0f; + brush->size = 20.0f; brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; brush->gpencil_settings->draw_sensitivity = 1.0f; brush->gpencil_settings->fill_leak = 3; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 25399d342e1..a8f38c3c4ce 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -66,8 +66,9 @@ void BKE_camera_init(Camera *cam) cam->flag |= CAM_SHOWPASSEPARTOUT; cam->passepartalpha = 0.5f; - cam->gpu_dof.fstop = 128.0f; - cam->gpu_dof.ratio = 1.0f; + cam->dof.aperture_fstop = 2.8f; + cam->dof.aperture_ratio = 1.0f; + cam->dof.focus_distance = 10.0f; /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; @@ -134,13 +135,13 @@ float BKE_camera_object_dof_distance(Object *ob) if (ob->type != OB_CAMERA) { return 0.0f; } - if (cam->dof_ob) { + if (cam->dof.focus_object) { float view_dir[3], dof_dir[3]; normalize_v3_v3(view_dir, ob->obmat[2]); - sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]); + sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]); return fabsf(dot_v3v3(view_dir, dof_dir)); } - return cam->dof_distance; + return cam->dof.focus_distance; } float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y) @@ -1016,18 +1017,6 @@ void BKE_camera_multiview_params(RenderData *rd, } } -void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings) -{ - if (camera->type == OB_CAMERA) { - Camera *cam = camera->data; - r_fx_settings->dof = &cam->gpu_dof; - r_fx_settings->dof->focal_length = cam->lens; - r_fx_settings->dof->sensor = BKE_camera_sensor_size( - cam->sensor_fit, cam->sensor_x, cam->sensor_y); - r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera); - } -} - CameraBGImage *BKE_camera_background_image_new(Camera *cam) { CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image"); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index d33d4e344b5..d2ca304e973 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -321,11 +321,11 @@ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *col * \warning If any 'deep copy' behavior is enabled, * this functions will clear all \a bmain id.idnew pointers. * - * \param do_hierarchy If true, it will recursively make shallow copies of children collections. - * \param do_objects If true, it will also make duplicates of objects. - * This one does nothing if \a do_hierarchy is not set. - * \param do_obdata If true, it will also make deep duplicates of objects, - * using behavior defined in user settings (U.dupflag). + * \param do_hierarchy: If true, it will recursively make shallow copies of children collections. + * \param do_objects: If true, it will also make duplicates of objects. + * This one does nothing if \a do_hierarchy is not set. + * \param do_obdata: If true, it will also make deep duplicates of objects, + * using behavior defined in user settings (#U.dupflag). * This one does nothing if \a do_hierarchy and \a do_objects are not set. */ Collection *BKE_collection_duplicate(Main *bmain, @@ -434,8 +434,8 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i int object_restrict = base->object->restrictflag; - if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && - ((object_restrict & OB_RESTRICT_VIEW) == 0)) { + if (((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) && + ((object_restrict & OB_RESTRICT_VIEWPORT) == 0)) { base->flag |= BASE_ENABLED_VIEWPORT; } @@ -705,18 +705,27 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) } /** - * Add object to all scene collections that reference objects is in - * (used to copy objects) + * Add object to all scene collections that reference object is in + * (used to copy objects). */ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst) { + bool is_instantiated = false; + FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { - if (BKE_collection_has_object(collection, ob_src)) { + if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, ob_src)) { collection_object_add(bmain, collection, ob_dst, 0, true); + is_instantiated = true; } } FOREACH_SCENE_COLLECTION_END; + if (!is_instantiated) { + /* In case we could not find any non-linked collections in which instantiate our ob_dst, + * fallback to scene's master collection... */ + collection_object_add(bmain, BKE_collection_master(scene), ob_dst, 0, true); + } + BKE_main_collection_sync(bmain); } @@ -966,6 +975,11 @@ static bool collection_find_child_recursive(Collection *parent, Collection *coll return false; } +bool BKE_collection_has_collection(Collection *parent, Collection *collection) +{ + return collection_find_child_recursive(parent, collection); +} + static CollectionParent *collection_find_parent(Collection *child, Collection *collection) { return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection)); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 0e29f165992..04789adea2f 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1882,6 +1882,7 @@ static void sizelike_new_data(void *cdata) bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata; data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY; + data->power = 1.0f; } static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -1929,6 +1930,10 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta mat4_to_size(size, ct->matrix); mat4_to_size(obsize, cob->matrix); + for (int i = 0; i < 3; i++) { + size[i] = powf(size[i], data->power); + } + if (data->flag & SIZELIKE_OFFSET) { /* Scale is a multiplicative quantity, so adding it makes no sense. * However, the additive mode has to stay for backward compatibility. */ @@ -2037,7 +2042,7 @@ static void samevolume_new_data(void *cdata) { bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata; - data->flag = SAMEVOL_Y; + data->free_axis = SAMEVOL_Y; data->volume = 1.0f; } @@ -2046,19 +2051,30 @@ static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * bSameVolumeConstraint *data = con->data; float volume = data->volume; - float fac = 1.0f, total_scale; + float fac = 1.0f, total_scale = 1.0f; float obsize[3]; mat4_to_size(obsize, cob->matrix); /* calculate normalizing scale factor for non-essential values */ - total_scale = obsize[0] * obsize[1] * obsize[2]; + switch (data->mode) { + case SAMEVOL_STRICT: + total_scale = obsize[0] * obsize[1] * obsize[2]; + break; + case SAMEVOL_UNIFORM: + total_scale = pow3f(obsize[data->free_axis]); + break; + case SAMEVOL_SINGLE_AXIS: + total_scale = obsize[data->free_axis]; + break; + } + if (total_scale != 0) { fac = sqrtf(volume / total_scale); } /* apply scaling factor to the channels not being kept */ - switch (data->flag) { + switch (data->free_axis) { case SAMEVOL_X: mul_v3_fl(cob->matrix[1], fac); mul_v3_fl(cob->matrix[2], fac); @@ -2097,7 +2113,6 @@ static void pycon_free(bConstraint *con) /* id-properties */ IDP_FreeProperty(data->prop); - MEM_freeN(data->prop); /* multiple targets */ BLI_freelistN(&data->targets); @@ -2406,7 +2421,8 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ copy_v3_v3(input_co, cob->matrix[3]); } - /* Process all targets. */ + /* Process all targets. This can't use ct->matrix, as armdef_get_tarmat is not + * called in solve for efficiency because the constraint needs bone data anyway. */ for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) { if (ct->weight <= 0.0f) { continue; @@ -4224,6 +4240,7 @@ static void splineik_new_data(void *cdata) data->bulge_min = 1.0f; data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; + data->flag = CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE; } static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -5600,6 +5617,11 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, */ cti->get_constraint_targets(con, targets); + /* The Armature constraint doesn't need ct->matrix for evaluate at all. */ + if (ELEM(cti->type, CONSTRAINT_TYPE_ARMATURE)) { + return; + } + /* set matrices * - calculate if possible, otherwise just initialize as identity matrix */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4383b6a1f9b..9d753319cfa 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -399,6 +399,41 @@ static int ctx_data_collection_get(const bContext *C, const char *member, ListBa return 0; } +static int ctx_data_base_collection_get(const bContext *C, const char *member, ListBase *list) +{ + ListBase ctx_object_list; + bool ok = false; + + if (!ctx_data_collection_get(C, member, &ctx_object_list)) { + return 0; + } + + if (BLI_listbase_is_empty(&ctx_object_list)) { + return 0; + } + + bContextDataResult result; + memset(&result, 0, sizeof(bContextDataResult)); + + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + CollectionPointerLink *ctx_object; + for (ctx_object = ctx_object_list.first; ctx_object; ctx_object = ctx_object->next) { + Object *ob = ctx_object->ptr.data; + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base != NULL) { + CTX_data_list_add(&result, &scene->id, &RNA_ObjectBase, base); + ok = true; + } + } + CTX_data_type_set(&result, CTX_DATA_TYPE_COLLECTION); + BLI_freelistN(&ctx_object_list); + + *list = result.list; + return ok; +} + PointerRNA CTX_data_pointer_get(const bContext *C, const char *member) { bContextDataResult result; @@ -1150,7 +1185,7 @@ int CTX_data_selected_editable_objects(const bContext *C, ListBase *list) int CTX_data_selected_editable_bases(const bContext *C, ListBase *list) { - return ctx_data_collection_get(C, "selected_editable_bases", list); + return ctx_data_base_collection_get(C, "selected_editable_objects", list); } int CTX_data_editable_objects(const bContext *C, ListBase *list) @@ -1160,7 +1195,7 @@ int CTX_data_editable_objects(const bContext *C, ListBase *list) int CTX_data_editable_bases(const bContext *C, ListBase *list) { - return ctx_data_collection_get(C, "editable_bases", list); + return ctx_data_base_collection_get(C, "editable_objects", list); } int CTX_data_selected_objects(const bContext *C, ListBase *list) @@ -1170,7 +1205,7 @@ int CTX_data_selected_objects(const bContext *C, ListBase *list) int CTX_data_selected_bases(const bContext *C, ListBase *list) { - return ctx_data_collection_get(C, "selected_bases", list); + return ctx_data_base_collection_get(C, "selected_objects", list); } int CTX_data_visible_objects(const bContext *C, ListBase *list) @@ -1180,7 +1215,7 @@ int CTX_data_visible_objects(const bContext *C, ListBase *list) int CTX_data_visible_bases(const bContext *C, ListBase *list) { - return ctx_data_collection_get(C, "visible_bases", list); + return ctx_data_base_collection_get(C, "visible_objects", list); } int CTX_data_selectable_objects(const bContext *C, ListBase *list) @@ -1190,7 +1225,7 @@ int CTX_data_selectable_objects(const bContext *C, ListBase *list) int CTX_data_selectable_bases(const bContext *C, ListBase *list) { - return ctx_data_collection_get(C, "selectable_bases", list); + return ctx_data_base_collection_get(C, "selectable_objects", list); } struct Object *CTX_data_active_object(const bContext *C) @@ -1200,7 +1235,14 @@ struct Object *CTX_data_active_object(const bContext *C) struct Base *CTX_data_active_base(const bContext *C) { - return ctx_data_pointer_get(C, "active_base"); + Object *ob = ctx_data_pointer_get(C, "active_object"); + + if (ob == NULL) { + return NULL; + } + + ViewLayer *view_layer = CTX_data_view_layer(C); + return BKE_view_layer_base_find(view_layer, ob); } struct Object *CTX_data_edit_object(const bContext *C) @@ -1312,7 +1354,21 @@ Depsgraph *CTX_data_depsgraph(const bContext *C) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - return BKE_scene_get_depsgraph(scene, view_layer, true); + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + /* Dependency graph might have been just allocated, and hence it will not be marked. + * This confuses redo system due to the lack of flushing changes back to the original data. + * In the future we would need to check whether the CTX_wm_window(C) is in editing mode (as an + * opposite of playback-preview-only) and set active flag based on that. */ + DEG_make_active(depsgraph); + return depsgraph; +} + +Depsgraph *CTX_data_evaluated_depsgraph(const bContext *C) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); + BKE_scene_graph_update_tagged(depsgraph, bmain); + return depsgraph; } Depsgraph *CTX_data_depsgraph_on_load(const bContext *C) diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index dc677449a4c..5945fa4bf33 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1737,241 +1737,9 @@ static void forward_diff_bezier_cotangent(const float p0[3], } } -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -float *BKE_curve_surf_make_orco(Object *ob) -{ - /* Note: this function is used in convertblender only atm, so - * suppose nonzero curve's render resolution should always be used */ - Curve *cu = ob->data; - Nurb *nu; - int a, b, tot = 0; - int sizeu, sizev; - int resolu, resolv; - float *fp, *coord_array; - - /* first calculate the size of the datablock */ - nu = cu->nurb.first; - while (nu) { - /* as we want to avoid the seam in a cyclic nurbs - * texture wrapping, reserve extra orco data space to save these extra needed - * vertex based UV coordinates for the meridian vertices. - * Vertices on the 0/2pi boundary are not duplicated inside the displist but later in - * the renderface/vert construction. - * - * See also convertblender.c: init_render_surf() - */ - - resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; - resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; - - sizeu = nu->pntsu * resolu; - sizev = nu->pntsv * resolv; - if (nu->flagu & CU_NURB_CYCLIC) { - sizeu++; - } - if (nu->flagv & CU_NURB_CYCLIC) { - sizev++; - } - if (nu->pntsv > 1) { - tot += sizeu * sizev; - } - - nu = nu->next; - } - /* makeNurbfaces wants zeros */ - fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco"); - - nu = cu->nurb.first; - while (nu) { - resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu; - resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv; - - if (nu->pntsv > 1) { - sizeu = nu->pntsu * resolu; - sizev = nu->pntsv * resolv; - - if (nu->flagu & CU_NURB_CYCLIC) { - sizeu++; - } - if (nu->flagv & CU_NURB_CYCLIC) { - sizev++; - } - - if (cu->flag & CU_UV_ORCO) { - for (b = 0; b < sizeu; b++) { - for (a = 0; a < sizev; a++) { - - if (sizev < 2) { - fp[0] = 0.0f; - } - else { - fp[0] = -1.0f + 2.0f * ((float)a) / (sizev - 1); - } - - if (sizeu < 2) { - fp[1] = 0.0f; - } - else { - fp[1] = -1.0f + 2.0f * ((float)b) / (sizeu - 1); - } - - fp[2] = 0.0; - - fp += 3; - } - } - } - else { - int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float); - float *_tdata = MEM_mallocN(size, "temp data"); - float *tdata = _tdata; - - BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv); - - for (b = 0; b < sizeu; b++) { - int use_b = b; - if (b == sizeu - 1 && (nu->flagu & CU_NURB_CYCLIC)) { - use_b = false; - } - - for (a = 0; a < sizev; a++) { - int use_a = a; - if (a == sizev - 1 && (nu->flagv & CU_NURB_CYCLIC)) { - use_a = false; - } - - tdata = _tdata + 3 * (use_b * (nu->pntsv * resolv) + use_a); - - fp[0] = (tdata[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (tdata[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (tdata[2] - cu->loc[2]) / cu->size[2]; - fp += 3; - } - } - - MEM_freeN(_tdata); - } - } - nu = nu->next; - } - - return coord_array; -} - -/* NOTE: This routine is tied to the order of vertex - * built by displist and as passed to the renderer. - */ -float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts) -{ - Curve *cu = ob->data; - DispList *dl; - int u, v, numVerts; - float *fp, *coord_array; - ListBase disp = {NULL, NULL}; - - BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp, NULL); - - numVerts = 0; - for (dl = disp.first; dl; dl = dl->next) { - if (dl->type == DL_INDEX3) { - numVerts += dl->nr; - } - else if (dl->type == DL_SURF) { - /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only - * (closed circle beveling) - */ - if (dl->flag & DL_CYCL_U) { - if (dl->flag & DL_CYCL_V) { - numVerts += (dl->parts + 1) * (dl->nr + 1); - } - else { - numVerts += dl->parts * (dl->nr + 1); - } - } - else if (dl->flag & DL_CYCL_V) { - numVerts += (dl->parts + 1) * dl->nr; - } - else { - numVerts += dl->parts * dl->nr; - } - } - } - - if (r_numVerts) { - *r_numVerts = numVerts; - } - - fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco"); - for (dl = disp.first; dl; dl = dl->next) { - if (dl->type == DL_INDEX3) { - for (u = 0; u < dl->nr; u++, fp += 3) { - if (cu->flag & CU_UV_ORCO) { - fp[0] = 2.0f * u / (dl->nr - 1) - 1.0f; - fp[1] = 0.0; - fp[2] = 0.0; - } - else { - copy_v3_v3(fp, &dl->verts[u * 3]); - - fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; - } - } - } - else if (dl->type == DL_SURF) { - int sizeu = dl->nr, sizev = dl->parts; - - /* exception as handled in convertblender.c too */ - if (dl->flag & DL_CYCL_U) { - sizeu++; - if (dl->flag & DL_CYCL_V) { - sizev++; - } - } - else if (dl->flag & DL_CYCL_V) { - sizev++; - } - - for (u = 0; u < sizev; u++) { - for (v = 0; v < sizeu; v++, fp += 3) { - if (cu->flag & CU_UV_ORCO) { - fp[0] = 2.0f * u / (sizev - 1) - 1.0f; - fp[1] = 2.0f * v / (sizeu - 1) - 1.0f; - fp[2] = 0.0; - } - else { - const float *vert; - int realv = v % dl->nr; - int realu = u % dl->parts; - - vert = dl->verts + 3 * (dl->nr * realu + realv); - copy_v3_v3(fp, vert); - - fp[0] = (fp[0] - cu->loc[0]) / cu->size[0]; - fp[1] = (fp[1] - cu->loc[1]) / cu->size[1]; - fp[2] = (fp[2] - cu->loc[2]) / cu->size[2]; - } - } - } - } - } - - BKE_displist_free(&disp); - - return coord_array; -} - /* ***************** BEVEL ****************** */ -void BKE_curve_bevel_make(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - ListBase *disp, - const bool for_render, - const bool use_render_resolution, - LinkNode *ob_cyclic_list) +void BKE_curve_bevel_make(Object *ob, ListBase *disp) { DispList *dl, *dlnew; Curve *bevcu, *cu; @@ -1995,26 +1763,7 @@ void BKE_curve_bevel_make(Depsgraph *depsgraph, facx = cu->bevobj->scale[0]; facy = cu->bevobj->scale[1]; - if (for_render) { - if (BLI_linklist_index(ob_cyclic_list, cu->bevobj) == -1) { - BKE_displist_make_curveTypes_forRender(depsgraph, - scene, - cu->bevobj, - &bevdisp, - NULL, - false, - use_render_resolution, - &(LinkNode){ - .link = ob, - .next = ob_cyclic_list, - }); - dl = bevdisp.first; - } - else { - dl = NULL; - } - } - else if (cu->bevobj->runtime.curve_cache) { + if (cu->bevobj->runtime.curve_cache) { dl = cu->bevobj->runtime.curve_cache->disp.first; } else { @@ -4980,7 +4729,7 @@ void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key) } } -bool BKE_nurb_check_valid_u(struct Nurb *nu) +bool BKE_nurb_check_valid_u(const Nurb *nu) { if (nu->pntsu <= 1) { return false; @@ -5007,7 +4756,7 @@ bool BKE_nurb_check_valid_u(struct Nurb *nu) } return true; } -bool BKE_nurb_check_valid_v(struct Nurb *nu) +bool BKE_nurb_check_valid_v(const Nurb *nu) { if (nu->pntsv <= 1) { return false; @@ -5035,7 +4784,7 @@ bool BKE_nurb_check_valid_v(struct Nurb *nu) return true; } -bool BKE_nurb_check_valid_uv(struct Nurb *nu) +bool BKE_nurb_check_valid_uv(const Nurb *nu) { if (!BKE_nurb_check_valid_u(nu)) { return false; diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 5d9ba1bcdc7..98c6d519d17 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -585,7 +585,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map /* Find last source actually used! */ while (idx_src-- && !use_layers_src[idx_src]) { - ; + /* pass */ } idx_src++; diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index e83e9560b02..a964cab3fa5 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -1124,7 +1124,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* Find last source actually used! */ idx_src = num_layers_src; while (idx_src-- && !use_layers_src[idx_src]) { - ; + /* pass */ } idx_src++; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index c228595b6e8..c8d6f7ae313 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -315,8 +315,7 @@ bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, i static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase, - const bool for_render, - const bool use_render_resolution) + const bool for_render) { Nurb *nu; DispList *dl; @@ -329,7 +328,7 @@ static void curve_to_displist(Curve *cu, nu = nubase->first; while (nu) { if (nu->hide == 0 || editmode == false) { - if (use_render_resolution && cu->resolu_ren != 0) { + if (for_render && cu->resolu_ren != 0) { resolu = cu->resolu_ren; } else { @@ -724,7 +723,7 @@ static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *tap dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL; if (dl == NULL) { - BKE_displist_make_curveTypes(depsgraph, scene, taperobj, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, taperobj, false, false); dl = taperobj->runtime.curve_cache->disp.first; } if (dl) { @@ -801,7 +800,7 @@ void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, - const bool use_render_resolution, + const bool for_render, const bool editmode) { VirtualModifierData virtualModifierData; @@ -809,7 +808,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, ModifierData *pretessellatePoint; int required_mode; - if (use_render_resolution) { + if (for_render) { required_mode = eModifierMode_Render; } else { @@ -848,12 +847,8 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, return pretessellatePoint; } -static void curve_calc_modifiers_pre(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - ListBase *nurb, - const bool for_render, - const bool use_render_resolution) +static void curve_calc_modifiers_pre( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -871,7 +866,7 @@ static void curve_calc_modifiers_pre(Depsgraph *depsgraph, if (editmode) { app_flag |= MOD_APPLY_USECACHE; } - if (use_render_resolution) { + if (for_render) { app_flag |= MOD_APPLY_RENDER; required_mode = eModifierMode_Render; } @@ -881,7 +876,7 @@ static void curve_calc_modifiers_pre(Depsgraph *depsgraph, const ModifierEvalContext mectx = {depsgraph, ob, app_flag}; - pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); + pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode); if (editmode) { required_mode |= eModifierMode_Editmode; @@ -979,8 +974,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, ListBase *nurb, ListBase *dispbase, Mesh **r_final, - const bool for_render, - const bool use_render_resolution) + const bool for_render) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -993,7 +987,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, int useCache = !for_render; ModifierApplyFlag app_flag = 0; - if (use_render_resolution) { + if (for_render) { app_flag |= MOD_APPLY_RENDER; required_mode = eModifierMode_Render; } @@ -1006,7 +1000,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph, const ModifierEvalContext mectx_apply = { depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag}; - pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); + pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode); if (editmode) { required_mode |= eModifierMode_Editmode; @@ -1199,144 +1193,13 @@ static void displist_surf_indices(DispList *dl) } } -/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ -#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS -static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - DerivedMesh *dm; - ListBase disp = {NULL, NULL}; - - /* OrcoDM should be created from underformed disp lists */ - BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp); - dm = CDDM_from_curve_displist(ob, &disp); - - BKE_displist_free(&disp); - - return dm; -} - -static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm) -{ - float(*orco)[3], (*layerorco)[3]; - int totvert, a; - Curve *cu = ob->data; - - totvert = dm->getNumVerts(dm); - - orco = MEM_callocN(sizeof(float) * 3 * totvert, "dm orco"); - - if (orcodm->getNumVerts(orcodm) == totvert) { - orcodm->getVertCos(orcodm, orco); - } - else { - dm->getVertCos(dm, orco); - } - - for (a = 0; a < totvert; a++) { - float *co = orco[a]; - co[0] = (co[0] - cu->loc[0]) / cu->size[0]; - co[1] = (co[1] - cu->loc[1]) / cu->size[1]; - co[2] = (co[2] - cu->loc[2]) / cu->size[2]; - } - - if ((layerorco = DM_get_vert_data_layer(dm, CD_ORCO))) { - memcpy(layerorco, orco, sizeof(float) * totvert); - MEM_freeN(orco); - } - else { - DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco); - } -} -#endif - -/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ -#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS -static void curve_calc_orcodm(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - DerivedMesh *dm_final, - const bool for_render, - const bool use_render_resolution) -{ - /* this function represents logic of mesh's orcodm calculation - * for displist-based objects - */ - VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); - ModifierData *pretessellatePoint; - Curve *cu = ob->data; - int required_mode; - const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); - DerivedMesh *ndm, *orcodm = NULL; - ModifierApplyFlag app_flag = MOD_APPLY_ORCO; - - if (use_render_resolution) { - app_flag |= MOD_APPLY_RENDER; - required_mode = eModifierMode_Render; - } - else { - required_mode = eModifierMode_Realtime; - } - - const ModifierEvalContext mectx = {depsgraph, ob, app_flag}; - - pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); - - if (editmode) { - required_mode |= eModifierMode_Editmode; - } - - if (pretessellatePoint) { - md = pretessellatePoint->next; - } - - /* If modifiers are disabled, we wouldn't be here because - * this function is only called if there're enabled constructive - * modifiers applied on the curve. - * - * This means we can create ORCO DM in advance and assume it's - * never NULL. - */ - orcodm = create_orco_dm(depsgraph, scene, ob); - - for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - md->scene = scene; - - if (!modifier_isEnabled(scene, md, required_mode)) { - continue; - } - if (mti->type != eModifierTypeType_Constructive) { - continue; - } - - ndm = modwrap_applyModifier(md, &mectx, orcodm); - - if (ndm) { - /* if the modifier returned a new dm, release the old one */ - if (orcodm && orcodm != ndm) { - orcodm->release(orcodm); - } - orcodm = ndm; - } - } - - /* add an orco layer if needed */ - add_orco_dm(ob, dm_final, orcodm); - - orcodm->release(orcodm); -} -#endif - void BKE_displist_make_surf(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, Mesh **r_final, const bool for_render, - const bool for_orco, - const bool use_render_resolution) + const bool for_orco) { ListBase nubase = {NULL, NULL}; Nurb *nu; @@ -1353,14 +1216,14 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution); + curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } for (nu = nubase.first; nu; nu = nu->next) { if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) { int resolu = nu->resolu, resolv = nu->resolv; - if (use_render_resolution) { + if (for_render) { if (cu->resolu_ren) { resolu = cu->resolu_ren; } @@ -1431,8 +1294,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post( - depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution); + curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); } BKE_nurbList_free(&nubase); @@ -1665,8 +1527,6 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, ListBase *dispbase, const bool for_render, const bool for_orco, - const bool use_render_resolution, - LinkNode *ob_cyclic_list, Mesh **r_final) { Curve *cu = ob->data; @@ -1677,8 +1537,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } if (ob->type == OB_SURF) { - BKE_displist_make_surf( - depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution); + BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco); } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; @@ -1705,18 +1564,17 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } if (!for_orco) { - curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution); + curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render); } - BKE_curve_bevelList_make(ob, &nubase, use_render_resolution); + BKE_curve_bevelList_make(ob, &nubase, for_render); /* If curve has no bevel will return nothing */ - BKE_curve_bevel_make( - depsgraph, scene, ob, &dlbev, for_render, use_render_resolution, ob_cyclic_list); + BKE_curve_bevel_make(ob, &dlbev); /* no bevel or extrude, and no width correction? */ if (!dlbev.first && cu->width == 1.0f) { - curve_to_displist(cu, &nubase, dispbase, for_render, use_render_resolution); + curve_to_displist(cu, &nubase, dispbase, for_render); } else { float widfac = cu->width - 1.0f; @@ -1916,8 +1774,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, if (!for_orco) { BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post( - depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution); + curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render); } if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) { @@ -1928,12 +1785,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } } -void BKE_displist_make_curveTypes(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - const bool for_render, - const bool for_orco, - LinkNode *ob_cyclic_list) +void BKE_displist_make_curveTypes( + Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_render, const bool for_orco) { ListBase *dispbase; @@ -1952,15 +1805,8 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, dispbase = &(ob->runtime.curve_cache->disp); - do_makeDispListCurveTypes(depsgraph, - scene, - ob, - dispbase, - for_render, - for_orco, - false, - ob_cyclic_list, - &ob->runtime.mesh_eval); + do_makeDispListCurveTypes( + depsgraph, scene, ob, dispbase, for_render, for_orco, &ob->runtime.mesh_eval); boundbox_displist_object(ob); } @@ -1970,33 +1816,13 @@ void BKE_displist_make_curveTypes_forRender(Depsgraph *depsgraph, Object *ob, ListBase *dispbase, Mesh **r_final, - const bool for_orco, - const bool use_render_resolution, - LinkNode *ob_cyclic_list) -{ - if (ob->runtime.curve_cache == NULL) { - ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); - } - - do_makeDispListCurveTypes(depsgraph, - scene, - ob, - dispbase, - true, - for_orco, - use_render_resolution, - ob_cyclic_list, - r_final); -} - -void BKE_displist_make_curveTypes_forOrco( - Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, LinkNode *ob_cyclic_list) + const bool for_orco) { if (ob->runtime.curve_cache == NULL) { ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } - do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, 1, 1, 1, ob_cyclic_list, NULL); + do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, true, for_orco, r_final); } void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 0ee32af336d..b5242d00ee0 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2066,7 +2066,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * } if (update_normals) { - // result->dirty |= DM_DIRTY_NORMALS; + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; } } /* make a copy of mesh to use as brush data */ @@ -5393,7 +5393,7 @@ static void dynamic_paint_effect_drip_cb(void *__restrict userdata, const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) & epointlock_bitmask) { - ; + /* pass */ } PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt]; @@ -5440,7 +5440,7 @@ static void dynamic_paint_effect_drip_cb(void *__restrict userdata, const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */ while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) & ppointlock_bitmask) { - ; + /* pass */ } pPoint->wetness -= ppoint_wetness_diff; diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 130f4ae88f1..b8234ccc5bb 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -248,3 +248,13 @@ void BKE_editmesh_lnorspace_update(BMEditMesh *em) BM_lnorspace_update(bm); } + +/* If autosmooth not already set, set it */ +void BKE_editmesh_ensure_autosmooth(BMEditMesh *em) +{ + Mesh *me = em->ob->data; + if (!(me->flag & ME_AUTOSMOOTH)) { + me->flag |= ME_AUTOSMOOTH; + BKE_editmesh_lnorspace_update(em); + } +} diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 51715c3a223..7cbd5b6b050 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -172,7 +172,7 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef if (cu->flag & CU_PATH) { if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL || eff->ob->runtime.curve_cache->path->data == NULL) { - BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false); } if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) { diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8c95e4c7ff3..3bca77c5b51 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1707,6 +1707,11 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) /* not valid channel */ return 0.0f; } + else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) { + /* Cubic root of the change in volume, equal to the geometric mean + * of scale over all three axes unless the matrix includes shear. */ + return cbrtf(mat4_to_volume_scale(mat)); + } else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) { /* Extract scale, and choose the right axis, * inline 'mat4_to_size'. */ @@ -3065,14 +3070,20 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, return evaluate_fcurve_ex(fcu, evaltime, cvalue); } +/* Checks if the curve has valid keys, drivers or modifiers that produce an actual curve. */ +bool BKE_fcurve_is_empty(FCurve *fcu) +{ + return (fcu->totvert == 0) && (fcu->driver == NULL) && + !list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE); +} + /* Calculate the value of the given F-Curve at the given frame, and set its curval */ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) { /* only calculate + set curval (overriding the existing value) if curve has * any data which warrants this... */ - if ((fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) || - list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE)) { + if (!BKE_fcurve_is_empty(fcu)) { /* calculate and set curval (evaluates driver too if necessary) */ float curval; if (fcu->driver) { diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index c6188642e41..794d07203af 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -867,7 +867,6 @@ static void fcm_python_free(FModifier *fcm) /* id-properties */ IDP_FreeProperty(data->prop); - MEM_freeN(data->prop); } static void fcm_python_new_data(void *mdata) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index c82b2c377fa..439005ca1b4 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1109,7 +1109,8 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n /* Returns the material for a brush with respect to its pinned state. */ Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush) { - if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { + if ((brush) && (brush->gpencil_settings) && + (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { Material *ma = BKE_gpencil_brush_material_get(brush); return ma; } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 39e72d7e3a8..016da52252a 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -121,7 +121,7 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) BLI_assert(prop->type == IDP_IDPARRAY); for (i = 0; i < prop->len; i++) { - IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user); + IDP_FreePropertyContent_ex(GETPROP(prop, i), do_id_user); } if (prop->data.pointer) { @@ -142,7 +142,7 @@ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) old = GETPROP(prop, index); if (item != old) { - IDP_FreeProperty(old); + IDP_FreePropertyContent(old); memcpy(old, item, sizeof(IDProperty)); } @@ -175,7 +175,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) int i; for (i = newlen; i < prop->len; i++) { - IDP_FreeProperty(GETPROP(prop, i)); + IDP_FreePropertyContent(GETPROP(prop, i)); } prop->len = newlen; @@ -192,7 +192,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) /* newlen is smaller */ int i; for (i = newlen; i < prop->len; i++) { - IDP_FreeProperty(GETPROP(prop, i)); + IDP_FreePropertyContent(GETPROP(prop, i)); } } @@ -236,7 +236,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) for (a = newlen; a < prop->len; a++) { IDP_FreeProperty(array[a]); - MEM_freeN(array[a]); } } } @@ -513,7 +512,6 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) default: { BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop)); IDP_FreeProperty(other); - MEM_freeN(other); break; } } @@ -535,7 +533,6 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar (prop_src->len != prop_dst->len))) { BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src)); IDP_FreeProperty(prop_dst); - MEM_freeN(prop_dst); } else if (prop_dst->type == IDP_GROUP) { IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen); @@ -562,7 +559,6 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) if (STREQ(loop->name, prop->name)) { BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); IDP_FreeProperty(loop); - MEM_freeN(loop); break; } } @@ -588,7 +584,6 @@ void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop if (prop_exist != NULL) { BLI_insertlinkreplace(&group->data.group, prop_exist, prop); IDP_FreeProperty(prop_exist); - MEM_freeN(prop_exist); } else { group->len++; @@ -668,12 +663,6 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw * (the function that adds new properties to groups, #IDP_AddToGroup, * returns false if a property can't be added to the group, and true if it can) * and free the property. - * - * Currently the code to free ID properties is designed to leave the actual struct - * you pass it un-freed, this is needed for how the system works. This means - * to free an ID property, you first call #IDP_FreeProperty then #MEM_freeN the struct. - * In the future this will just be #IDP_FreeProperty and the code will - * be reorganized to work properly. */ bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) { @@ -709,8 +698,7 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew * \note this does not free the property!! * * To free the property, you have to do: - * IDP_FreeProperty(prop); //free all subdata - * MEM_freeN(prop); //free property struct itself + * IDP_FreeProperty(prop); */ void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop) { @@ -727,7 +715,6 @@ void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop) { IDP_RemoveFromGroup(group, prop); IDP_FreeProperty(prop); - MEM_freeN(prop); } IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name) @@ -753,7 +740,7 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) BLI_assert(prop->type == IDP_GROUP); for (loop = prop->data.group.first; loop; loop = loop->next) { - IDP_FreeProperty_ex(loop, do_id_user); + IDP_FreePropertyContent_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); } @@ -1070,7 +1057,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs! * But it does not free the actual IDProperty struct itself. */ -void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user) +void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user) { switch (prop->type) { case IDP_ARRAY: @@ -1093,14 +1080,20 @@ void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user) } } +void IDP_FreePropertyContent(IDProperty *prop) +{ + IDP_FreePropertyContent_ex(prop, true); +} + void IDP_FreeProperty(IDProperty *prop) { - IDP_FreeProperty_ex(prop, true); + IDP_FreePropertyContent(prop); + MEM_freeN(prop); } void IDP_ClearProperty(IDProperty *prop) { - IDP_FreeProperty(prop); + IDP_FreePropertyContent(prop); prop->data.pointer = NULL; prop->len = prop->totallen = 0; } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f23c58befdf..9960994400f 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -470,7 +470,7 @@ bool BKE_image_scale(Image *image, int width, int height) if (ibuf) { IMB_scaleImBuf(ibuf, width, height); - ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_mark_dirty(image, ibuf); } BKE_image_release_ibuf(image, ibuf, lock); @@ -502,6 +502,12 @@ static void image_init_color_management(Image *ima) if (ibuf->flags & IB_alphamode_premul) { ima->alpha_mode = IMA_ALPHA_PREMUL; } + else if (ibuf->flags & IB_alphamode_channel_packed) { + ima->alpha_mode = IMA_ALPHA_CHANNEL_PACKED; + } + else if (ibuf->flags & IB_alphamode_ignore) { + ima->alpha_mode = IMA_ALPHA_IGNORE; + } else { ima->alpha_mode = IMA_ALPHA_STRAIGHT; } @@ -646,7 +652,6 @@ static ImBuf *add_ibuf_size(unsigned int width, } STRNCPY(ibuf->name, name); - ibuf->userflags |= IB_BITMAPDIRTY; switch (gen_type) { case IMA_GENTYPE_GRID: @@ -3593,16 +3598,18 @@ static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf)) static int imbuf_alpha_flags_for_image(Image *ima) { - int flag = 0; - - if (ima->flag & IMA_IGNORE_ALPHA) { - flag |= IB_ignore_alpha; - } - else if (ima->alpha_mode == IMA_ALPHA_PREMUL) { - flag |= IB_alphamode_premul; + switch (ima->alpha_mode) { + case IMA_ALPHA_STRAIGHT: + return 0; + case IMA_ALPHA_PREMUL: + return IB_alphamode_premul; + case IMA_ALPHA_CHANNEL_PACKED: + return IB_alphamode_channel_packed; + case IMA_ALPHA_IGNORE: + return IB_alphamode_ignore; } - return flag; + return 0; } /* the number of files will vary according to the stereo format */ @@ -5081,12 +5088,20 @@ bool BKE_image_has_packedfile(Image *ima) return (BLI_listbase_is_empty(&ima->packedfiles) == false); } +bool BKE_image_has_filepath(Image *ima) +{ + /* This could be improved to detect cases like //../../, currently path + * remapping empty file paths empty. */ + return ima->name[0] != '\0'; +} + /* Checks the image buffer changes with time (not keyframed values). */ bool BKE_image_is_animated(Image *image) { return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE); } +/* Image modifications */ bool BKE_image_is_dirty(Image *image) { bool is_dirty = false; @@ -5110,6 +5125,11 @@ bool BKE_image_is_dirty(Image *image) return is_dirty; } +void BKE_image_mark_dirty(Image *UNUSED(image), ImBuf *ibuf) +{ + ibuf->userflags |= IB_BITMAPDIRTY; +} + void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options) { BLI_spin_lock(&image_spin); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index fc349e62809..60c00160e6d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -235,7 +235,6 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) if (view_layer->id_properties) { IDP_FreeProperty(view_layer->id_properties); - MEM_freeN(view_layer->id_properties); } MEM_SAFE_FREE(view_layer->object_bases_array); @@ -693,8 +692,8 @@ static short layer_collection_sync(ViewLayer *view_layer, lc->runtime_flag = child_runtime_flag; } - if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && - ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0)) { + if (((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) && + ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0)) { lc->runtime_flag |= LAYER_COLLECTION_VISIBLE; } @@ -723,9 +722,9 @@ static short layer_collection_sync(ViewLayer *view_layer, BLI_addtail(new_object_bases, base); } - if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) { + if ((child_restrict & COLLECTION_RESTRICT_VIEWPORT) == 0) { base->flag_from_collection |= BASE_ENABLED_VIEWPORT; - if ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) { + if ((child_layer_restrict & LAYER_COLLECTION_HIDE) == 0) { base->flag_from_collection |= BASE_VISIBLE; if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) { base->flag_from_collection |= BASE_SELECTABLE; @@ -1014,8 +1013,8 @@ bool BKE_layer_collection_isolate(Scene *scene, bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE); if ((!ID_IS_LINKED(lc->collection) && !hide_it)) { - if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { - lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW; + if (lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) { + lc->collection->flag &= ~COLLECTION_RESTRICT_VIEWPORT; depsgraph_need_update = true; } } @@ -1024,13 +1023,13 @@ bool BKE_layer_collection_isolate(Scene *scene, /* Hide all collections . */ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_HIDE); } } /* Make all the direct parents visible. */ if (hide_it) { - lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW; + lc->flag |= LAYER_COLLECTION_HIDE; } else { LayerCollection *lc_parent = lc; @@ -1044,13 +1043,13 @@ bool BKE_layer_collection_isolate(Scene *scene, while (lc_parent != lc) { if (!ID_IS_LINKED(lc_parent->collection)) { - if (lc_parent->collection->flag & COLLECTION_RESTRICT_VIEW) { - lc_parent->collection->flag &= ~COLLECTION_RESTRICT_VIEW; + if (lc_parent->collection->flag & COLLECTION_RESTRICT_VIEWPORT) { + lc_parent->collection->flag &= ~COLLECTION_RESTRICT_VIEWPORT; depsgraph_need_update = true; } } - lc_parent->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + lc_parent->flag &= ~LAYER_COLLECTION_HIDE; for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { @@ -1062,7 +1061,7 @@ bool BKE_layer_collection_isolate(Scene *scene, } /* Make all the children visible, but respect their disable state. */ - layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_HIDE); BKE_layer_collection_activate(view_layer, lc); } @@ -1109,27 +1108,27 @@ bool BKE_layer_collection_set_visible(ViewLayer *view_layer, bool depsgraph_changed = false; if (visible && (!ID_IS_LINKED(lc->collection)) && - ((lc->collection->flag & COLLECTION_RESTRICT_VIEW) != 0)) { - lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW; + ((lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) != 0)) { + lc->collection->flag &= ~COLLECTION_RESTRICT_VIEWPORT; depsgraph_changed = true; } if (hierarchy) { if (visible) { - layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_HIDE); layer_collection_bases_show_recursive(view_layer, lc); } else { - layer_collection_flag_set_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW); + layer_collection_flag_set_recursive(lc, LAYER_COLLECTION_HIDE); layer_collection_bases_hide_recursive(view_layer, lc); } } else { if (visible) { - lc->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + lc->flag &= ~LAYER_COLLECTION_HIDE; } else { - lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW; + lc->flag |= LAYER_COLLECTION_HIDE; } } return depsgraph_changed; @@ -1491,7 +1490,7 @@ void BKE_base_eval_flags(Base *base) /* Apply object restrictions. */ const int object_restrict = base->object->restrictflag; - if (object_restrict & OB_RESTRICT_VIEW) { + if (object_restrict & OB_RESTRICT_VIEWPORT) { base->flag &= ~BASE_ENABLED_VIEWPORT; } if (object_restrict & OB_RESTRICT_RENDER) { diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index ad0c405ab28..8b08c189270 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -873,7 +873,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) /* assign copy */ RNA_id_pointer_create(newid, &idptr); - RNA_property_pointer_set(ptr, prop, idptr); + RNA_property_pointer_set(ptr, prop, idptr, NULL); RNA_property_update(C, ptr, prop); /* tag grease pencil datablock and disable onion */ @@ -1860,7 +1860,7 @@ static void library_make_local_copying_check(ID *id, * (except group and objects ones). */ /* Note: Old (2.77) version was simply making (tagging) data-blocks as local, - * without actually making any check whether * they were also indirectly used or not... + * without actually making any check whether they were also indirectly used or not... * * Current version uses regular id_make_local callback, with advanced pre-processing step to detect * all cases of IDs currently indirectly used, but which will be used by local data only once this diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c index 5ed6577e90a..231e0b8ee60 100644 --- a/source/blender/blenkernel/intern/library_override.c +++ b/source/blender/blenkernel/intern/library_override.c @@ -81,7 +81,7 @@ IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id) for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL; ancestor_id = ancestor_id->override_static->reference) { - ; + /* pass */ } if (ancestor_id != NULL && ancestor_id->override_static != NULL) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d0515d8783d..a95069a2af9 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -755,7 +755,7 @@ static void library_foreach_ID_link(Main *bmain, case ID_CA: { Camera *camera = (Camera *)id; - CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP); + CALLBACK_INVOKE(camera->dof.focus_object, IDWALK_CB_NOP); for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) { if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER); diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 3b6f11935d1..4e5eac7924b 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -740,7 +740,7 @@ void BKE_libblock_relink_to_newid(ID *id) void BKE_libblock_free_data(ID *id, const bool do_id_user) { if (id->properties) { - IDP_FreeProperty_ex(id->properties, do_id_user); + IDP_FreePropertyContent_ex(id->properties, do_id_user); MEM_freeN(id->properties); } diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index 05b2eb82daf..1c3acb6a73a 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -80,6 +80,7 @@ void BKE_light_init(Light *la) la->contact_thickness = 0.2f; la->spec_fac = 1.0f; la->att_dist = 40.0f; + la->sun_angle = DEG2RADF(0.526f); curvemapping_initialize(la->curfalloff); } diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 9a9b3757ef2..43fc8152c7b 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -225,6 +225,16 @@ MaskLayer *BKE_mask_layer_copy(const MaskLayer *masklay) MaskSpline *spline_new = BKE_mask_spline_copy(spline); BLI_addtail(&masklay_new->splines, spline_new); + + if (spline == masklay->act_spline) { + masklay_new->act_spline = spline_new; + } + + if (masklay->act_point >= spline->points && + masklay->act_point < spline->points + spline->tot_point) { + const size_t point_index = masklay->act_point - spline->points; + masklay_new->act_point = spline_new->points + point_index; + } } /* correct animation */ diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 3f4e504867c..461adc823b9 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -34,10 +34,13 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_edgehash.h" +#include "BLI_string.h" #include "BKE_main.h" #include "BKE_DerivedMesh.h" +#include "BKE_editmesh.h" #include "BKE_key.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -612,7 +615,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, } /* make mesh */ - me = BKE_mesh_add(bmain, obdata_name); + if (bmain != NULL) { + me = BKE_mesh_add(bmain, obdata_name); + } + else { + me = BKE_id_new_nomain(ID_ME, obdata_name); + } + me->totvert = totvert; me->totedge = totedge; me->totloop = totloop; @@ -632,7 +641,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, BKE_mesh_calc_normals(me); } else { - me = BKE_mesh_add(bmain, obdata_name); + if (bmain != NULL) { + me = BKE_mesh_add(bmain, obdata_name); + } + else { + me = BKE_id_new_nomain(ID_ME, obdata_name); + } + ob->runtime.mesh_eval = NULL; BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); } @@ -662,16 +677,18 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, ob->type = OB_MESH; /* other users */ - ob1 = bmain->objects.first; - while (ob1) { - if (ob1->data == cu) { - ob1->type = OB_MESH; - - id_us_min((ID *)ob1->data); - ob1->data = ob->data; - id_us_plus((ID *)ob1->data); + if (bmain != NULL) { + ob1 = bmain->objects.first; + while (ob1) { + if (ob1->data == cu) { + ob1->type = OB_MESH; + + id_us_min((ID *)ob1->data); + ob1->data = ob->data; + id_us_plus((ID *)ob1->data); + } + ob1 = ob1->id.next; } - ob1 = ob1->id.next; } if (temporary) { @@ -892,302 +909,280 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), } } -/* settings: 1 - preview, 2 - render - * - * The convention goes as following: - * - * - Passing original object with apply_modifiers=false will give a - * non-modified non-deformed mesh. - * The result mesh will point to datablocks from the original "domain". For - * example, materials will be original. - * - * - Passing original object with apply_modifiers=true will give a mesh which - * has all modifiers applied. - * The result mesh will point to datablocks from the original "domain". For - * example, materials will be original. +/* Create a temporary object to be used for nurbs-to-mesh conversion. * - * - Passing evaluated object will ignore apply_modifiers argument, and the - * result always contains all modifiers applied. - * The result mesh will point to an evaluated datablocks. For example, - * materials will be an evaluated IDs from the dependency graph. - */ -Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, - Main *bmain, - Scene *sce, - Object *ob, - const bool apply_modifiers, - const bool calc_undeformed) + * This is more complex that it should be because BKE_mesh_from_nurbs_displist() will do more than + * simply conversion and will attempt to take over ownership of evaluated result and will also + * modify the input object. */ +static Object *object_for_curve_to_mesh_create(Object *object) { - Mesh *tmpmesh; - Curve *tmpcu = NULL, *copycu; - int i; - const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - bool effective_apply_modifiers = apply_modifiers; - bool do_mat_id_data_us = true; - - Object *object_input = ob; - Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input); - Object object_for_eval; - - if (object_eval == object_input) { - /* Evaluated mesh contains all modifiers applied already. - * The other types of object has them applied, but are stored in other - * data structures than a mesh. So need to apply modifiers again on a - * temporary copy before converting result to mesh. */ - if (object_input->type == OB_MESH) { - effective_apply_modifiers = false; - } - else { - effective_apply_modifiers = true; - } - object_for_eval = *object_eval; + Curve *curve = (Curve *)object->data; + + /* Create object itself. */ + Object *temp_object; + BKE_id_copy_ex(NULL, &object->id, (ID **)&temp_object, LIB_ID_COPY_LOCALIZE); + + /* Remove all modifiers, since we don't want them to be applied. */ + BKE_object_free_modifiers(temp_object, LIB_ID_CREATE_NO_USER_REFCOUNT); + + /* Copy relevant evaluated fields of curve cache. + * + * Note that there are extra fields in there like bevel and path, but those are not needed during + * conversion, so they are not copied to save unnecessary allocations. */ + if (object->runtime.curve_cache != NULL) { + temp_object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), + "CurveCache for curve types"); + BKE_displist_copy(&temp_object->runtime.curve_cache->disp, &object->runtime.curve_cache->disp); } - else { - if (apply_modifiers) { - object_for_eval = *object_eval; - if (object_for_eval.runtime.mesh_orig != NULL) { - object_for_eval.data = object_for_eval.runtime.mesh_orig; - } - } - else { - object_for_eval = *object_input; - } + /* Constructive modifiers will use mesh to store result. */ + if (object->runtime.mesh_eval != NULL) { + BKE_id_copy_ex(NULL, + &object->runtime.mesh_eval->id, + (ID **)&temp_object->runtime.mesh_eval, + LIB_ID_COPY_LOCALIZE); } - const bool cage = !effective_apply_modifiers; + /* Need to create copy of curve itself as well, it will be freed by underlying conversion + * functions. + * + * NOTE: Copies the data, but not the shapekeys. */ + BKE_id_copy_ex(NULL, object->data, (ID **)&temp_object->data, LIB_ID_COPY_LOCALIZE); + Curve *temp_curve = (Curve *)temp_object->data; - /* perform the mesh extraction based on type */ - switch (object_for_eval.type) { - case OB_FONT: - case OB_CURVE: - case OB_SURF: { - ListBase dispbase = {NULL, NULL}; - Mesh *me_eval_final = NULL; - int uv_from_orco; - - /* copies object and modifiers (but not the data) */ - Object *tmpobj; - BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE); - tmpcu = (Curve *)tmpobj->data; - - /* Copy cached display list, it might be needed by the stack evaluation. - * Ideally stack should be able to use render-time display list, but doing - * so is quite tricky and not safe so close to the release. - * - * TODO(sergey): Look into more proper solution. - */ - if (object_for_eval.runtime.curve_cache != NULL) { - if (tmpobj->runtime.curve_cache == NULL) { - tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), - "CurveCache for curve types"); - } - BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, - &object_for_eval.runtime.curve_cache->disp); - } + /* Make sure texture space is calculated for a copy of curve, it will be used for the final + * result. */ + BKE_curve_texspace_calc(temp_curve); - /* if getting the original caged mesh, delete object modifiers */ - if (cage) { - BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT); - } + /* Temporarily set edit so we get updates from edit mode, but also because for text datablocks + * copying it while in edit mode gives invalid data structures. */ + temp_curve->editfont = curve->editfont; + temp_curve->editnurb = curve->editnurb; - /* copies the data, but *not* the shapekeys. */ - BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)©cu, LIB_ID_COPY_LOCALIZE); - tmpobj->data = copycu; - - /* make sure texture space is calculated for a copy of curve, - * it will be used for the final result. - */ - BKE_curve_texspace_calc(copycu); - - /* temporarily set edit so we get updates from edit mode, but - * also because for text datablocks copying it while in edit - * mode gives invalid data structures */ - copycu->editfont = tmpcu->editfont; - copycu->editnurb = tmpcu->editnurb; - - /* get updated display list, and convert to a mesh */ - BKE_displist_make_curveTypes_forRender( - depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render, NULL); - - copycu->editfont = NULL; - copycu->editnurb = NULL; - - tmpobj->runtime.mesh_eval = me_eval_final; - - /* convert object type to mesh */ - uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0; - BKE_mesh_from_nurbs_displist( - bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true); - /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */ - copycu = NULL; - - tmpmesh = tmpobj->data; - id_us_min( - &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */ - - BKE_displist_free(&dispbase); - - /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. - * if it didn't the curve did not have any segments or otherwise - * would have generated an empty mesh */ - if (tmpobj->type != OB_MESH) { - BKE_id_free(NULL, tmpobj); - return NULL; - } + return temp_object; +} - BKE_id_free(NULL, tmpobj); +static void curve_to_mesh_eval_ensure(Object *object) +{ + if (object->runtime.curve_cache == NULL) { + object->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); + } + Curve *curve = (Curve *)object->data; + Curve remapped_curve = *curve; + Object remapped_object = *object; + remapped_object.data = &remapped_curve; - /* XXX The curve to mesh conversion is convoluted... - * But essentially, BKE_mesh_from_nurbs_displist() - * already transfers the ownership of materials from the temp copy of the Curve ID to the - * new Mesh ID, so we do not want to increase materials' usercount later. */ - do_mat_id_data_us = false; + /* Clear all modifiers for the bevel object. + * + * This is because they can not be reliably evaluated for an original object (at least because + * the state of dependencies is not know). + * + * So we create temporary copy of the object which will use same data as the original bevel, but + * will have no modifiers. */ + Object bevel_object = {NULL}; + if (remapped_curve.bevobj != NULL) { + bevel_object = *remapped_curve.bevobj; + BLI_listbase_clear(&bevel_object.modifiers); + remapped_curve.bevobj = &bevel_object; + } - break; - } + /* Same thing for taper. */ + Object taper_object = {NULL}; + if (remapped_curve.taperobj != NULL) { + taper_object = *remapped_curve.taperobj; + BLI_listbase_clear(&taper_object.modifiers); + remapped_curve.taperobj = &taper_object; + } - case OB_MBALL: { - /* metaballs don't have modifiers, so just convert to mesh */ - Object *basis_ob = BKE_mball_basis_find(sce, object_input); - /* todo, re-generatre for render-res */ - /* metaball_polygonize(scene, ob) */ + /* NOTE: We don't have dependency graph or scene here, so we pass NULL. This is all fine since + * they are only used for modifier stack, which we have explicitly disabled for all objects. + * + * TODO(sergey): This is a very fragile logic, but proper solution requires re-writing quite a + * bit of internal functions (BKE_mesh_from_nurbs_displist, BKE_mesh_nomain_to_mesh) and also + * Mesh From Curve operator. + * Brecht says hold off with that. */ + BKE_displist_make_curveTypes_forRender(NULL, + NULL, + &remapped_object, + &remapped_object.runtime.curve_cache->disp, + &remapped_object.runtime.mesh_eval, + false); + + BKE_object_free_curve_cache(&bevel_object); + BKE_object_free_curve_cache(&taper_object); +} - if (basis_ob != object_input) { - /* Only do basis metaball. */ - return NULL; - } +static Mesh *mesh_new_from_curve_type_object(Object *object) +{ + Curve *curve = object->data; + const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; - tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); - /* BKE_mesh_add gives us a user count we don't need */ - id_us_min(&tmpmesh->id); + Object *temp_object = object_for_curve_to_mesh_create(object); + Curve *temp_curve = (Curve *)temp_object->data; - if (render) { - ListBase disp = {NULL, NULL}; - BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp); - BKE_mesh_from_metaball(&disp, tmpmesh); - BKE_displist_free(&disp); - } - else { - ListBase disp = {NULL, NULL}; - if (object_for_eval.runtime.curve_cache) { - disp = object_for_eval.runtime.curve_cache->disp; - } - BKE_mesh_from_metaball(&disp, tmpmesh); - } + /* When input object is an original one, we don't have evaluated curve cache yet, so need to + * create it in the temporary object. */ + if (!DEG_is_evaluated_object(object)) { + curve_to_mesh_eval_ensure(temp_object); + } - BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval); + /* Reset pointers before conversion. */ + temp_curve->editfont = NULL; + temp_curve->editnurb = NULL; + + /* Convert to mesh. */ + BKE_mesh_from_nurbs_displist(NULL, + temp_object, + &temp_object->runtime.curve_cache->disp, + uv_from_orco, + curve->id.name + 2, + true); + + /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did + * not have any segments or otherwise would have generated an empty mesh. */ + if (temp_object->type != OB_MESH) { + BKE_id_free(NULL, temp_object); + return NULL; + } - break; - } - case OB_MESH: - /* copies object and modifiers (but not the data) */ - if (cage) { - /* copies the data (but *not* the shapekeys). */ - Mesh *mesh = object_for_eval.data; - BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0); - /* XXX BKE_mesh_copy() already handles materials usercount. */ - do_mat_id_data_us = false; - } - /* if not getting the original caged mesh, get final derived mesh */ - else { - /* Make a dummy mesh, saves copying */ - Mesh *me_eval; - CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter, - * for example, needs CD_MASK_MDEFORMVERT */ + Mesh *mesh_result = temp_object->data; - if (calc_undeformed) { - mask.vmask |= CD_MASK_ORCO; - } + BKE_id_free(NULL, temp_object); - if (render) { - me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask); - } - else { - me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask); - } + /* NOTE: Materials are copied in BKE_mesh_from_nurbs_displist(). */ - tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); - BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true); + return mesh_result; +} - /* Copy autosmooth settings from original mesh. */ - Mesh *me = (Mesh *)object_for_eval.data; - tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); - tmpmesh->smoothresh = me->smoothresh; - } +static Mesh *mesh_new_from_mball_object(Object *object) +{ + MetaBall *mball = (MetaBall *)object->data; - /* BKE_mesh_add/copy gives us a user count we don't need */ - id_us_min(&tmpmesh->id); + /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta + * balls and all evaluated child meta balls (since polygonization is only stored in the mother + * ball). + * + * We create empty mesh so scripters don't run into None objects. */ + if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL || + BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { + return BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); + } - break; - default: - /* "Object does not have geometry data") */ - return NULL; + Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); + BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); + + /* Copy materials. */ + mesh_result->totcol = mball->totcol; + mesh_result->mat = MEM_dupallocN(mball->mat); + if (mball->mat != NULL) { + for (int i = mball->totcol; i-- > 0;) { + mesh_result->mat[i] = give_current_material(object, i + 1); + } } - /* Copy materials to new mesh */ - switch (object_for_eval.type) { - case OB_SURF: - case OB_FONT: - case OB_CURVE: - tmpmesh->totcol = tmpcu->totcol; + return mesh_result; +} - /* free old material list (if it exists) and adjust user counts */ - if (tmpcu->mat) { - for (i = tmpcu->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); +static Mesh *mesh_new_from_mesh_object(Object *object) +{ + Mesh *mesh_input = object->data; + /* If we are in edit mode, use evaluated mesh from edit structure, matching to what + * viewport is using for visualization. */ + if (mesh_input->edit_mesh != NULL && mesh_input->edit_mesh->mesh_eval_final) { + mesh_input = mesh_input->edit_mesh->mesh_eval_final; + } + Mesh *mesh_result = NULL; + BKE_id_copy_ex(NULL, + &mesh_input->id, + (ID **)&mesh_result, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT); + /* NOTE: Materials should already be copied. */ + /* Copy original mesh name. This is because edit meshes might not have one properly set name. */ + BLI_strncpy(mesh_result->id.name, ((ID *)object->data)->name, sizeof(mesh_result->id.name)); + return mesh_result; +} - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } +Mesh *BKE_mesh_new_from_object(Object *object) +{ + Mesh *new_mesh = NULL; + switch (object->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + new_mesh = mesh_new_from_curve_type_object(object); + break; + case OB_MBALL: + new_mesh = mesh_new_from_mball_object(object); break; + case OB_MESH: + new_mesh = mesh_new_from_mesh_object(object); + break; + default: + /* Object does not have geometry data. */ + return NULL; + } + if (new_mesh == NULL) { + /* Happens in special cases like request of mesh for non-mother meta ball. */ + return NULL; + } + /* The result must have 0 users, since it's just a mesh which is free-dangling data-block. + * All the conversion functions are supposed to ensure mesh is not counted. */ + BLI_assert(new_mesh->id.us == 0); + return new_mesh; +} - case OB_MBALL: { - MetaBall *tmpmb = (MetaBall *)object_for_eval.data; - tmpmesh->mat = MEM_dupallocN(tmpmb->mat); - tmpmesh->totcol = tmpmb->totcol; +static int foreach_libblock_make_original_and_usercount_callback(void *user_data_v, + ID *id_self, + ID **id_p, + int cb_flag) +{ + UNUSED_VARS(user_data_v, id_self, cb_flag); + if (*id_p == NULL) { + return IDWALK_RET_NOP; + } + *id_p = DEG_get_original_id(*id_p); + id_us_plus(*id_p); + return IDWALK_RET_NOP; +} - /* free old material list (if it exists) and adjust user counts */ - if (tmpmb->mat) { - for (i = tmpmb->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); +Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain, Object *object) +{ + Mesh *mesh = BKE_mesh_new_from_object(object); - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } - break; - } + /* Make sure mesh only points original datablocks, also increase users of materials and other + * possibly referenced data-blocks. + * + * Going to original data-blocks is required to have bmain in a consistent state, where + * everything is only allowed to reference original data-blocks. + * + * user-count is required is because so far mesh was in a limbo, where library management does + * not perform any user management (i.e. copy of a mesh will not increase users of materials). */ + BKE_library_foreach_ID_link( + NULL, &mesh->id, foreach_libblock_make_original_and_usercount_callback, NULL, IDWALK_NOP); + + /* Append the mesh to bmain. + * We do it a bit longer way since there is no simple and clear way of adding existing datablock + * to the bmain. So we allocate new empty mesh in the bmain (which guarantess all the naming and + * orders and flags) and move the temporary mesh in place there. */ + Mesh *mesh_in_bmain = BKE_mesh_add(bmain, mesh->id.name + 2); + + /* NOTE: BKE_mesh_nomain_to_mesh() does not copy materials and instead it preserves them in the + * destinaion mesh .So we "steal" all related fields before calling it. + * + * TODO(sergey): We really better have a function which gets and ID and accepts it for the bmain. + */ + mesh_in_bmain->mat = mesh->mat; + mesh_in_bmain->totcol = mesh->totcol; + mesh_in_bmain->flag = mesh->flag; + mesh_in_bmain->smoothresh = mesh->smoothresh; + mesh->mat = NULL; - case OB_MESH: - if (!cage) { - Mesh *origmesh = object_for_eval.data; - tmpmesh->flag = origmesh->flag; - tmpmesh->mat = MEM_dupallocN(origmesh->mat); - tmpmesh->totcol = origmesh->totcol; - tmpmesh->smoothresh = origmesh->smoothresh; - if (origmesh->mat) { - for (i = origmesh->totcol; i-- > 0;) { - /* are we an object material or data based? */ - tmpmesh->mat[i] = give_current_material(object_input, i + 1); - - if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && - tmpmesh->mat[i]) { - id_us_plus(&tmpmesh->mat[i]->id); - } - } - } - } - break; - } /* end copy materials */ + BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, NULL, &CD_MASK_MESH, true); + + /* Make sure user count from BKE_mesh_add() is the one we expect here and bring it down to 0. */ + BLI_assert(mesh_in_bmain->id.us == 1); + id_us_min(&mesh_in_bmain->id); - return tmpmesh; + return mesh_in_bmain; } static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index d889fca3a3a..f0fd1203cae 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -2141,8 +2141,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const * Higher level functions hiding most of the code needed around call to * #BKE_mesh_normals_loop_custom_set(). * - * \param r_custom_loopnors is not const, since code will replace zero_v3 normals there - * with automatically computed vectors. + * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there + * with automatically computed vectors. */ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3]) { @@ -2153,8 +2153,8 @@ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3]) * Higher level functions hiding most of the code needed around call to * #BKE_mesh_normals_loop_custom_from_vertices_set(). * - * \param r_custom_loopnors is not const, since code will replace zero_v3 normals there - * with automatically computed vectors. + * \param r_custom_loopnors: is not const, since code will replace zero_v3 normals there + * with automatically computed vectors. */ void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3]) { diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 9bc9865631f..43a5e1d6592 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -934,8 +934,8 @@ void modwrap_deformVertsEM(ModifierData *md, * Note that modifiers in stack always get fully evaluated COW ID pointers, * never original ones. Makes things simpler. * - * \param get_cage_mesh Return evaluated mesh with only deforming modifiers applied - * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh). + * \param get_cage_mesh: Return evaluated mesh with only deforming modifiers applied + * (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh). */ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, const bool get_cage_mesh) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3adb6cfe960..b7db434e234 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -787,7 +787,7 @@ static void node_socket_free(bNodeTree *UNUSED(ntree), const bool do_id_user) { if (sock->prop) { - IDP_FreeProperty_ex(sock->prop, do_id_user); + IDP_FreePropertyContent_ex(sock->prop, do_id_user); MEM_freeN(sock->prop); } @@ -1850,7 +1850,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node) if (node->prop) { /* Remember, no ID user refcount management here! */ - IDP_FreeProperty_ex(node->prop, false); + IDP_FreePropertyContent_ex(node->prop, false); MEM_freeN(node->prop); } @@ -1910,7 +1910,6 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *so { if (sock->prop) { IDP_FreeProperty(sock->prop); - MEM_freeN(sock->prop); } if (sock->default_value) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 38a8ad2769a..85ca9cb26b9 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -469,6 +469,7 @@ void BKE_object_free_derived_caches(Object *ob) ob->runtime.mesh_deform_eval = NULL; } + BKE_object_to_mesh_clear(ob); BKE_object_free_curve_cache(ob); /* clear grease pencil data */ @@ -1467,7 +1468,7 @@ Object *BKE_object_copy(Main *bmain, const Object *ob) /** Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.). * - * \param dupflag Controls which sub-data are also duplicated + * \param dupflag: Controls which sub-data are also duplicated * (see #eDupli_ID_Flags in DNA_userdef_types.h). * * \note This function does not do any remapping to new IDs, caller must do it @@ -1951,7 +1952,6 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) /* copy IDProperties */ if (ob->id.properties) { IDP_FreeProperty(ob->id.properties); - MEM_freeN(ob->id.properties); ob->id.properties = NULL; } if (target->id.properties) { @@ -4487,3 +4487,32 @@ void BKE_object_type_set_empty_for_versioning(Object *ob) } ob->mode = OB_MODE_OBJECT; } + +/* Updates select_id of all objects in the given bmain. */ +void BKE_object_update_select_id(struct Main *bmain) +{ + Object *ob = bmain->objects.first; + int select_id = 1; + while (ob) { + ob->runtime.select_id = select_id++; + ob = ob->id.next; + } +} + +Mesh *BKE_object_to_mesh(Object *object) +{ + BKE_object_to_mesh_clear(object); + + Mesh *mesh = BKE_mesh_new_from_object(object); + object->runtime.object_as_temp_mesh = mesh; + return mesh; +} + +void BKE_object_to_mesh_clear(Object *object) +{ + if (object->runtime.object_as_temp_mesh == NULL) { + return; + } + BKE_id_free(NULL, object->runtime.object_as_temp_mesh); + object->runtime.object_as_temp_mesh = NULL; +} diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 8080834a53a..0dedbb7e934 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -1082,7 +1082,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) /* Should the dupli's be generated for this object? - Respect restrict flags */ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : - (restrictflag & OB_RESTRICT_VIEW)) { + (restrictflag & OB_RESTRICT_VIEWPORT)) { return NULL; } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 183bc968897..6dee936ca76 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -202,9 +202,11 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o case OB_CURVE: case OB_SURF: - case OB_FONT: - BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false, NULL); + case OB_FONT: { + bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + BKE_displist_make_curveTypes(depsgraph, scene, ob, for_render, false); break; + } case OB_LATTICE: BKE_lattice_modifiers_calc(depsgraph, scene, ob); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c55cf18fcea..5849d691b03 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -82,8 +82,11 @@ static eOverlayControlFlags overlay_flags = 0; void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex) { Paint *p = BKE_paint_get_active(scene, view_layer); - Brush *br = p->brush; + if (!p) { + return; + } + Brush *br = p->brush; if (!br) { return; } @@ -99,8 +102,11 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve) { Paint *p = BKE_paint_get_active(scene, view_layer); - Brush *br = p->brush; + if (p == NULL) { + return; + } + Brush *br = p->brush; if (br && br->curve == curve) { overlay_flags |= PAINT_OVERLAY_INVALID_CURVE; } @@ -1273,9 +1279,6 @@ void BKE_sculpt_update_mesh_elements( } } } - - /* 2.8x - avoid full mesh update! */ - BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index c6cc72ba989..13649eaf096 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -387,8 +387,11 @@ void psys_find_group_weights(ParticleSettings *part) /* Find object pointers based on index. If the collection is linked from * another library linking may not have the object pointers available on * file load, so we have to retrieve them later. See T49273. */ - const ListBase instance_collection_objects = BKE_collection_object_cache_get( - part->instance_collection); + ListBase instance_collection_objects = {NULL, NULL}; + + if (part->instance_collection) { + instance_collection_objects = BKE_collection_object_cache_get(part->instance_collection); + } for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) { if (dw->ob == NULL) { diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 8125024585c..070c3c7a566 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -1170,7 +1170,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, int i_mapped = 0; for (i = 0; i < totelem && element_weight[i] == 0.0f; i++) { - ; + /* pass */ } element_sum[i_mapped] = element_weight[i] * inv_totweight; element_map[i_mapped] = i; @@ -1216,7 +1216,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, for (i = 0, p = 0; p < totpart; p++, pos += step) { for (; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++) { - ; + /* pass */ } particle_element[p] = element_map[i]; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index cba15aed55f..27722aab2d9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -471,14 +471,6 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData ctx->ma = give_current_material(sim->ob, sim->psys->part->omat); } -#define MAX_PARTICLES_PER_TASK \ - 256 /* XXX arbitrary - maybe use at least number of points instead for better balancing? */ - -BLI_INLINE int ceil_ii(int a, int b) -{ - return (a + b - 1) / b; -} - void psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart, @@ -486,7 +478,7 @@ void psys_tasks_create(ParticleThreadContext *ctx, int *r_numtasks) { ParticleTask *tasks; - int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK); + int numtasks = min_ii(BLI_system_thread_count() * 4, endpart - startpart); float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext; int i; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index c186394880b..f1d5347c48b 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -181,10 +181,10 @@ static int partition_indices(int *prim_indices, int lo, int hi, int axis, float int i = lo, j = hi; for (;;) { for (; prim_bbc[prim_indices[i]].bcentroid[axis] < mid; i++) { - ; + /* pass */ } for (; mid < prim_bbc[prim_indices[j]].bcentroid[axis]; j--) { - ; + /* pass */ } if (!(i < j)) { @@ -216,18 +216,18 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi) for (;;) { if (bvh->looptri) { for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) { - ; + /* pass */ } for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--) { - ; + /* pass */ } } else { for (; grid_materials_match(first, &flagmats[indices[i]]); i++) { - ; + /* pass */ } for (; !grid_materials_match(first, &flagmats[indices[j]]); j--) { - ; + /* pass */ } } @@ -2202,26 +2202,17 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } -struct PBVHNodeDrawCallbackData { - void (*draw_fn)(void *user_data, GPUBatch *batch); +typedef struct PBVHNodeDrawCallbackData { + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers); void *user_data; - bool fast; - bool only_mask; /* Only draw nodes that have mask data. */ - bool wires; -}; +} PBVHNodeDrawCallbackData; static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) { - struct PBVHNodeDrawCallbackData *data = data_v; + PBVHNodeDrawCallbackData *data = data_v; if (!(node->flag & PBVH_FullyHidden)) { - GPUBatch *batch = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast, data->wires); - bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers); - if (!data->only_mask || show_mask) { - if (batch != NULL) { - data->draw_fn(data->user_data, batch); - } - } + data->draw_fn(data->user_data, node->draw_buffers); } } @@ -2231,20 +2222,10 @@ static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) void BKE_pbvh_draw_cb(PBVH *bvh, float (*planes)[4], float (*fnors)[3], - bool fast, - bool wires, - bool only_mask, bool show_vcol, - void (*draw_fn)(void *user_data, GPUBatch *batch), + void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), void *user_data) { - struct PBVHNodeDrawCallbackData draw_data = { - .only_mask = only_mask, - .fast = fast, - .wires = wires, - .draw_fn = draw_fn, - .user_data = user_data, - }; PBVHNode **nodes; int totnode; @@ -2261,6 +2242,11 @@ void BKE_pbvh_draw_cb(PBVH *bvh, MEM_freeN(nodes); } + PBVHNodeDrawCallbackData draw_data = { + .draw_fn = draw_fn, + .user_data = user_data, + }; + if (planes) { BKE_pbvh_search_callback( bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data); @@ -2268,10 +2254,18 @@ void BKE_pbvh_draw_cb(PBVH *bvh, else { BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data); } -#if 0 - if (G.debug_value == 14) - pbvh_draw_BB(bvh); -#endif +} + +void BKE_pbvh_draw_debug_cb( + PBVH *bvh, + void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), + void *user_data) +{ + for (int a = 0; a < bvh->totnode; a++) { + PBVHNode *node = &bvh->nodes[a]; + + draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag); + } } void BKE_pbvh_grids_update( diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 58b36aed24f..872f99ff813 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -497,7 +497,6 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) } if (sce->r.ffcodecdata.properties) { IDP_FreeProperty(sce->r.ffcodecdata.properties); - MEM_freeN(sce->r.ffcodecdata.properties); sce->r.ffcodecdata.properties = NULL; } @@ -566,7 +565,7 @@ void BKE_scene_init(Scene *sce) sce->cursor.rotation_quaternion[0] = 1.0f; sce->cursor.rotation_axis[1] = 1.0f; - sce->r.mode = R_OSA; + sce->r.mode = 0; sce->r.cfra = 1; sce->r.sfra = 1; sce->r.efra = 250; @@ -767,7 +766,6 @@ void BKE_scene_init(Scene *sce) BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic)); BLI_rctf_init(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f); - sce->r.osa = 8; /* Note; in header_info.c the scene copy happens..., * if you add more to renderdata it has to be checked there. */ @@ -905,6 +903,9 @@ void BKE_scene_init(Scene *sce) sce->display.matcap_ssao_attenuation = 1.0f; sce->display.matcap_ssao_samples = 16; + sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; + sce->display.viewport_aa = SCE_DISPLAY_AA_FXAA; + /* OpenGL Render. */ BKE_screen_view3d_shading_init(&sce->display.shading); @@ -2384,4 +2385,20 @@ void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], boo } } +void BKE_scene_cursor_to_mat4(const View3DCursor *cursor, float mat[4][4]) +{ + float mat3[3][3]; + BKE_scene_cursor_rot_to_mat3(cursor, mat3); + copy_m4_m3(mat, mat3); + copy_v3_v3(mat[3], cursor->location); +} + +void BKE_scene_cursor_from_mat4(View3DCursor *cursor, const float mat[4][4], bool use_compat) +{ + float mat3[3][3]; + copy_m3_m4(mat3, mat); + BKE_scene_cursor_mat3_to_rot(cursor, mat3, use_compat); + copy_v3_v3(cursor->location, mat[3]); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 9799f7c2943..222e8ddb724 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -193,18 +193,6 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb) Panel *pa = lb->first; for (; newpa; newpa = newpa->next, pa = pa->next) { newpa->activedata = NULL; - - Panel *newpatab = newlb->first; - Panel *patab = lb->first; - while (newpatab) { - if (newpa->paneltab == patab) { - newpa->paneltab = newpatab; - break; - } - newpatab = newpatab->next; - patab = patab->next; - } - panel_list_copy(&newpa->children, &pa->children); } } @@ -439,7 +427,6 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) } if (uilst->properties) { IDP_FreeProperty(uilst->properties); - MEM_freeN(uilst->properties); } } @@ -853,12 +840,13 @@ void BKE_screen_view3d_shading_init(View3DShading *shading) shading->type = OB_SOLID; shading->prev_type = OB_SOLID; shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_BONE; - shading->light = V3D_LIGHTING_STUDIO; + shading->light = V3D_LIGHTING_MATCAP; shading->shadow_intensity = 0.5f; shading->xray_alpha = 0.5f; shading->xray_alpha_wire = 0.5f; shading->cavity_valley_factor = 1.0f; shading->cavity_ridge_factor = 1.0f; + shading->cavity_type = V3D_SHADING_CAVITY_CURVATURE; shading->curvature_ridge_factor = 1.0f; shading->curvature_valley_factor = 1.0f; copy_v3_fl(shading->single_color, 0.8f); diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index 1c0aa63f590..f77b3e99e30 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -90,7 +90,6 @@ typedef struct SeqCacheKey { struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame */ struct Sequence *seq; SeqRenderData context; - float cfra; float nfra; float cost; bool is_temp_cache; @@ -232,14 +231,17 @@ static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCac SeqCacheKey *finalkey = NULL; if (rkey && lkey) { - if (lkey->cfra > rkey->cfra) { + int lkey_cfra = lkey->seq->start + lkey->nfra; + int rkey_cfra = rkey->seq->start + rkey->nfra; + + if (lkey_cfra > rkey_cfra) { SeqCacheKey *swapkey = lkey; lkey = rkey; rkey = swapkey; } - int l_diff = scene->r.cfra - lkey->cfra; - int r_diff = rkey->cfra - scene->r.cfra; + int l_diff = scene->r.cfra - lkey_cfra; + int r_diff = rkey_cfra - scene->r.cfra; if (l_diff > r_diff) { finalkey = lkey; @@ -319,7 +321,7 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) if (key->cost <= scene->ed->recycle_max_cost) { cheap_count++; if (lkey) { - if (key->cfra < lkey->cfra) { + if (key->seq->start + key->nfra < lkey->seq->start + lkey->nfra) { lkey = key; } } @@ -327,7 +329,7 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) lkey = key; } if (rkey) { - if (key->cfra > rkey->cfra) { + if (key->seq->start + key->nfra > rkey->seq->start + rkey->nfra) { rkey = key; } } @@ -425,7 +427,7 @@ void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int cfra) SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - if (key->is_temp_cache && key->creator_id == id && key->cfra != cfra) { + if (key->is_temp_cache && key->creator_id == id && key->seq->start + key->nfra != cfra) { BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree); } } @@ -592,7 +594,6 @@ void BKE_sequencer_cache_put( key->cache_owner = cache; key->seq = seq; key->context = *context; - key->cfra = cfra; key->nfra = cfra - seq->start; key->type = type; key->cost = cost; @@ -634,7 +635,7 @@ void BKE_sequencer_cache_put( void BKE_sequencer_cache_iterate( struct Scene *scene, void *userdata, - bool callback(void *userdata, struct Sequence *seq, int cfra, int cache_type, float cost)) + bool callback(void *userdata, struct Sequence *seq, int nfra, int cache_type, float cost)) { SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -650,7 +651,7 @@ void BKE_sequencer_cache_iterate( SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - interrupt = callback(userdata, key->seq, key->cfra, key->type, key->cost); + interrupt = callback(userdata, key->seq, key->nfra, key->type, key->cost); } cache->last_key = NULL; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index b1a32552878..92f951ec637 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -262,7 +262,7 @@ static void BKE_sequence_free_ex(Scene *scene, } if (seq->prop) { - IDP_FreeProperty_ex(seq->prop, do_id_user); + IDP_FreePropertyContent_ex(seq->prop, do_id_user); MEM_freeN(seq->prop); } @@ -635,8 +635,6 @@ void BKE_sequencer_new_render_data(Main *bmain, r_context->is_proxy_render = false; r_context->view_id = 0; r_context->gpu_offscreen = NULL; - r_context->gpu_samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; - r_context->gpu_full_samples = (r_context->gpu_samples) && (scene->r.scemode & R_FULL_SAMPLE); } /* ************************* iterator ************************** */ @@ -2792,7 +2790,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, } if (ibuf->x != context->rectx || ibuf->y != context->recty) { - if (scene->r.mode & R_OSA) { + if (scene->display.render_aa > SCE_DISPLAY_AA_FXAA) { IMB_scaleImBuf(ibuf, (short)context->rectx, (short)context->recty); } else { @@ -3523,7 +3521,6 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, unsigned int draw_flags = V3D_OFSDRAW_NONE; draw_flags |= (use_gpencil) ? V3D_OFSDRAW_SHOW_ANNOTATION : 0; - draw_flags |= (context->gpu_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0; draw_flags |= (context->scene->r.seq_flag & R_SEQ_OVERRIDE_SCENE_SETTINGS) ? V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS : 0; @@ -3549,7 +3546,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, IB_rect, draw_flags, scene->r.alphamode, - context->gpu_samples, + U.ogl_multisamples, viewname, context->gpu_offscreen, err_out); @@ -3578,9 +3575,9 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, re = RE_NewSceneRender(scene); } - RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false); + RE_RenderFrame(re, context->bmain, scene, view_layer, camera, frame, false); - /* restore previous state after it was toggled on & off by RE_BlenderFrame */ + /* restore previous state after it was toggled on & off by RE_RenderFrame */ G.is_rendering = is_rendering; } @@ -5671,12 +5668,12 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) { int start_frame_back = seq_load->start_frame; - seq_load->channel++; + seq_load->channel--; seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load); seq_load->start_frame = start_frame_back; - seq_load->channel--; + seq_load->channel++; } /* can be NULL */ diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 1fe63e21e78..695f9b21559 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -275,10 +275,10 @@ static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame) i = MAX2(0, i); i = MIN2(i, end - 1); for (; i < end - 1 && markers[i].framenr <= ref_frame; ++i) { - ; + /* pass */ } for (; 0 < i && markers[i].framenr > ref_frame; --i) { - ; + /* pass */ } track->last_marker = i; diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index d3e0ff56977..caf88eb0fff 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -29,6 +29,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLT_translation.h" + #include "DNA_listBase.h" #include "DNA_windowmanager_types.h" @@ -337,7 +339,7 @@ static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain) { UNDO_NESTED_ASSERT(false); - undosys_stack_push_main(ustack, "original", bmain); + undosys_stack_push_main(ustack, IFACE_("Original"), bmain); } /* called after 'BKE_undosys_stack_init_from_main' */ @@ -345,7 +347,7 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C) { const UndoType *ut = BKE_undosys_type_from_context(C); if ((ut != NULL) && (ut != BKE_UNDOSYS_TYPE_MEMFILE)) { - BKE_undosys_step_push_with_type(ustack, C, "original mode", ut); + BKE_undosys_step_push_with_type(ustack, C, IFACE_("Original Mode"), ut); } } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 293eed8cfe3..f5b73d88867 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -663,7 +663,7 @@ static const char *unit_find_str(const char *str, const char *substr, bool case_ } /* If str_found is not a valid unit, we have to check further in the string... */ for (str_found++; isalpha_or_utf8(*str_found); str_found++) { - ; + /* pass */ } str = str_found; } diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index f9584adc6e0..387d4ec5773 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -36,6 +36,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" #include "DEG_depsgraph.h" @@ -43,7 +44,8 @@ #include "MEM_guardedalloc.h" /* -------------------------------------------------------------------- */ -/* Internal utils */ +/** \name Internal Utils + * \{ */ static void workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, @@ -134,8 +136,11 @@ static bool UNUSED_FUNCTION(workspaces_is_screen_used) return false; } +/** \} */ + /* -------------------------------------------------------------------- */ -/* Create, delete, init */ +/** \name Create, Delete, Init + * \{ */ WorkSpace *BKE_workspace_add(Main *bmain, const char *name) { @@ -253,8 +258,11 @@ void BKE_workspace_relations_free(ListBase *relation_list) } } +/** \} */ + /* -------------------------------------------------------------------- */ -/* General Utils */ +/** \name General Utils + * \{ */ WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bScreen *screen) { @@ -348,14 +356,37 @@ void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tre } if (tref->properties) { IDP_FreeProperty(tref->properties); - MEM_freeN(tref->properties); } BLI_remlink(&workspace->tools, tref); MEM_freeN(tref); } +bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_id) +{ + if ((*owner_id == '\0') || ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) { + return true; + } + else { + /* We could use hash lookup, for now this list is highly likely under < ~16 items. */ + return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL; + } +} + +void BKE_workspace_id_tag_all_visible(Main *bmain, int tag) +{ + BKE_main_id_tag_listbase(&bmain->workspaces, tag, false); + wmWindowManager *wm = bmain->wm.first; + for (wmWindow *win = wm->windows.first; win; win = win->next) { + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + workspace->id.tag |= tag; + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ -/* Getters/Setters */ +/** \name Getters/Setters + * \{ */ WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook) { @@ -433,13 +464,4 @@ void BKE_workspace_hook_layout_for_workspace_set(WorkSpaceInstanceHook *hook, workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout); } -bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_id) -{ - if ((*owner_id == '\0') || ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) { - return true; - } - else { - /* we could use hash lookup, for now this list is highly under < ~16 items. */ - return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL; - } -} +/** \} */ diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index b72b99e514d..19425a0d80b 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -118,7 +118,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.start_movie = start_stub; mh.append_movie = append_stub; mh.end_movie = end_stub; - mh.get_next_frame = NULL; mh.get_movie_path = NULL; mh.context_create = context_create_stub; mh.context_free = context_free_stub; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index a74d5b241ed..ae41b8f3272 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1616,7 +1616,7 @@ static void ffmpeg_set_expert_options(RenderData *rd) int codec_id = rd->ffcodecdata.codec; if (rd->ffcodecdata.properties) { - IDP_FreeProperty(rd->ffcodecdata.properties); + IDP_FreePropertyContent(rd->ffcodecdata.properties); } if (codec_id == AV_CODEC_ID_H264) { @@ -1680,7 +1680,7 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset) int isntsc = (rd->frs_sec != 25); if (rd->ffcodecdata.properties) { - IDP_FreeProperty(rd->ffcodecdata.properties); + IDP_FreePropertyContent(rd->ffcodecdata.properties); } switch (preset) { diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h index ed8af49d640..4d9fc66a806 100644 --- a/source/blender/blenlib/BLI_callbacks.h +++ b/source/blender/blenlib/BLI_callbacks.h @@ -52,6 +52,7 @@ typedef enum { BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST, BLI_CB_EVT_VERSION_UPDATE, + BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST, BLI_CB_EVT_TOT, } eCbEvent; diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 652f096f32d..52d976daa2d 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -209,6 +209,7 @@ bool invert_m3(float R[3][3]); bool invert_m3_m3(float R[3][3], const float A[3][3]); bool invert_m4(float R[4][4]); bool invert_m4_m4(float R[4][4], const float A[4][4]); +bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]); /* double arithmetic (mixed float/double) */ void mul_m4_v4d(const float M[4][4], double r[4]); @@ -260,6 +261,7 @@ float determinant_m2(float a, float b, float c, float d); float determinant_m3( float a, float b, float c, float d, float e, float f, float g, float h, float i); float determinant_m3_array(const float m[3][3]); +float determinant_m4_mat3_array(const float m[4][4]); float determinant_m4(const float A[4][4]); #define PSEUDOINVERSE_EPSILON 1e-8f @@ -277,6 +279,9 @@ void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); void scale_m3_fl(float R[3][3], float scale); void scale_m4_fl(float R[4][4], float scale); +float mat3_to_volume_scale(const float M[3][3]); +float mat4_to_volume_scale(const float M[4][4]); + float mat3_to_scale(const float M[3][3]); float mat4_to_scale(const float M[4][4]); float mat4_to_xy_scale(const float M[4][4]); diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h new file mode 100644 index 00000000000..c5ef26ffb91 --- /dev/null +++ b/source/blender/blenlib/BLI_memblock.h @@ -0,0 +1,60 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +#ifndef __BLI_MEMBLOCK_H__ +#define __BLI_MEMBLOCK_H__ + +/** \file + * \ingroup bli + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +struct BLI_memblock; + +typedef struct BLI_memblock BLI_memblock; +typedef void (*MemblockValFreeFP)(void *val); + +BLI_memblock *BLI_memblock_create(uint elem_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP valfreefp) ATTR_NONNULL(1); +void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1); + +typedef struct BLI_memblock_iter { + void **chunk_list; + int cur_index; + int end_index; + int chunk_max_ofs; + int chunk_idx; + int elem_size; + int elem_ofs; +} BLI_memblock_iter; + +void BLI_memblock_iternew(BLI_memblock *pool, BLI_memblock_iter *iter) ATTR_NONNULL(); +void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +#ifdef __cplusplus +} +#endif + +#endif /* __BLI_MEMBLOCK_H__ */ diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 151b02a33aa..eec4e885493 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -25,6 +25,10 @@ * \brief Random number functions. */ +#ifdef __cplusplus +extern "C" { +#endif + /* RNG is an abstract random number generator type that avoids using globals. * Always use this instead of the global RNG unless you have a good reason, * the global RNG is not thread safe and will not give repeatable results. @@ -106,4 +110,8 @@ void BLI_hammersley_1d(unsigned int n, double *r); void BLI_halton_2d_sequence(unsigned int prime[2], double offset[2], int n, double *r); void BLI_hammersley_2d_sequence(unsigned int n, double *r); +#ifdef __cplusplus +} +#endif + #endif /* __BLI_RAND_H__ */ diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index f23580916b1..e3cd70f7413 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -62,6 +62,10 @@ void BLI_rcti_resize(struct rcti *rect, int x, int y); void BLI_rctf_resize(struct rctf *rect, float x, float y); void BLI_rcti_scale(rcti *rect, const float scale); void BLI_rctf_scale(rctf *rect, const float scale); +void BLI_rctf_pad_y(struct rctf *rect, + const float boundary_size, + const float pad_min, + const float pad_max); void BLI_rctf_interp(struct rctf *rect, const struct rctf *rect_a, const struct rctf *rect_b, diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 93ad0e1e70f..f4c0399e959 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -41,6 +41,10 @@ char *BLI_cpu_brand_string(void); */ void BLI_hostname_get(char *buffer, size_t bufsize); +/* Get maximum addressable memory in megabytes. */ +size_t BLI_system_memory_max_in_megabytes(void); +int BLI_system_memory_max_in_megabytes_int(void); + /* getpid */ #ifdef WIN32 # define BLI_SYSTEM_PID_H <process.h> diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index dbc72ff1213..0ec6e7ee4fc 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC intern/BLI_linklist.c intern/BLI_linklist_lockfree.c intern/BLI_memarena.c + intern/BLI_memblock.c intern/BLI_memiter.c intern/BLI_mempool.c intern/BLI_timer.c @@ -194,6 +195,7 @@ set(SRC BLI_math_statistics.h BLI_math_vector.h BLI_memarena.h + BLI_memblock.h BLI_memiter.h BLI_memory_utils.h BLI_mempool.h diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c index b5815f7b503..0f7ac92a348 100644 --- a/source/blender/blenlib/intern/BLI_memarena.c +++ b/source/blender/blenlib/intern/BLI_memarena.c @@ -77,6 +77,10 @@ static void memarena_buf_free_all(struct MemBuf *mb) { while (mb != NULL) { struct MemBuf *mb_next = mb->next; + + /* Unpoison memory because MEM_freeN might overwrite it. */ + ASAN_UNPOISON_MEMORY_REGION(mb, (uint)MEM_allocN_len(mb)); + MEM_freeN(mb); mb = mb_next; } diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c new file mode 100644 index 00000000000..ec9b74f2b50 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -0,0 +1,182 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bli + * + * Dead simple, fast memory allocator for allocating many elements of the same size. + * + */ + +#include <string.h> +#include <stdlib.h> + +#include "atomic_ops.h" + +#include "BLI_utildefines.h" + +#include "BLI_memblock.h" /* own include */ + +#include "MEM_guardedalloc.h" + +#include "BLI_strict_flags.h" /* keep last */ + +#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */ +#define CHUNK_LIST_SIZE 16 + +struct BLI_memblock { + void **chunk_list; + + /** Element size in bytes. */ + int elem_size; + /** First unused element index. */ + int elem_next; + /** Last "touched" element. */ + int elem_last; + /** Offset in a chunk of the next elem. */ + int elem_next_ofs; + /** Max offset in a chunk. */ + int chunk_max_ofs; + /** Id of the chunk used for the next allocation. */ + int chunk_next; + /** Chunck size in bytes. */ + int chunk_size; + /** Number of allocated chunck. */ + int chunk_len; +}; + +BLI_memblock *BLI_memblock_create(uint elem_size) +{ + BLI_assert(elem_size < BLI_MEM_BLOCK_CHUNK_SIZE); + + BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock"); + mblk->elem_size = (int)elem_size; + mblk->elem_next = 0; + mblk->elem_last = -1; + mblk->chunk_size = BLI_MEM_BLOCK_CHUNK_SIZE; + mblk->chunk_len = CHUNK_LIST_SIZE; + mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list"); + mblk->chunk_list[0] = MEM_callocN((uint)mblk->chunk_size, "BLI_memblock chunk"); + mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size; + mblk->elem_next_ofs = 0; + mblk->chunk_next = 0; + return mblk; +} + +void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) +{ + BLI_memblock_clear(mblk, free_callback); + + for (int i = 0; i < mblk->chunk_len; i++) { + MEM_SAFE_FREE(mblk->chunk_list[i]); + } + MEM_SAFE_FREE(mblk->chunk_list); + MEM_freeN(mblk); +} + +/* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem + * count. */ +void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) +{ + int elem_per_chunk = mblk->chunk_size / mblk->elem_size; + int last_used_chunk = mblk->elem_next / elem_per_chunk; + + if (free_callback) { + for (int i = mblk->elem_last; i >= mblk->elem_next; i--) { + int chunk_idx = i / elem_per_chunk; + int elem_idx = i - elem_per_chunk * chunk_idx; + void *val = (char *)(mblk->chunk_list[chunk_idx]) + mblk->elem_size * elem_idx; + free_callback(val); + } + } + + for (int i = last_used_chunk + 1; i < mblk->chunk_len; i++) { + MEM_SAFE_FREE(mblk->chunk_list[i]); + } + + if (UNLIKELY(last_used_chunk + 1 < mblk->chunk_len - CHUNK_LIST_SIZE)) { + mblk->chunk_len -= CHUNK_LIST_SIZE; + mblk->chunk_list = MEM_recallocN(mblk->chunk_list, sizeof(void *) * (uint)mblk->chunk_len); + } + + mblk->elem_last = mblk->elem_next - 1; + mblk->elem_next = 0; + mblk->elem_next_ofs = 0; + mblk->chunk_next = 0; +} + +void *BLI_memblock_alloc(BLI_memblock *mblk) +{ + /* Bookeeping. */ + if (mblk->elem_last < mblk->elem_next) { + mblk->elem_last = mblk->elem_next; + } + mblk->elem_next++; + + void *ptr = (char *)(mblk->chunk_list[mblk->chunk_next]) + mblk->elem_next_ofs; + + mblk->elem_next_ofs += mblk->elem_size; + + if (mblk->elem_next_ofs == mblk->chunk_max_ofs) { + mblk->elem_next_ofs = 0; + mblk->chunk_next++; + + if (UNLIKELY(mblk->chunk_next >= mblk->chunk_len)) { + mblk->chunk_len += CHUNK_LIST_SIZE; + mblk->chunk_list = MEM_recallocN(mblk->chunk_list, sizeof(void *) * (uint)mblk->chunk_len); + } + + if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) { + mblk->chunk_list[mblk->chunk_next] = MEM_callocN((uint)mblk->chunk_size, + "BLI_memblock chunk"); + } + } + return ptr; +} + +void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) +{ + /* Small copy of the memblock used for better cache coherence. */ + iter->chunk_list = mblk->chunk_list; + iter->end_index = mblk->elem_next; + iter->cur_index = 0; + iter->chunk_idx = 0; + iter->elem_ofs = 0; + iter->elem_size = mblk->elem_size; + iter->chunk_max_ofs = mblk->chunk_max_ofs; +} + +void *BLI_memblock_iterstep(BLI_memblock_iter *iter) +{ + if (iter->cur_index == iter->end_index) { + return NULL; + } + + iter->cur_index++; + + void *ptr = (char *)(iter->chunk_list[iter->chunk_idx]) + iter->elem_ofs; + + iter->elem_ofs += iter->elem_size; + + if (iter->elem_ofs == iter->chunk_max_ofs) { + iter->elem_ofs = 0; + iter->chunk_idx++; + } + return ptr; +} diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c index c7df7d5fdd4..2d3ba56d08e 100644 --- a/source/blender/blenlib/intern/BLI_memiter.c +++ b/source/blender/blenlib/intern/BLI_memiter.c @@ -239,6 +239,10 @@ static void memiter_free_data(BLI_memiter *mi) BLI_memiter_chunk *chunk = mi->head; while (chunk) { BLI_memiter_chunk *chunk_next = chunk->next; + + /* Unpoison memory because MEM_freeN might overwrite it. */ + ASAN_UNPOISON_MEMORY_REGION(chunk, MEM_allocN_len(chunk)); + MEM_freeN(chunk); chunk = chunk_next; } diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c index 6dc0203ead2..49c7fb19b7d 100644 --- a/source/blender/blenlib/intern/expr_pylike_eval.c +++ b/source/blender/blenlib/intern/expr_pylike_eval.c @@ -164,7 +164,8 @@ eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, #define FAIL_IF(condition) \ if (condition) { \ return EXPR_PYLIKE_FATAL_ERROR; \ - } + } \ + ((void)0) /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */ FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000); @@ -391,7 +392,8 @@ static BuiltinOpDef builtin_ops[] = { #define CHECK_ERROR(condition) \ if (!(condition)) { \ return false; \ - } + } \ + ((void)0) /* For simplicity simple token types are represented by their own character; * these are special identifiers for multi-character tokens. */ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index e09fae7d140..6ac1ac776b3 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -931,6 +931,13 @@ float determinant_m3_array(const float m[3][3]) m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); } +float determinant_m4_mat3_array(const float m[4][4]) +{ + return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - + m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) + + m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1])); +} + bool invert_m3_ex(float m[3][3], const float epsilon) { float tmp[3][3]; @@ -1011,6 +1018,81 @@ bool invert_m4(float m[4][4]) return success; } +/** + * Computes the inverse of mat and puts it in inverse. + * Uses Gaussian Elimination with partial (maximal column) pivoting. + * \return true on success (i.e. can always find a pivot) and false on failure. + * Mark Segal - 1992. + * + * \note this is less performant than #EIG_invert_m4_m4 (Eigen), but e.g. + * for non-invertible scale matrices, findinging a partial solution can + * be useful to have a valid local transform center, see T57767. + */ +bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4]) +{ + if (EIG_invert_m4_m4(inverse, mat)) { + return true; + } + + int i, j, k; + double temp; + float tempmat[4][4]; + float max; + int maxj; + + BLI_assert(inverse != mat); + + /* Set inverse to identity */ + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + inverse[i][j] = 0; + for (i = 0; i < 4; i++) + inverse[i][i] = 1; + + /* Copy original matrix so we don't mess it up */ + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + tempmat[i][j] = mat[i][j]; + + for (i = 0; i < 4; i++) { + /* Look for row with max pivot */ + max = fabsf(tempmat[i][i]); + maxj = i; + for (j = i + 1; j < 4; j++) { + if (fabsf(tempmat[j][i]) > max) { + max = fabsf(tempmat[j][i]); + maxj = j; + } + } + /* Swap rows if necessary */ + if (maxj != i) { + for (k = 0; k < 4; k++) { + SWAP(float, tempmat[i][k], tempmat[maxj][k]); + SWAP(float, inverse[i][k], inverse[maxj][k]); + } + } + + if (UNLIKELY(tempmat[i][i] == 0.0f)) { + return false; /* No non-zero pivot */ + } + temp = (double)tempmat[i][i]; + for (k = 0; k < 4; k++) { + tempmat[i][k] = (float)((double)tempmat[i][k] / temp); + inverse[i][k] = (float)((double)inverse[i][k] / temp); + } + for (j = 0; j < 4; j++) { + if (j != i) { + temp = tempmat[j][i]; + for (k = 0; k < 4; k++) { + tempmat[j][k] -= (float)((double)tempmat[i][k] * temp); + inverse[j][k] -= (float)((double)inverse[i][k] * temp); + } + } + } + } + return true; +} + bool invert_m4_m4(float inverse[4][4], const float mat[4][4]) { /* Use optimized matrix inverse from Eigen, since performance @@ -1641,9 +1723,26 @@ void mat4_to_size(float size[3], const float mat[4][4]) size[2] = len_v3(mat[2]); } -/* this gets the average scale of a matrix, only use when your scaling +/** + * This computes the overall volume scale factor of a transformation matrix. + * For an orthogonal matrix, it is the product of all three scale values. + * Returns a negative value if the transform is flipped by negative scale. + */ +float mat3_to_volume_scale(const float mat[3][3]) +{ + return determinant_m3_array(mat); +} + +float mat4_to_volume_scale(const float mat[4][4]) +{ + return determinant_m4_mat3_array(mat); +} + +/** + * This gets the average scale of a matrix, only use when your scaling * data that has no idea of scale axis, examples are bone-envelope-radius - * and curve radius */ + * and curve radius. + */ float mat3_to_scale(const float mat[3][3]) { /* unit length vector */ @@ -2003,10 +2102,12 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]) equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3])); } -/* make a 4x4 matrix out of 3 transform components */ -/* matrices are made in the order: scale * rot * loc */ -/* TODO: need to have a version that allows for rotation order... */ - +/** + * Make a 4x4 matrix out of 3 transform components. + * Matrices are made in the order: `scale * rot * loc` + * + * TODO: need to have a version that allows for rotation order... + */ void loc_eul_size_to_mat4(float mat[4][4], const float loc[3], const float eul[3], @@ -2031,9 +2132,10 @@ void loc_eul_size_to_mat4(float mat[4][4], mat[3][2] = loc[2]; } -/* make a 4x4 matrix out of 3 transform components */ - -/* matrices are made in the order: scale * rot * loc */ +/** + * Make a 4x4 matrix out of 3 transform components. + * Matrices are made in the order: `scale * rot * loc` + */ void loc_eulO_size_to_mat4(float mat[4][4], const float loc[3], const float eul[3], @@ -2059,9 +2161,10 @@ void loc_eulO_size_to_mat4(float mat[4][4], mat[3][2] = loc[2]; } -/* make a 4x4 matrix out of 3 transform components */ - -/* matrices are made in the order: scale * rot * loc */ +/** + * Make a 4x4 matrix out of 3 transform components. + * Matrices are made in the order: `scale * rot * loc` + */ void loc_quat_size_to_mat4(float mat[4][4], const float loc[3], const float quat[4], diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index 5000b3df92b..99288abb38c 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -643,6 +643,25 @@ void BLI_rctf_scale(rctf *rect, const float scale) rect->ymax = cent_y + size_y_half; } +void BLI_rctf_pad_y(rctf *rect, + const float boundary_size, + const float pad_min, + const float pad_max) +{ + BLI_assert(pad_max >= 0.0f); + BLI_assert(pad_min >= 0.0f); + BLI_assert(boundary_size > 0.0f); + + float total_pad = pad_max + pad_min; + if (total_pad == 0.0f) { + return; + } + + float total_extend = BLI_rctf_size_y(rect) * total_pad / (boundary_size - total_pad); + rect->ymax += total_extend * (pad_max / total_pad); + rect->ymin -= total_extend * (pad_min / total_pad); +} + void BLI_rctf_interp(rctf *rect, const rctf *rect_a, const rctf *rect_b, const float fac) { const float ifac = 1.0f - fac; diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c index d23b45a3937..3348912f02a 100644 --- a/source/blender/blenlib/intern/system.c +++ b/source/blender/blenlib/intern/system.c @@ -18,10 +18,12 @@ * \ingroup bli */ +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BLI_system.h" #include "BLI_string.h" @@ -189,3 +191,20 @@ void BLI_hostname_get(char *buffer, size_t bufsize) } #endif } + +size_t BLI_system_memory_max_in_megabytes(void) +{ + /* Maximum addressable bytes on this platform. + * + * NOTE: Due to the shift arithmetic this is a half of the memory. */ + const size_t limit_bytes_half = (((size_t)1) << ((sizeof(size_t) * 8) - 1)); + /* Convert it to megabytes and return. */ + return (limit_bytes_half >> 20) * 2; +} + +int BLI_system_memory_max_in_megabytes_int(void) +{ + const size_t limit_megabytes = BLI_system_memory_max_in_megabytes(); + /* NOTE: The result will fit into integer. */ + return (int)min_zz(limit_megabytes, (size_t)INT_MAX); +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7f62369647a..5edba272cd4 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2537,7 +2537,7 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, /* corrupt file! */ printf("%s: found non group data, freeing type %d!\n", caller_func_id, (*prop)->type); /* don't risk id, data's likely corrupt. */ - // IDP_FreeProperty(*prop); + // IDP_FreePropertyContent(*prop); *prop = NULL; } } @@ -3763,9 +3763,6 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) } } - /* avoid string */ - GHash *bone_hash = BKE_armature_bone_from_name_map(arm); - if (ob->proxy) { /* sync proxy layer */ if (pose->proxy_layer) { @@ -3774,7 +3771,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) /* sync proxy active bone */ if (pose->proxy_act_bone[0]) { - Bone *bone = BLI_ghash_lookup(bone_hash, pose->proxy_act_bone); + Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone); if (bone) { arm->act_bone = bone; } @@ -3784,7 +3781,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { lib_link_constraints(fd, (ID *)ob, &pchan->constraints); - pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name); + pchan->bone = BKE_armature_find_bone_name(arm, pchan->name); IDP_LibLinkProperty(pchan->prop, fd); @@ -3799,8 +3796,6 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) } } - BLI_ghash_free(bone_hash, NULL, NULL); - if (rebuild) { DEG_id_tag_update_ex( bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); @@ -3858,6 +3853,7 @@ static void direct_link_armature(FileData *fd, bArmature *arm) Bone *bone; link_list(fd, &arm->bonebase); + arm->bonehash = NULL; arm->edbo = NULL; arm->adt = newdataadr(fd, arm->adt); @@ -3869,6 +3865,8 @@ static void direct_link_armature(FileData *fd, bArmature *arm) arm->act_bone = newdataadr(fd, arm->act_bone); arm->act_edbone = NULL; + + BKE_armature_bone_hash_make(arm); } /** \} */ @@ -3884,9 +3882,10 @@ static void lib_link_camera(FileData *fd, Main *main) IDP_LibLinkProperty(ca->id.properties, fd); lib_link_animdata(fd, &ca->id, ca->adt); - ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system + ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); /* deprecated, for versioning */ - ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); + ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); /* deprecated, for versioning */ + ca->dof.focus_object = newlibadr(fd, ca->id.lib, ca->dof.focus_object); for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) { bgpic->ima = newlibadr_us(fd, ca->id.lib, bgpic->ima); @@ -6629,6 +6628,13 @@ static void direct_link_paint(FileData *fd, const Scene *scene, Paint *p) p->tool_slots = newdataadr(fd, p->tool_slots); + /* Workaround for invalid data written in older versions. */ + const size_t expected_size = sizeof(PaintToolSlot) * p->tool_slots_len; + if (p->tool_slots && MEM_allocN_len(p->tool_slots) < expected_size) { + MEM_freeN(p->tool_slots); + p->tool_slots = MEM_callocN(expected_size, "PaintToolSlot"); + } + BKE_paint_runtime_init(scene->toolsettings, p); } @@ -7101,7 +7107,6 @@ static void direct_link_panel_list(FileData *fd, ListBase *lb) link_list(fd, lb); for (Panel *pa = lb->first; pa; pa = pa->next) { - pa->paneltab = newdataadr(fd, pa->paneltab); pa->runtime_flag = 0; pa->activedata = NULL; pa->type = NULL; @@ -9602,6 +9607,9 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) /* Don't read the active app template, use the default one. */ user->app_template[0] = '\0'; + /* Clear runtime data. */ + user->runtime.is_dirty = false; + /* free fd->datamap again */ oldnewmap_free_unused(fd->datamap); oldnewmap_clear(fd->datamap); @@ -9622,14 +9630,17 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) ListBase mainlist = {NULL, NULL}; bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata"); - bfd->main = BKE_main_new(); - BLI_addtail(&mainlist, bfd->main); - fd->mainlist = &mainlist; + bfd->main = BKE_main_new(); bfd->main->versionfile = fd->fileversion; bfd->type = BLENFILETYPE_BLEND; - BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name)); + + if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) { + BLI_addtail(&mainlist, bfd->main); + fd->mainlist = &mainlist; + BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name)); + } if (G.background) { /* We only read & store .blend thumbnail in background mode @@ -9707,45 +9718,52 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) /* do before read_libraries, but skip undo case */ if (fd->memfile == NULL) { - do_versions(fd, NULL, bfd->main); - do_versions_userdef(fd, bfd); + if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) { + do_versions(fd, NULL, bfd->main); + } + + if ((fd->skip_flags & BLO_READ_SKIP_USERDEF) == 0) { + do_versions_userdef(fd, bfd); + } } - read_libraries(fd, &mainlist); + if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) { + read_libraries(fd, &mainlist); - blo_join_main(&mainlist); + blo_join_main(&mainlist); - lib_link_all(fd, bfd->main); + lib_link_all(fd, bfd->main); - /* Skip in undo case. */ - if (fd->memfile == NULL) { - /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ - blo_split_main(&mainlist, bfd->main); - for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) { - BLI_assert(mainvar->versionfile != 0); - do_versions_after_linking(mainvar); - } - blo_join_main(&mainlist); + /* Skip in undo case. */ + if (fd->memfile == NULL) { + /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ + blo_split_main(&mainlist, bfd->main); + for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) { + BLI_assert(mainvar->versionfile != 0); + do_versions_after_linking(mainvar); + } + blo_join_main(&mainlist); - /* After all data has been read and versioned, uses LIB_TAG_NEW. */ - ntreeUpdateAllNew(bfd->main); - } + /* After all data has been read and versioned, uses LIB_TAG_NEW. */ + ntreeUpdateAllNew(bfd->main); + } - BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false); + BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false); - /* Now that all our data-blocks are loaded, - * we can re-generate overrides from their references. */ - if (fd->memfile == NULL) { - /* Do not apply in undo case! */ - BKE_main_override_static_update(bfd->main); - } + /* Now that all our data-blocks are loaded, + * we can re-generate overrides from their references. */ + if (fd->memfile == NULL) { + /* Do not apply in undo case! */ + BKE_main_override_static_update(bfd->main); + } - BKE_collections_after_lib_link(bfd->main); + BKE_collections_after_lib_link(bfd->main); - fix_relpaths_library(fd->relabase, - bfd->main); /* make all relative paths, relative to the open blend file */ + /* Make all relative paths, relative to the open blend file. */ + fix_relpaths_library(fd->relabase, bfd->main); - link_global(fd, bfd); /* as last */ + link_global(fd, bfd); /* as last */ + } fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */ @@ -10757,6 +10775,15 @@ static void expand_camera(FileData *fd, Main *mainvar, Camera *ca) { expand_doit(fd, mainvar, ca->ipo); // XXX deprecated - old animation system + for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) { + if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { + expand_doit(fd, mainvar, bgpic->ima); + } + else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { + expand_doit(fd, mainvar, bgpic->ima); + } + } + if (ca->adt) { expand_animdata(fd, mainvar, ca->adt); } diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index face4b61d1e..7b239105251 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -285,8 +285,8 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) memcpy(&ar->v2d, &sipo->v2d, sizeof(View2D)); /* init mainarea view2d */ - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.min[0] = FLT_MIN; ar->v2d.min[1] = FLT_MIN; @@ -304,7 +304,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f; ar->v2d.tot.ymax = 0.0f; - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.align = V2D_ALIGN_NO_POS_Y; ar->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL; @@ -330,7 +330,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.align = V2D_ALIGN_NO_POS_Y; @@ -349,8 +349,8 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) SpaceSeq *sseq = (SpaceSeq *)sl; memcpy(&ar->v2d, &sseq->v2d, sizeof(View2D)); - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.align = V2D_ALIGN_NO_NEG_Y; ar->v2d.flag |= V2D_IS_INITIALISED; break; diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 77ef27182f2..7b0aab99aea 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1808,6 +1808,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) Image *image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima); if (image && (image->flag & IMA_DO_PREMUL) == 0) { + const int IMA_IGNORE_ALPHA = (1 << 12); image->flag |= IMA_IGNORE_ALPHA; } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index f9f87731197..c4e3390d65f 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -421,10 +421,13 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene) Collection *collection = BKE_collection_add(bmain, collection_master, name); collection->id.lib = scene->id.lib; + if (collection->id.lib != NULL) { + collection->id.tag |= LIB_TAG_INDIRECT; + } collections[layer] = collection; if (!(scene->lay & (1 << layer))) { - collection->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER; + collection->flag |= COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER; } } @@ -692,6 +695,26 @@ static void do_version_bbone_scale_animdata_cb(ID *UNUSED(id), } } +static void do_version_constraints_maintain_volume_mode_uniform(ListBase *lb) +{ + for (bConstraint *con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SAMEVOL) { + bSameVolumeConstraint *data = (bSameVolumeConstraint *)con->data; + data->mode = SAMEVOL_UNIFORM; + } + } +} + +static void do_version_constraints_copy_scale_power(ListBase *lb) +{ + for (bConstraint *con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SIZELIKE) { + bSizeLikeConstraint *data = (bSizeLikeConstraint *)con->data; + data->power = 1.0f; + } + } +} + void do_versions_after_linking_280(Main *bmain) { bool use_collection_compat_28 = true; @@ -705,7 +728,7 @@ void do_versions_after_linking_280(Main *bmain) /* Add fake user for all existing groups. */ id_fake_user_set(&collection->id); - if (collection->flag & (COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER)) { + if (collection->flag & (COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER)) { continue; } @@ -731,7 +754,8 @@ void do_versions_after_linking_280(Main *bmain) char name[MAX_ID_NAME]; BLI_snprintf(name, sizeof(name), DATA_("Hidden %d"), coll_idx + 1); *collection_hidden = BKE_collection_add(bmain, collection, name); - (*collection_hidden)->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER; + (*collection_hidden)->flag |= COLLECTION_RESTRICT_VIEWPORT | + COLLECTION_RESTRICT_RENDER; } BKE_collection_object_add(bmain, *collection_hidden, ob); @@ -826,7 +850,6 @@ void do_versions_after_linking_280(Main *bmain) for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) { if (srl->prop) { IDP_FreeProperty(srl->prop); - MEM_freeN(srl->prop); } BKE_freestyle_config_free(&srl->freestyleConfig, true); } @@ -1061,6 +1084,32 @@ void do_versions_after_linking_280(Main *bmain) BKE_rigidbody_constraints_collection_validate(scene, rbw); } } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { + /* Unify DOF settings (EEVEE part only) */ + const int SCE_EEVEE_DOF_ENABLED = (1 << 7); + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE)) { + if (scene->eevee.flag & SCE_EEVEE_DOF_ENABLED) { + Object *cam_ob = scene->camera; + if (cam_ob && cam_ob->type == OB_CAMERA) { + Camera *cam = cam_ob->data; + cam->dof.flag |= CAM_DOF_ENABLED; + } + } + } + } + + LISTBASE_FOREACH (Camera *, camera, &bmain->cameras) { + camera->dof.focus_object = camera->dof_ob; + camera->dof.focus_distance = camera->dof_distance; + camera->dof.aperture_fstop = camera->gpu_dof.fstop; + camera->dof.aperture_rotation = camera->gpu_dof.rotation; + camera->dof.aperture_ratio = camera->gpu_dof.ratio; + camera->dof.aperture_blades = camera->gpu_dof.num_blades; + camera->dof_ob = NULL; + } + } } /* NOTE: This version patch is intended for versions < 2.52.2, @@ -1290,6 +1339,16 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* 2.79 style Maintain Volume mode. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + do_version_constraints_maintain_volume_mode_uniform(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + do_version_constraints_maintain_volume_mode_uniform(&pchan->constraints); + } + } + } } #ifdef USE_COLLECTION_COMPAT_28 @@ -1637,10 +1696,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } \ } \ ((void)0) - + const int SCE_EEVEE_DOF_ENABLED = (1 << 7); IDProperty *props = IDP_GetPropertyFromGroup(scene->layer_properties, RE_engine_id_BLENDER_EEVEE); - EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED); + // EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED); EEVEE_GET_BOOL(props, volumetric_lights, SCE_EEVEE_VOLUMETRIC_LIGHTS); EEVEE_GET_BOOL(props, volumetric_shadows, SCE_EEVEE_VOLUMETRIC_SHADOWS); EEVEE_GET_BOOL(props, gtao_enable, SCE_EEVEE_GTAO_ENABLED); @@ -1651,7 +1710,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) EEVEE_GET_BOOL(props, motion_blur_enable, SCE_EEVEE_MOTION_BLUR_ENABLED); EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH); EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION); - EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED); + // EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED); EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO); EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED); EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION); @@ -1705,7 +1764,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Cleanup. */ IDP_FreeProperty(scene->layer_properties); - MEM_freeN(scene->layer_properties); scene->layer_properties = NULL; #undef EEVEE_GET_FLOAT_ARRAY @@ -2816,7 +2874,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - mat->blend_flag &= ~(MA_BL_FLAG_UNUSED_2); + mat->blend_flag &= ~(1 << 2); /* UNUSED */ } } @@ -3287,6 +3345,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "char", "render_aa")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + scene->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; + scene->display.viewport_aa = SCE_DISPLAY_AA_FXAA; + } + } /* Split bbone_scalein/bbone_scaleout into x and y fields. */ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scale_out_y")) { @@ -3321,6 +3385,108 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 280, 61)) { + /* Added a power option to Copy Scale. */ + if (!DNA_struct_elem_find(fd->filesdna, "bSizeLikeConstraint", "float", "power")) { + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + do_version_constraints_copy_scale_power(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + do_version_constraints_copy_scale_power(&pchan->constraints); + } + } + } + } + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (ELEM(sl->spacetype, SPACE_CLIP, SPACE_GRAPH, SPACE_SEQ)) { + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + + ARegion *ar = NULL; + if (sl->spacetype == SPACE_CLIP) { + if (((SpaceClip *)sl)->view == SC_VIEW_GRAPH) { + ar = do_versions_find_region(regionbase, RGN_TYPE_PREVIEW); + } + } + else { + ar = do_versions_find_region(regionbase, RGN_TYPE_WINDOW); + } + + if (ar != NULL) { + ar->v2d.scroll &= ~V2D_SCROLL_LEFT; + ar->v2d.scroll |= V2D_SCROLL_RIGHT; + } + } + } + } + } + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *area = screen->areabase.first; area; area = area->next) { + for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype != SPACE_OUTLINER) { + continue; + } + SpaceOutliner *so = (SpaceOutliner *)sl; + so->filter &= ~SO_FLAG_UNUSED_1; + so->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { + LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { + arm->flag &= ~(ARM_FLAG_UNUSED_7 | ARM_FLAG_UNUSED_9); + } + + /* Initializes sun lights with the new angular diameter property */ + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "sun_angle")) { + LISTBASE_FOREACH (Light *, light, &bmain->lights) { + light->sun_angle = 2.0f * atanf(light->area_size); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 70)) { + /* New image alpha modes. */ + LISTBASE_FOREACH (Image *, image, &bmain->images) { + const int IMA_IGNORE_ALPHA = (1 << 12); + if (image->flag & IMA_IGNORE_ALPHA) { + image->alpha_mode = IMA_ALPHA_IGNORE; + image->flag &= ~IMA_IGNORE_ALPHA; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 71)) { + /* This assumes the Blender builtin config. Depending on the OCIO + * environment variable for versioning is weak, and these deprecated view + * transforms and look names don't seem to exist in other commonly used + * OCIO configs so .blend files created for those would be unaffected. */ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + ColorManagedViewSettings *view_settings; + view_settings = &scene->view_settings; + + if (STREQ(view_settings->view_transform, "Default")) { + STRNCPY(view_settings->view_transform, "Standard"); + } + else if (STREQ(view_settings->view_transform, "RRT") || + STREQ(view_settings->view_transform, "Film")) { + STRNCPY(view_settings->view_transform, "Filmic"); + } + else if (STREQ(view_settings->view_transform, "Log")) { + STRNCPY(view_settings->view_transform, "Filmic Log"); + } + + if (STREQ(view_settings->look, "Filmic - Base Contrast")) { + STRNCPY(view_settings->look, "None"); + } + } + } + { /* Versioning code until next subversion bump goes here. */ } diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index 023bd685352..9bfbf4477ab 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -32,12 +32,15 @@ #include "DNA_light_types.h" #include "DNA_node_types.h" #include "DNA_particle_types.h" +#include "DNA_camera_types.h" #include "BKE_colortools.h" #include "BKE_idprop.h" #include "BKE_main.h" #include "BKE_node.h" +#include "IMB_colormanagement.h" + #include "BLO_readfile.h" #include "readfile.h" @@ -47,6 +50,12 @@ static float *cycles_node_socket_float_value(bNodeSocket *socket) return &socket_data->value; } +static float *cycles_node_socket_rgba_value(bNodeSocket *socket) +{ + bNodeSocketValueRGBA *socket_data = socket->default_value; + return socket_data->value; +} + static IDProperty *cycles_properties_from_ID(ID *id) { IDProperty *idprop = IDP_GetProperties(id, false); @@ -59,12 +68,26 @@ static float cycles_property_float(IDProperty *idprop, const char *name, float d return (prop) ? IDP_Float(prop) : default_value; } +static float cycles_property_int(IDProperty *idprop, const char *name, int default_value) +{ + IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); + return (prop) ? IDP_Int(prop) : default_value; +} + static bool cycles_property_boolean(IDProperty *idprop, const char *name, bool default_value) { IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_INT); return (prop) ? IDP_Int(prop) : default_value; } +static const char *cycles_property_string(IDProperty *idprop, + const char *name, + const char *default_value) +{ + IDProperty *prop = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_STRING); + return (prop) ? IDP_String(prop) : default_value; +} + static void displacement_node_insert(bNodeTree *ntree) { bool need_update = false; @@ -262,6 +285,114 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree) } } +static void image_node_colorspace(bNode *node) +{ + if (node->id == NULL) { + return; + } + + int color_space; + if (node->type == SH_NODE_TEX_IMAGE) { + NodeTexImage *tex = node->storage; + color_space = tex->color_space; + } + else if (node->type == SH_NODE_TEX_ENVIRONMENT) { + NodeTexEnvironment *tex = node->storage; + color_space = tex->color_space; + } + else { + return; + } + + const int SHD_COLORSPACE_NONE = 0; + Image *image = (Image *)node->id; + if (color_space == SHD_COLORSPACE_NONE) { + STRNCPY(image->colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA)); + } +} + +static void light_emission_node_to_energy(Light *light, float *energy, float color[3]) +{ + *energy = 1.0; + copy_v3_fl(color, 1.0f); + + /* If nodetree has animation or drivers, don't try to convert. */ + bNodeTree *ntree = light->nodetree; + if (ntree == NULL || ntree->adt) { + return; + } + + /* Find emission node */ + bNode *output_node = ntreeShaderOutputNode(ntree, SHD_OUTPUT_CYCLES); + if (output_node == NULL) { + return; + } + + bNode *emission_node = NULL; + for (bNodeLink *link = ntree->links.first; link; link = link->next) { + if (link->tonode == output_node && link->fromnode->type == SH_NODE_EMISSION) { + emission_node = link->fromnode; + break; + } + } + + if (emission_node == NULL) { + return; + } + + /* Don't convert if anything is linked */ + bNodeSocket *strength_socket = nodeFindSocket(emission_node, SOCK_IN, "Strength"); + bNodeSocket *color_socket = nodeFindSocket(emission_node, SOCK_IN, "Color"); + + if ((strength_socket->flag & SOCK_IN_USE) || (color_socket->flag & SOCK_IN_USE)) { + return; + } + + float *strength_value = cycles_node_socket_float_value(strength_socket); + float *color_value = cycles_node_socket_rgba_value(color_socket); + + *energy = *strength_value; + copy_v3_v3(color, color_value); + + *strength_value = 1.0f; + copy_v4_fl(color_value, 1.0f); + light->use_nodes = false; +} + +static void light_emission_unify(Light *light, const char *engine) +{ + if (light->type != LA_SUN) { + light->energy *= 100.0f; + } + + /* Attempt to extract constant energy and color from nodes. */ + bool use_nodes = light->use_nodes; + float energy, color[3]; + light_emission_node_to_energy(light, &energy, color); + + if (STREQ(engine, "CYCLES")) { + if (use_nodes) { + /* Energy extracted from nodes */ + light->energy = energy; + copy_v3_v3(&light->r, color); + } + else { + /* Default cycles multipliers if there are no nodes */ + if (light->type == LA_SUN) { + light->energy = 1.0f; + } + else { + light->energy = 100.0f; + } + } + } + else { + /* Disable nodes if scene was configured for Eevee */ + light->use_nodes = false; + } +} + void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain) { /* Particle shape shared with Eevee. */ @@ -280,11 +411,25 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm } } } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 68)) { + /* Unify Cycles and Eevee film transparency. */ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (STREQ(scene->r.engine, RE_engine_id_CYCLES)) { + IDProperty *cscene = cycles_properties_from_ID(&scene->id); + if (cscene) { + bool cycles_film_transparency = cycles_property_boolean( + cscene, "film_transparent", false); + scene->r.alphamode = cycles_film_transparency ? R_ALPHAPREMUL : R_ADDSKY; + } + } + } + } } void do_versions_after_linking_cycles(Main *bmain) { - if (!MAIN_VERSION_ATLEAST(bmain, 280, 5)) { + if (!MAIN_VERSION_ATLEAST(bmain, 280, 66)) { /* Shader node tree changes. After lib linking so we have all the typeinfo * pointers and updated sockets and we can use the high level node API to * manipulate nodes. */ @@ -326,7 +471,64 @@ void do_versions_after_linking_cycles(Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 279, 5)) { ambient_occlusion_node_relink(ntree); } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 66)) { + for (bNode *node = ntree->nodes.first; node; node = node->next) { + image_node_colorspace(node); + } + } } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 64)) { + /* Unfiy Cycles and Eevee settings. */ + Scene *scene = bmain->scenes.first; + const char *engine = (scene) ? scene->r.engine : "CYCLES"; + + for (Light *light = bmain->lights.first; light; light = light->id.next) { + light_emission_unify(light, engine); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { + /* Unify Cycles and Eevee depth of field. */ + Scene *scene = bmain->scenes.first; + const char *engine = (scene) ? scene->r.engine : "CYCLES"; + + if (STREQ(engine, RE_engine_id_CYCLES)) { + for (Camera *camera = bmain->cameras.first; camera; camera = camera->id.next) { + IDProperty *ccamera = cycles_properties_from_ID(&camera->id); + if (ccamera) { + const char *aperture_type = cycles_property_string(ccamera, "aperture_type", "RADIUS"); + + camera->dof.aperture_fstop = cycles_property_float(ccamera, "aperture_fstop", 5.6f); + camera->dof.aperture_blades = cycles_property_int(ccamera, "aperture_blades", 0); + camera->dof.aperture_rotation = cycles_property_float(ccamera, "aperture_rotation", 0.0); + camera->dof.aperture_ratio = cycles_property_float(ccamera, "aperture_ratio", 1.0f); + camera->dof.flag |= CAM_DOF_ENABLED; + + float aperture_size = cycles_property_float(ccamera, "aperture_size", 0.0f); + + if (STREQ(aperture_type, "RADIUS") && aperture_size > 0.0f) { + if (camera->type == CAM_ORTHO) { + camera->dof.aperture_fstop = 1.0f / (2.0f * aperture_size); + } + else { + camera->dof.aperture_fstop = (camera->lens * 1e-3f) / (2.0f * aperture_size); + } + + continue; + } + } + + /* No depth of field, set default settings. */ + camera->dof.aperture_fstop = 2.8f; + camera->dof.aperture_blades = 0; + camera->dof.aperture_rotation = 0.0f; + camera->dof.aperture_ratio = 1.0f; + camera->dof.flag &= ~CAM_DOF_ENABLED; + } + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 45c2a50cc3f..aafff7b1250 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -24,7 +24,9 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" +#include "BLI_system.h" +#include "DNA_camera_types.h" #include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" @@ -68,20 +70,21 @@ void BLO_update_defaults_userpref_blend(void) U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE; #endif + /* Transform tweak with single click and drag. */ + U.flag |= USER_RELEASECONFIRM; + + U.flag &= ~(USER_DEVELOPER_UI | USER_TOOLTIPS_PYTHON); + /* Clear addon preferences. */ for (bAddon *addon = U.addons.first, *addon_next; addon != NULL; addon = addon_next) { addon_next = addon->next; if (addon->prop) { IDP_FreeProperty(addon->prop); - MEM_freeN(addon->prop); addon->prop = NULL; } } - /* Transform tweak with single click and drag. */ - U.flag |= USER_RELEASECONFIRM; - /* Ignore the theme saved in the blend file, * instead use the theme from 'userdef_default_theme.c' */ { @@ -92,10 +95,13 @@ void BLO_update_defaults_userpref_blend(void) /* Leave temp directory empty, will then get appropriate value per OS. */ U.tempdir[0] = '\0'; + /* System-specific fonts directory. */ + BKE_appdir_font_folder_default(U.fontdir); + /* Only enable tooltips translation by default, * without actually enabling translation itself, for now. */ U.transopts = USER_TR_TOOLTIPS; - U.memcachelimit = 4096; + U.memcachelimit = min_ii(BLI_system_memory_max_in_megabytes_int() / 2, 4096); /* Auto perspective. */ U.uiflag |= USER_AUTOPERSP; @@ -153,9 +159,16 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - /* Remove all stored panels, we want to use defaults - * (order, open/closed) as defined by UI code here! */ - BKE_area_region_panels_free(&ar->panels); + if (builtin_template) { + /* Remove all stored panels, we want to use defaults + * (order, open/closed) as defined by UI code here! */ + BKE_area_region_panels_free(&ar->panels); + BLI_freelistN(&ar->panels_category_active); + + /* Reset size so it uses consistent defaults from the region types. */ + ar->sizex = 0; + ar->sizey = 0; + } /* some toolbars have been saved as initialized, * we don't want them to have odd zoom-level or scrolling set, see: T47047 */ @@ -279,17 +292,46 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - /* Hide channels in timelines. */ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - SpaceAction *saction = (sa->spacetype == SPACE_ACTION) ? sa->spacedata.first : NULL; + if (sa->spacetype == SPACE_ACTION) { + /* Show marker lines, hide channels and collapse summary in timelines. */ + SpaceAction *saction = sa->spacedata.first; + saction->flag |= SACTION_SHOW_MARKER_LINES; - if (saction && saction->mode == SACTCONT_TIMELINE) { - for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_CHANNELS) { - ar->flag |= RGN_FLAG_HIDDEN; + if (saction->mode == SACTCONT_TIMELINE) { + saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED; + + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_CHANNELS) { + ar->flag |= RGN_FLAG_HIDDEN; + } } } } + else if (sa->spacetype == SPACE_GRAPH) { + SpaceGraph *sipo = sa->spacedata.first; + sipo->flag |= SIPO_MARKER_LINES; + } + else if (sa->spacetype == SPACE_NLA) { + SpaceNla *snla = sa->spacedata.first; + snla->flag |= SNLA_SHOW_MARKER_LINES; + } + else if (sa->spacetype == SPACE_TEXT) { + /* Show syntax and line numbers in Script workspace text editor. */ + SpaceText *stext = sa->spacedata.first; + stext->showsyntax = true; + stext->showlinenrs = true; + } + else if (sa->spacetype == SPACE_VIEW3D) { + /* Screen space cavity by default for faster performance. */ + View3D *v3d = sa->spacedata.first; + v3d->shading.cavity_type = V3D_SHADING_CAVITY_CURVATURE; + v3d->shading.light = V3D_LIGHTING_MATCAP; + } + else if (sa->spacetype == SPACE_CLIP) { + SpaceClip *sclip = sa->spacedata.first; + sclip->around = V3D_AROUND_CENTER_MEDIAN; + } } } @@ -333,8 +375,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) scene->r.displaymode = R_OUTPUT_WINDOW; if (app_template && STREQ(app_template, "Video_Editing")) { - /* Filmic is too slow, use default until it is optimized. */ - STRNCPY(scene->view_settings.view_transform, "Default"); + /* Filmic is too slow, use standard until it is optimized. */ + STRNCPY(scene->view_settings.view_transform, "Standard"); STRNCPY(scene->view_settings.look, "None"); } else { @@ -368,6 +410,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) /* Match default for new meshes. */ mesh->smoothresh = DEG2RADF(30); } + + for (Camera *camera = bmain->cameras.first; camera; camera = camera->id.next) { + /* Initialize to a useful value. */ + camera->dof.focus_distance = 10.0f; + camera->dof.aperture_fstop = 2.8f; + } } for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 91611fe8c74..d1cb9d32212 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -19,7 +19,7 @@ * * Version patch user preferences. */ - +#define DNA_DEPRECATED_ALLOW #include <string.h> #include "BLI_math.h" @@ -28,6 +28,7 @@ #include "DNA_userdef_types.h" #include "DNA_curve_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_scene_types.h" #include "BKE_addon.h" #include "BKE_colorband.h" @@ -42,7 +43,7 @@ /* Disallow access to global userdef. */ #define U (_error_) -static void do_versions_theme(UserDef *userdef, bTheme *btheme) +static void do_versions_theme(const UserDef *userdef, bTheme *btheme) { #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver) @@ -113,13 +114,37 @@ static void do_versions_theme(UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_info.info_info); } + if (!USER_VERSION_ATLEAST(280, 64)) { + FROM_DEFAULT_V4_UCHAR(tui.icon_scene); + + if (btheme->space_view3d.obcenter_dia == 0) { + btheme->space_view3d.obcenter_dia = U_theme_default.space_view3d.obcenter_dia; + } + + FROM_DEFAULT_V4_UCHAR(space_graph.text); + FROM_DEFAULT_V4_UCHAR(space_action.text); + FROM_DEFAULT_V4_UCHAR(space_nla.text); + FROM_DEFAULT_V4_UCHAR(space_sequencer.text); + FROM_DEFAULT_V4_UCHAR(space_clip.text); + + FROM_DEFAULT_V4_UCHAR(space_graph.scrubbing_background); + FROM_DEFAULT_V4_UCHAR(space_action.scrubbing_background); + FROM_DEFAULT_V4_UCHAR(space_nla.scrubbing_background); + FROM_DEFAULT_V4_UCHAR(space_sequencer.scrubbing_background); + FROM_DEFAULT_V4_UCHAR(space_clip.scrubbing_background); + } + + if (!USER_VERSION_ATLEAST(280, 67)) { + FROM_DEFAULT_V4_UCHAR(space_outliner.selected_object); + FROM_DEFAULT_V4_UCHAR(space_outliner.active_object); + FROM_DEFAULT_V4_UCHAR(space_outliner.edited_object); + FROM_DEFAULT_V4_UCHAR(space_outliner.row_alternate); + } + /** * Include next version bump. */ { - if (btheme->space_view3d.obcenter_dia == 0) { - btheme->space_view3d.obcenter_dia = U_theme_default.space_view3d.obcenter_dia; - } } #undef FROM_DEFAULT_V4_UCHAR @@ -542,15 +567,48 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) userdef->dupflag |= USER_DUP_GPENCIL; } - /** - * Include next version bump. - */ - { + if (!USER_VERSION_ATLEAST(280, 60)) { + const float GPU_VIEWPORT_QUALITY_FXAA = 0.10f; + const float GPU_VIEWPORT_QUALITY_TAA8 = 0.25f; + const float GPU_VIEWPORT_QUALITY_TAA16 = 0.6f; + const float GPU_VIEWPORT_QUALITY_TAA32 = 0.8f; + + if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_FXAA) { + userdef->viewport_aa = SCE_DISPLAY_AA_OFF; + } + else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA8) { + userdef->viewport_aa = SCE_DISPLAY_AA_FXAA; + } + else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA16) { + userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_8; + } + else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA32) { + userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_16; + } + else { + userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_32; + } + } + + if (!USER_VERSION_ATLEAST(280, 62)) { /* (keep this block even if it becomes empty). */ if (userdef->vbotimeout == 0) { userdef->vbocollectrate = 60; userdef->vbotimeout = 120; } + + if (userdef->lookdev_sphere_size == 0) { + userdef->lookdev_sphere_size = 150; + } + + userdef->pref_flag |= USER_PREF_FLAG_SAVE; + } + + /** + * Include next version bump. + */ + { + /* pass */ } if (userdef->pixelsize == 0.0f) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 9a4e2adc0e3..6305aa95e7f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2416,7 +2416,7 @@ static void write_paint(WriteData *wd, Paint *p) if (p->cavity_curve) { write_curvemapping(wd, p->cavity_curve); } - writedata(wd, DATA, sizeof(PaintToolSlot) * p->tool_slots_len, p->tool_slots); + writestruct(wd, DATA, PaintToolSlot, p->tool_slots_len, p->tool_slots); } static void write_layer_collections(WriteData *wd, ListBase *lb) diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index cb10ec9d701..a35d10db697 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1440,7 +1440,6 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops) * Note that this is On² piece of code, * but it is not designed to be used with huge selection sets, * rather with only a few items selected at most.*/ - printf("using face history selection\n"); /* Goes from last selected to the first selected element. */ for (ese = bm->selected.last; ese; ese = ese->prev) { if (ese->htype == BM_FACE) { @@ -1473,7 +1472,6 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops) else { if (sel_faces) { /* Only select all loops of selected faces. */ - printf("using face selection\n"); BMLoop *l; BMFace *f; BMIter liter, fiter; @@ -1487,7 +1485,6 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops) } if (sel_edges) { /* Only select all loops of selected edges. */ - printf("using edge selection\n"); BMLoop *l; BMEdge *e; BMIter liter, eiter; @@ -1510,7 +1507,6 @@ static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops) } if (sel_verts) { /* Select all loops of selected verts. */ - printf("using vert selection\n"); BMLoop *l; BMVert *v; BMIter liter, viter; diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 0279e4dd23e..78e8ce04115 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -126,6 +126,13 @@ enum { BEVEL_MITER_ARC, }; +/* Normal Face Strength values */ +enum { + FACE_STRENGTH_WEAK = -16384, + FACE_STRENGTH_MEDIUM = 0, + FACE_STRENGTH_STRONG = 16384, +}; + extern const BMOpDefine *bmo_opdefines[]; extern const int bmo_opdefines_total; diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index af5ce4ed9ac..a559d13fc70 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -5222,7 +5222,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) BMIter iter; EdgeHalf *e; float weight, z; - float vert_axis[3]; + float vert_axis[3] = {0, 0, 0}; int i, ccw_test_sum; int nsel = 0; int ntot = 0; @@ -5357,7 +5357,6 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) normalize_v3(edge_dir); add_v3_v3v3(vert_axis, vert_axis, edge_dir); } - mul_v3_fl(vert_axis, 1 / ntot); } } @@ -5430,8 +5429,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) case BEVEL_AMT_WIDTH: { v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); - normalize_v3(edge_dir); - z = fabsf(2.0f * sinf(angle_normalized_v3v3(vert_axis, edge_dir))); + z = fabsf(2.0f * sinf(angle_v3v3(vert_axis, edge_dir))); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel. */ } @@ -5443,8 +5441,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) case BEVEL_AMT_DEPTH: { v2 = BM_edge_other_vert(e->e, bv->v); sub_v3_v3v3(edge_dir, bv->v->co, v2->co); - normalize_v3(edge_dir); - z = fabsf(cosf(angle_normalized_v3v3(vert_axis, edge_dir))); + z = fabsf(cosf(angle_v3v3(vert_axis, edge_dir))); if (z < BEVEL_EPSILON) { e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel. */ } diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index 2c9865bcd95..ba878a28e50 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -79,13 +79,13 @@ bool AnimationExporter::exportAnimations() { Scene *sce = export_settings.get_scene(); - LinkNode &export_set = *this->export_settings.get_export_set(); + LinkNode *export_set = this->export_settings->export_set; bool has_anim_data = bc_has_animations(sce, export_set); int animation_count = 0; if (has_anim_data) { BCObjectSet animated_subset; - BCAnimationSampler::get_animated_from_export_set(animated_subset, export_set); + BCAnimationSampler::get_animated_from_export_set(animated_subset, *export_set); animation_count = animated_subset.size(); BCAnimationSampler animation_sampler(export_settings, animated_subset); diff --git a/source/blender/collada/CameraExporter.cpp b/source/blender/collada/CameraExporter.cpp index dea0bddd941..74862c44270 100644 --- a/source/blender/collada/CameraExporter.cpp +++ b/source/blender/collada/CameraExporter.cpp @@ -93,6 +93,6 @@ bool CamerasExporter::exportBlenderProfile(COLLADASW::Camera &cm, Camera *cam) { cm.addExtraTechniqueParameter("blender", "shiftx", cam->shiftx); cm.addExtraTechniqueParameter("blender", "shifty", cam->shifty); - cm.addExtraTechniqueParameter("blender", "dof_distance", cam->dof_distance); + cm.addExtraTechniqueParameter("blender", "dof_distance", cam->dof.focus_distance); return true; } diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 320f8379c9e..60813fb951c 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -859,7 +859,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) if (et && et->isProfile("blender")) { et->setData("shiftx", &(cam->shiftx)); et->setData("shifty", &(cam->shifty)); - et->setData("dof_distance", &(cam->dof_distance)); + et->setData("dof_distance", &(cam->dof.focus_distance)); } cam->clip_start = camera->getNearClippingPlane().getValue(); cam->clip_end = camera->getFarClippingPlane().getValue(); diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index bbd0a2e0bd3..61603226dfd 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -244,20 +244,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // performs the actual writing ep.addProfileElements(); - bool twoSided = false; - if (ob->type == OB_MESH && ob->data) { - Mesh *me = (Mesh *)ob->data; - if (me->flag & ME_TWOSIDED) - twoSided = true; - } - if (twoSided) - ep.addExtraTechniqueParameter("GOOGLEEARTH", "double_sided", 1); ep.addExtraTechniques(mSW); ep.closeProfile(); - if (twoSided) - mSW->appendTextBlock( - "<extra><technique profile=\"MAX3D\"><double_sided>1</double_sided></technique></extra>"); closeEffect(); } diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp index 926d85e7fb2..c0573dcc081 100644 --- a/source/blender/collada/GeometryExporter.cpp +++ b/source/blender/collada/GeometryExporter.cpp @@ -127,11 +127,6 @@ void GeometryExporter::operator()(Object *ob) closeMesh(); - if (me->flag & ME_TWOSIDED) { - mSW->appendTextBlock( - "<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); - } - closeGeometry(); if (this->export_settings.get_include_shapekeys()) { @@ -212,11 +207,6 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb) closeMesh(); - if (me->flag & ME_TWOSIDED) { - mSW->appendTextBlock( - "<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); - } - closeGeometry(); } diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index f4837d3d358..71201c8a55c 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -61,7 +61,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) return; } - bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0; + bool is_dirty = BKE_image_is_dirty(image); ImageFormatData imageFormat; BKE_imbuf_to_image_format(&imageFormat, imbuf); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 4b85500008b..8b8c9854781 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -925,15 +925,16 @@ bool bc_has_animations(Object *ob) return false; } -bool bc_has_animations(Scene *sce, LinkNode &export_set) +bool bc_has_animations(Scene *sce, LinkNode *export_set) { LinkNode *node; + if (export_set) { + for (node = export_set; node; node = node->next) { + Object *ob = (Object *)node->link; - for (node = &export_set; node; node = node->next) { - Object *ob = (Object *)node->link; - - if (bc_has_animations(ob)) - return true; + if (bc_has_animations(ob)) + return true; + } } return false; } diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 8fe64a19401..acbf6f94add 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -227,7 +227,7 @@ extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]) extern void bc_enable_fcurves(bAction *act, char *bone_name); extern bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim); extern bool bc_is_animated(BCMatrixSampleMap &values); -extern bool bc_has_animations(Scene *sce, LinkNode &node); +extern bool bc_has_animations(Scene *sce, LinkNode *node); extern bool bc_has_animations(Object *ob); void bc_add_global_transform(Matrix &to_mat, diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp index 1f5749d782c..30a6a05ed2c 100644 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp @@ -154,7 +154,7 @@ static void FHT2D( for (i = 0; stm > 0; i++) { #define PRED(k) (((k & Nym) << Mx) + (k >> My)) for (j = PRED(i); j > i; j = PRED(j)) { - ; + /* pass */ } if (j < i) { continue; diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index aee925ad8f8..ba6b3b32d60 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -69,7 +69,6 @@ set(SRC intern/depsgraph_eval.cc intern/depsgraph_physics.cc intern/depsgraph_query.cc - intern/depsgraph_query_filter.cc intern/depsgraph_query_foreach.cc intern/depsgraph_query_iter.cc intern/depsgraph_tag.cc diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h index 9ebd5f7ffae..73e03523003 100644 --- a/source/blender/depsgraph/DEG_depsgraph_debug.h +++ b/source/blender/depsgraph/DEG_depsgraph_debug.h @@ -68,7 +68,7 @@ void DEG_debug_stats_gnuplot(const struct Depsgraph *graph, /* Compare two dependency graphs. */ bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2); -/* Check that dependnecies in the graph are really up to date. */ +/* Check that dependencies in the graph are really up to date. */ bool DEG_debug_graph_relations_validate(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene, diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 89e4958eddc..a7b5535d11a 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -20,7 +20,7 @@ /** \file * \ingroup depsgraph * - * Public API for Querying and Filtering Depsgraph. + * Public API for Querying Depsgraph. */ #ifndef __DEG_DEPSGRAPH_QUERY_H__ @@ -72,10 +72,15 @@ void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph, struct Object *object, struct CustomData_MeshMasks *r_mask); -/* Get scene the despgraph is created for. */ +/* Get scene at its evaluated state. + * + * Technically, this is a copied-on-written and fully evaluated version of the input scene. + * This function will check that the datablock has been expanded (and copied) from the original + * one. Assert will happen if it's not. */ struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph); -/* Get scene layer the despgraph is created for. */ +/* Get view layer at its evaluated state. + * This is a shortcut for accessing active view layer from evaluated scene. */ struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph); /* Get evaluated version of object for given original one. */ @@ -95,6 +100,19 @@ struct Object *DEG_get_original_object(struct Object *object); /* Get original version of given evaluated ID datablock. */ struct ID *DEG_get_original_id(struct ID *id); +/* Check whether given ID is an original, + * + * Original IDs are considered all the IDs which are not covered by copy-on-write system and are + * not out-of-main localized datablocks. */ +bool DEG_is_original_id(struct ID *id); +bool DEG_is_original_object(struct Object *object); + +/* Opposite of the above. + * + * If the datablock is not original it must be evaluated, and vice versa. */ +bool DEG_is_evaluated_id(struct ID *id); +bool DEG_is_evaluated_object(struct Object *object); + /* ************************ DEG object iterators ********************* */ enum { @@ -205,38 +223,6 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data); -/* ********************* DEG graph filtering ****************** */ - -/* ComponentKey for nodes we want to be able to evaluate in the filtered graph */ -typedef struct DEG_FilterTarget { - struct DEG_FilterTarget *next, *prev; - - struct ID *id; - /* TODO: component identifiers - Component Type, Subdata/Component Name */ -} DEG_FilterTarget; - -typedef enum eDEG_FilterQuery_Granularity { - DEG_FILTER_NODES_ALL = 0, - DEG_FILTER_NODES_NO_OPS = 1, - DEG_FILTER_NODES_ID_ONLY = 2, -} eDEG_FilterQuery_Granularity; - -typedef struct DEG_FilterQuery { - /* List of DEG_FilterTarget's */ - struct ListBase targets; - - /* Level of detail in the resulting graph */ - eDEG_FilterQuery_Granularity detail_level; -} DEG_FilterQuery; - -/* Obtain a new graph instance that only contains the subset of desired nodes - * WARNING: Do NOT pass an already filtered depsgraph through this function again, - * as we are currently unable to accurately recreate it. - */ -Depsgraph *DEG_graph_filter(const Depsgraph *depsgraph, - struct Main *bmain, - DEG_FilterQuery *query); - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index b8e0ba51019..36c6d246097 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -103,7 +103,7 @@ bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel *pchan) { BLI_assert(object->type == OB_ARMATURE); - if (pchan->bone == NULL) { + if (pchan == NULL || pchan->bone == NULL) { return false; } /* We don't really care whether segments are higher than 1 due to static user input (as in, @@ -114,7 +114,10 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel } bArmature *armature = static_cast<bArmature *>(object->data); AnimatedPropertyID property_id(&armature->id, &RNA_Bone, pchan->bone, "bbone_segments"); - return cache_->isPropertyAnimated(&armature->id, property_id); + /* Check both Object and Armature animation data, because drivers modifying Armature + * state could easily be created in the Object AnimData. */ + return cache_->isPropertyAnimated(&object->id, property_id) || + cache_->isPropertyAnimated(&armature->id, property_id); } bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 224e3212d57..040bb6cfeea 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -23,10 +23,10 @@ #pragma once -struct bPoseChannel; struct Base; struct Main; struct Object; +struct bPoseChannel; namespace DEG { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index b6822a89093..0d10bd1d3dc 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -58,6 +58,7 @@ extern "C" { #include "DNA_lightprobe_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "DNA_speaker_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" @@ -443,6 +444,9 @@ void DepsgraphNodeBuilder::build_id(ID *id) case ID_SPK: build_speaker((Speaker *)id); break; + case ID_SO: + build_sound((bSound *)id); + break; case ID_TXT: /* Not a part of dependency graph. */ break; @@ -459,7 +463,7 @@ void DepsgraphNodeBuilder::build_id(ID *id) void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection, Collection *collection) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEWPORT : COLLECTION_RESTRICT_RENDER; const bool is_collection_restricted = (collection->flag & restrict_flag); const bool is_collection_visible = !is_collection_restricted && is_parent_collection_visible_; @@ -708,7 +712,7 @@ void DepsgraphNodeBuilder::build_object_data_speaker(Object *object) { Speaker *speaker = (Speaker *)object->data; build_speaker(speaker); - add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + add_operation_node(&object->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL); } void DepsgraphNodeBuilder::build_object_transform(Object *object) @@ -1154,7 +1158,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) /* This is an exit operation for the entire key datablock, is what is used * as dependency for modifiers evaluation. */ add_operation_node(&key->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_SHAPEKEY); - /* Create per-key block properties, allowing tricky inter-dependnecies for + /* Create per-key block properties, allowing tricky inter-dependencies for * drivers evaluation. */ LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { add_operation_node( @@ -1543,9 +1547,23 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) return; } /* Placeholder so we can add relations and tag ID node for update. */ - add_operation_node(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL); build_animdata(&speaker->id); build_parameters(&speaker->id); + if (speaker->sound != NULL) { + build_sound(speaker->sound); + } +} + +void DepsgraphNodeBuilder::build_sound(bSound *sound) +{ + if (built_map_.checkIsBuiltAndTag(sound)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&sound->id, NodeType::AUDIO, OperationCode::SOUND_EVAL); + build_animdata(&sound->id); + build_parameters(&sound->id); } /* **** ID traversal callbacks functions **** */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index cf7cf1a62d8..41314380b23 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -62,6 +62,7 @@ struct bConstraint; struct bGPdata; struct bNodeTree; struct bPoseChannel; +struct bSound; struct PropertyRNA; @@ -206,6 +207,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { void build_movieclip(MovieClip *clip); void build_lightprobe(LightProbe *probe); void build_speaker(Speaker *speaker); + void build_sound(bSound *sound); /* Per-ID information about what was already in the dependency graph. * Allows to re-use certain values, to speed up following evaluation. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 60b711d76d3..b898b3d3519 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -60,7 +60,7 @@ namespace DEG { void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEWPORT : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { @@ -92,7 +92,6 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, /* Get pointer to a CoW version of scene ID. */ Scene *scene_cow = get_cow_datablock(scene); /* Scene objects. */ - int select_id = 1; /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, * but object is expected to be an original one. Hence we go into some * tricks here iterating over the view layer. */ @@ -108,7 +107,6 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, build_object(base_index, base->object, linked_state, true); ++base_index; } - base->object->select_id = select_id++; } build_layer_collections(&view_layer->layer_collections); if (scene->camera != NULL) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d3fd16d889f..5686bcac5cb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -58,6 +58,7 @@ extern "C" { #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "DNA_speaker_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" @@ -487,6 +488,9 @@ void DepsgraphRelationBuilder::build_id(ID *id) case ID_SPK: build_speaker((Speaker *)id); break; + case ID_SO: + build_sound((bSound *)id); + break; case ID_TXT: /* Not a part of dependency graph. */ break; @@ -766,9 +770,9 @@ void DepsgraphRelationBuilder::build_object_data_speaker(Object *object) { Speaker *speaker = (Speaker *)object->data; build_speaker(speaker); - OperationKey probe_key(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); - OperationKey object_key(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); - add_relation(probe_key, object_key, "Speaker Update"); + ComponentKey speaker_key(&speaker->id, NodeType::AUDIO); + ComponentKey object_key(&object->id, NodeType::AUDIO); + add_relation(speaker_key, object_key, "Speaker Update"); } void DepsgraphRelationBuilder::build_object_parent(Object *object) @@ -1321,25 +1325,47 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) { - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (GS(id->name) == ID_AR && STRPREFIX(rna_path, "bones[")) { + /* Validate the RNA path pointer just in case. */ + const char *rna_path = fcu->rna_path; + if (rna_path == NULL || rna_path[0] == '\0') { + return; + } + /* Parse the RNA path to find the target property pointer. */ + RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); + if (RNA_pointer_is_null(&property_entry_key.ptr)) { + /* TODO(sergey): This would only mean that driver is broken. + * so we can't create relation anyway. However, we need to avoid + * adding drivers which are known to be buggy to a dependency + * graph, in order to save computational power. */ + return; + } + OperationKey driver_key( + id, NodeType::PARAMETERS, OperationCode::DRIVER, rna_path, fcu->array_index); + /* If the target of the driver is a Bone property, find the Armature data, + * and then link the driver to all pose bone evaluation components that use + * it. This is necessary to provide more granular dependencies specifically for + * Bone objects, because the armature data doesn't have per-bone components, + * and generic add_relation can only add one link. */ + ID *id_ptr = (ID *)property_entry_key.ptr.id.data; + bool is_bone = id_ptr && property_entry_key.ptr.type == &RNA_Bone; + /* If the Bone property is referenced via obj.pose.bones[].bone, + * the RNA pointer refers to the Object ID, so skip to data. */ + if (is_bone && GS(id_ptr->name) == ID_OB) { + id_ptr = (ID *)((Object *)id_ptr)->data; + } + if (is_bone && GS(id_ptr->name) == ID_AR) { /* Drivers on armature-level bone settings (i.e. bbone stuff), * which will affect the evaluation of corresponding pose bones. */ - char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); - if (bone_name != NULL) { + Bone *bone = (Bone *)property_entry_key.ptr.data; + if (bone != NULL) { /* Find objects which use this, and make their eval callbacks * depend on this. */ for (IDNode *to_node : graph_->id_nodes) { if (GS(to_node->id_orig->name) == ID_OB) { Object *object = (Object *)to_node->id_orig; /* We only care about objects with pose data which use this. */ - if (object->data == id && object->pose != NULL) { - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + if (object->data == id_ptr && object->pose != NULL) { + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone->name); if (pchan != NULL) { OperationKey bone_key( &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); @@ -1348,23 +1374,18 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) } } } - /* Free temp data. */ - MEM_freeN(bone_name); - bone_name = NULL; + /* Make the driver depend on COW, similar to the generic case below. */ + if (id_ptr != id) { + ComponentKey cow_key(id_ptr, NodeType::COPY_ON_WRITE); + add_relation(cow_key, driver_key, "Driven CoW -> Driver", RELATION_CHECK_BEFORE_ADD); + } } else { fprintf(stderr, "Couldn't find armature bone name for driver path - '%s'\n", rna_path); } } - else if (rna_path != NULL && rna_path[0] != '\0') { - RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); - if (RNA_pointer_is_null(&property_entry_key.ptr)) { - /* TODO(sergey): This would only mean that driver is broken. - * so we can't create relation anyway. However, we need to avoid - * adding drivers which are known to be buggy to a dependency - * graph, in order to save computational power. */ - return; - } + else { + /* If it's not a Bone, handle the generic single dependency case. */ add_relation(driver_key, property_entry_key, "Driver -> Driven Property"); /* Similar to the case with f-curves, driver might drive a nested * datablock, which means driver execution should wait for that @@ -2046,10 +2067,11 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera) if (built_map_.checkIsBuiltAndTag(camera)) { return; } + build_animdata(&camera->id); build_parameters(&camera->id); - if (camera->dof_ob != NULL) { + if (camera->dof.focus_object != NULL) { ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); - ComponentKey dof_ob_key(&camera->dof_ob->id, NodeType::TRANSFORM); + ComponentKey dof_ob_key(&camera->dof.focus_object->id, NodeType::TRANSFORM); add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); } } @@ -2060,6 +2082,7 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) if (built_map_.checkIsBuiltAndTag(lamp)) { return; } + build_animdata(&lamp->id); build_parameters(&lamp->id); /* light's nodetree */ if (lamp->nodetree != NULL) { @@ -2246,8 +2269,8 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask) TimeSourceKey time_src_key; add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); /* Final mask evaluation. */ - ComponentKey parameters_key(mask_id, NodeType::PARAMETERS); - add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); + OperationKey mask_eval_key(mask_id, NodeType::PARAMETERS, OperationCode::MASK_EVAL); + add_relation(mask_animation_key, mask_eval_key, "Mask Animation -> Mask Eval"); } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) @@ -2276,6 +2299,21 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker) } build_animdata(&speaker->id); build_parameters(&speaker->id); + if (speaker->sound != NULL) { + build_sound(speaker->sound); + ComponentKey speaker_key(&speaker->id, NodeType::AUDIO); + ComponentKey sound_key(&speaker->sound->id, NodeType::AUDIO); + add_relation(sound_key, speaker_key, "Sound -> Speaker"); + } +} + +void DepsgraphRelationBuilder::build_sound(bSound *sound) +{ + if (built_map_.checkIsBuiltAndTag(sound)) { + return; + } + build_animdata(&sound->id); + build_parameters(&sound->id); } void DepsgraphRelationBuilder::build_copy_on_write_relations() diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 90bdb9bae65..1cf0b48128f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -78,6 +78,7 @@ struct bConstraint; struct bGPdata; struct bNodeTree; struct bPoseChannel; +struct bSound; struct PropertyRNA; @@ -264,6 +265,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { void build_movieclip(MovieClip *clip); void build_lightprobe(LightProbe *probe); void build_speaker(Speaker *speaker); + void build_sound(bSound *sound); void build_nested_datablock(ID *owner, ID *id); void build_nested_nodetree(ID *owner, bNodeTree *ntree); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index fadce685d31..f8313dc854b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -383,7 +383,13 @@ void DepsgraphRelationBuilder::build_rig(Object *object) bPoseChannel *prev, *next; BKE_pchan_bbone_handles_get(pchan, &prev, &next); if (prev) { - OperationKey prev_key(&object->id, NodeType::BONE, prev->name, OperationCode::BONE_DONE); + OperationCode opcode = OperationCode::BONE_DONE; + /* Inheriting parent roll requires access to prev handle's B-Bone properties. */ + if ((pchan->bone->flag & BONE_ADD_PARENT_END_ROLL) != 0 && + check_pchan_has_bbone_segments(object, prev)) { + opcode = OperationCode::BONE_SEGMENTS; + } + OperationKey prev_key(&object->id, NodeType::BONE, prev->name, opcode); add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments"); } if (next) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index a325544e046..b5a926ad597 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -61,7 +61,7 @@ namespace DEG { void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEWPORT : COLLECTION_RESTRICT_RENDER; for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 1238cdc70c6..fa38dce1a9f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -196,11 +196,30 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, /* Bone - generally, we just want the bone component. */ node_identifier.type = NodeType::BONE; node_identifier.component_name = pchan->name; - /* But B-Bone properties should connect to the actual operation. */ - Object *object = reinterpret_cast<Object *>(node_identifier.id); - if (!ELEM(NULL, pchan->bone, prop) && STRPREFIX(RNA_property_identifier(prop), "bbone_") && - builder_->check_pchan_has_bbone_segments(object, pchan)) { - node_identifier.operation_code = OperationCode::BONE_SEGMENTS; + /* However check property name for special handling. */ + if (prop != NULL) { + Object *object = reinterpret_cast<Object *>(node_identifier.id); + const char *prop_name = RNA_property_identifier(prop); + /* B-Bone properties should connect to the final operation. */ + if (STRPREFIX(prop_name, "bbone_")) { + if (builder_->check_pchan_has_bbone_segments(object, pchan)) { + node_identifier.operation_code = OperationCode::BONE_SEGMENTS; + } + else { + node_identifier.operation_code = OperationCode::BONE_DONE; + } + } + /* Final transform properties go to the Done node for the exit. */ + else if (STREQ(prop_name, "head") || STREQ(prop_name, "tail") || + STRPREFIX(prop_name, "matrix")) { + if (source == RNAPointerSource::EXIT) { + node_identifier.operation_code = OperationCode::BONE_DONE; + } + } + /* And other properties can always go to the entry operation. */ + else { + node_identifier.operation_code = OperationCode::BONE_LOCAL; + } } } return node_identifier; @@ -211,6 +230,12 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, * bone components, instead of using this generic code. */ node_identifier.type = NodeType::PARAMETERS; node_identifier.operation_code = OperationCode::ARMATURE_EVAL; + /* If trying to look up via an Object, e.g. due to lookup via + * obj.pose.bones[].bone in a driver attached to the Object, + * redirect to its data. */ + if (GS(node_identifier.id->name) == ID_OB) { + node_identifier.id = (ID *)((Object *)node_identifier.id)->data; + } return node_identifier; } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 068a04943e6..c4455a6e59f 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -434,6 +434,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node) case NodeType::BATCH_CACHE: case NodeType::DUPLI: case NodeType::SYNCHRONIZATION: + case NodeType::AUDIO: case NodeType::GENERIC_DATABLOCK: { ComponentNode *comp_node = (ComponentNode *)node; if (!comp_node->operations.empty()) { diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index a653366a588..02f2519b3fb 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -263,3 +263,43 @@ ID *DEG_get_original_id(ID *id) BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0); return (ID *)id->orig_id; } + +bool DEG_is_original_id(ID *id) +{ + /* Some explanation of the logic. + * + * What we want here is to be able to tell whether given ID is a result of dependency graph + * evaluation or not. + * + * All the datablocks which are created by copy-on-write mechanism will have will be tagged with + * LIB_TAG_COPIED_ON_WRITE tag. Those datablocks can not be original. + * + * Modifier stack evaluation might create special datablocks which have all the modifiers + * applied, and those will be tagged with LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT. Such datablocks + * can not be original as well. + * + * Localization is usually happening from evaluated datablock, or will have some special pointer + * magic which will make them to act as evaluated. + * + * NOTE: We conder ID evaluated if ANY of those flags is set. We do NOT require ALL of them. */ + if (id->tag & + (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT | LIB_TAG_LOCALIZED)) { + return false; + } + return true; +} + +bool DEG_is_original_object(Object *object) +{ + return DEG_is_original_id(&object->id); +} + +bool DEG_is_evaluated_id(ID *id) +{ + return !DEG_is_original_id(id); +} + +bool DEG_is_evaluated_object(Object *object) +{ + return !DEG_is_original_object(object); +} diff --git a/source/blender/depsgraph/intern/depsgraph_query_filter.cc b/source/blender/depsgraph/intern/depsgraph_query_filter.cc deleted file mode 100644 index a02ced286eb..00000000000 --- a/source/blender/depsgraph/intern/depsgraph_query_filter.cc +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2018 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup depsgraph - * - * Implementation of Graph Filtering API - */ - -#include "MEM_guardedalloc.h" - -extern "C" { -#include <string.h> // XXX: memcpy - -#include "BLI_utildefines.h" -#include "BKE_idcode.h" -#include "BKE_main.h" -#include "BLI_listbase.h" -#include "BLI_ghash.h" - -#include "BKE_action.h" // XXX: BKE_pose_channel_from_name -} /* extern "C" */ - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "RNA_access.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" -#include "DEG_depsgraph_debug.h" - -#include "intern/eval/deg_eval_copy_on_write.h" - -#include "intern/depsgraph.h" -#include "intern/depsgraph_type.h" - -#include "intern/node/deg_node.h" -#include "intern/node/deg_node_component.h" -#include "intern/node/deg_node_id.h" -#include "intern/node/deg_node_operation.h" - -/* *************************************************** */ -/* Graph Filtering Internals */ - -namespace DEG { - -/* UserData for deg_add_retained_id_cb */ -struct RetainedIdUserData { - DEG_FilterQuery *query; - GSet *set; -}; - -/* Helper for DEG_foreach_ancestor_id() - * Keep track of all ID's encountered in a set - */ -static void deg_add_retained_id_cb(ID *id, void *user_data) -{ - RetainedIdUserData *data = (RetainedIdUserData *)user_data; - BLI_gset_add(data->set, (void *)id); -} - -/* ------------------------------------------- */ - -/* Remove relations pointing to the given OperationNode */ -/* TODO: Make this part of OperationNode? */ -static void deg_unlink_opnode(Depsgraph *graph, OperationNode *op_node) -{ - vector<Relation *> all_links; - - /* Collect all inlinks to this operation */ - for (Relation *rel : op_node->inlinks) { - all_links.push_back(rel); - } - /* Collect all outlinks from this operation */ - for (Relation *rel : op_node->outlinks) { - all_links.push_back(rel); - } - - /* Delete all collected relations */ - for (Relation *rel : all_links) { - rel->unlink(); - OBJECT_GUARDED_DELETE(rel, Relation); - } - - /* Remove from entry tags */ - if (BLI_gset_haskey(graph->entry_tags, op_node)) { - BLI_gset_remove(graph->entry_tags, op_node, NULL); - } -} - -/* Remove every ID Node (and its associated subnodes, COW data) */ -static void deg_filter_remove_unwanted_ids(Depsgraph *graph, GSet *retained_ids) -{ - /* 1) First pass over ID nodes + their operations - * - Identify and tag ID's (via "custom_flags = 1") to be removed - * - Remove all links to/from operations that will be removed. */ - for (IDNode *id_node : graph->id_nodes) { - id_node->custom_flags = !BLI_gset_haskey(retained_ids, (void *)id_node->id_orig); - if (id_node->custom_flags) { - GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { - for (OperationNode *op_node : comp_node->operations) { - deg_unlink_opnode(graph, op_node); - } - } - GHASH_FOREACH_END(); - } - } - - /* 2) Remove unwanted operations from graph->operations */ - for (Depsgraph::OperationNodes::iterator it_opnode = graph->operations.begin(); - it_opnode != graph->operations.end();) { - OperationNode *op_node = *it_opnode; - IDNode *id_node = op_node->owner->owner; - if (id_node->custom_flags) { - it_opnode = graph->operations.erase(it_opnode); - } - else { - ++it_opnode; - } - } - - /* Free ID nodes that are no longer wanted - * - * This is loosely based on Depsgraph::clear_id_nodes(). - * However, we don't worry about the conditional freeing for physics - * stuff, since it's rarely needed currently. */ - for (Depsgraph::IDDepsNodes::iterator it_id = graph->id_nodes.begin(); - it_id != graph->id_nodes.end();) { - IDNode *id_node = *it_id; - ID *id = id_node->id_orig; - - if (id_node->custom_flags) { - /* Destroy node data, then remove from collections, and free */ - id_node->destroy(); - - BLI_ghash_remove(graph->id_hash, id, NULL, NULL); - it_id = graph->id_nodes.erase(it_id); - - OBJECT_GUARDED_DELETE(id_node, IDNode); - } - else { - /* This node has not been marked for deletion. Increment iterator */ - ++it_id; - } - } -} - -} // namespace DEG - -/* *************************************************** */ -/* Graph Filtering API */ - -/* Obtain a new graph instance that only contains the subset of desired nodes - * WARNING: Do NOT pass an already filtered depsgraph through this function again, - * as we are currently unable to accurately recreate it. - */ -Depsgraph *DEG_graph_filter(const Depsgraph *graph_src, Main *bmain, DEG_FilterQuery *query) -{ - const DEG::Depsgraph *deg_graph_src = reinterpret_cast<const DEG::Depsgraph *>(graph_src); - if (deg_graph_src == NULL) { - return NULL; - } - - /* Construct a full new depsgraph based on the one we got */ - /* TODO: Improve the builders to not add any ID nodes we don't need later (e.g. ProxyBuilder?) */ - Depsgraph *graph_new = DEG_graph_new( - deg_graph_src->scene, deg_graph_src->view_layer, deg_graph_src->mode); - DEG_graph_build_from_view_layer( - graph_new, bmain, deg_graph_src->scene, deg_graph_src->view_layer); - - /* Build a set of all the id's we want to keep */ - GSet *retained_ids = BLI_gset_ptr_new(__func__); - DEG::RetainedIdUserData retained_id_data = {query, retained_ids}; - - LISTBASE_FOREACH (DEG_FilterTarget *, target, &query->targets) { - /* Target Itself */ - BLI_gset_add(retained_ids, (void *)target->id); - - /* Target's Ancestors (i.e. things it depends on) */ - DEG_foreach_ancestor_ID(graph_new, target->id, DEG::deg_add_retained_id_cb, &retained_id_data); - } - - /* Remove everything we don't want to keep around anymore */ - DEG::Depsgraph *deg_graph_new = reinterpret_cast<DEG::Depsgraph *>(graph_new); - if (BLI_gset_len(retained_ids) > 0) { - DEG::deg_filter_remove_unwanted_ids(deg_graph_new, retained_ids); - } - // TODO: query->LOD filters - - /* Free temp data */ - BLI_gset_free(retained_ids, NULL); - retained_ids = NULL; - - /* Print Stats */ - // XXX: Hide behind debug flags - size_t s_outer, s_operations, s_relations; - size_t s_ids = deg_graph_src->id_nodes.size(); - unsigned int s_idh = BLI_ghash_len(deg_graph_src->id_hash); - - size_t n_outer, n_operations, n_relations; - size_t n_ids = deg_graph_new->id_nodes.size(); - unsigned int n_idh = BLI_ghash_len(deg_graph_new->id_hash); - - DEG_stats_simple(graph_src, &s_outer, &s_operations, &s_relations); - DEG_stats_simple(graph_new, &n_outer, &n_operations, &n_relations); - - printf("%s: src = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", - __func__, - s_ids, - s_idh, - s_outer, - s_operations, - s_relations); - printf("%s: new = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", - __func__, - n_ids, - n_idh, - n_outer, - n_operations, - n_relations); - - /* Return this new graph instance */ - return graph_new; -} - -/* *************************************************** */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index d3bf27747c0..06632d7e510 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -94,7 +94,6 @@ void verify_id_properties_freed(DEGObjectIterData *data) // Free memory which is owned by temporary storage which is about to // get overwritten. IDP_FreeProperty(temp_dupli_object->id.properties); - MEM_freeN(temp_dupli_object->id.properties); temp_dupli_object->id.properties = NULL; } @@ -145,7 +144,6 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) Object *dupli_parent = data->dupli_parent; Object *temp_dupli_object = &data->temp_dupli_object; *temp_dupli_object = *dob->ob; - temp_dupli_object->select_id = dupli_parent->select_id; temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI; temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits; temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt); @@ -159,7 +157,13 @@ bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) continue; } + /* This could be avoided by refactoring make_dupli() in order to track all negative scaling + * recursively. */ + bool is_neg_scale = is_negative_m4(dob->mat); + SET_FLAG_FROM_TEST(data->temp_dupli_object.transflag, is_neg_scale, OB_NEG_SCALE); + copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); + invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat); iter->current = &data->temp_dupli_object; BLI_assert(DEG::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); return true; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index f682dadee8e..7dcba8b7655 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -245,6 +245,13 @@ void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) deg_editors_id_update(&update_ctx, id); } +void depsgraph_id_tag_copy_on_write(Depsgraph *graph, IDNode *id_node, eUpdateSource update_source) +{ + ComponentNode *cow_comp = id_node->find_component(NodeType::COPY_ON_WRITE); + cow_comp->tag_update(graph, update_source); + id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE; +} + void depsgraph_tag_component(Depsgraph *graph, IDNode *id_node, NodeType component_type, @@ -252,7 +259,13 @@ void depsgraph_tag_component(Depsgraph *graph, eUpdateSource update_source) { ComponentNode *component_node = id_node->find_component(component_type); + /* NOTE: Animation component might not be existing yet (which happens when adding new driver or + * adding a new keyframe), so the required copy-on-write tag needs to be taken care explicitly + * here. */ if (component_node == NULL) { + if (component_type == NodeType::ANIMATION) { + depsgraph_id_tag_copy_on_write(graph, id_node, update_source); + } return; } if (operation_code == OperationCode::OPERATION) { @@ -266,9 +279,7 @@ void depsgraph_tag_component(Depsgraph *graph, } /* If component depends on copy-on-write, tag it as well. */ if (component_node->need_tag_cow_before_update()) { - ComponentNode *cow_comp = id_node->find_component(NodeType::COPY_ON_WRITE); - cow_comp->tag_update(graph, update_source); - id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE; + depsgraph_id_tag_copy_on_write(graph, id_node, update_source); } } @@ -462,7 +473,9 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) * Need to solve those issues carefully, for until then we evaluate * animation for datablocks which appears in the graph for the first * time. */ - flag |= ID_RECALC_ANIMATION; + if (BKE_animdata_from_id(id_node->id_orig) != NULL) { + flag |= ID_RECALC_ANIMATION; + } } /* We only tag components which needs an update. Tagging everything is * not a good idea because that might reset particles cache (or any diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 2f153e585d3..2a76d5cd362 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -1278,7 +1278,9 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow) bool deg_copy_on_write_is_needed(const ID *id_orig) { const ID_Type id_type = GS(id_orig->name); - return !ELEM(id_type, ID_IM); + /* TODO(sergey): Make Sound copyable. It is here only because the code for dependency graph is + * being work in progress. */ + return !ELEM(id_type, ID_IM, ID_SO); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 5692983fbe2..7df96330ef0 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -101,13 +101,12 @@ const char *nodeTypeAsString(NodeType type) return "POINT_CACHE"; case NodeType::BATCH_CACHE: return "BATCH_CACHE"; - /* Duplication. */ case NodeType::DUPLI: return "DUPLI"; - /* Synchronization. */ case NodeType::SYNCHRONIZATION: return "SYNCHRONIZATION"; - /* Generic datablock. */ + case NodeType::AUDIO: + return "AUDIO"; case NodeType::GENERIC_DATABLOCK: return "GENERIC_DATABLOCK"; diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index ece43657b38..e350cc9a6f4 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -92,6 +92,8 @@ enum class NodeType { /* Used by all operations which are updating object when something is * changed in view layer. */ OBJECT_FROM_LAYER, + /* Audio-related evaluation. */ + AUDIO, /* Un-interestying datablock, which is a part of dependency graph, but does * not have very distinctive update procedure. */ GENERIC_DATABLOCK, diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index ceec62e278b..f67a81f594f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -131,7 +131,6 @@ string ComponentNode::identifier() const const string typebuf = "" + to_string(static_cast<int>(type)) + ")"; return typebuf + name + " : " + idname + "( affects_directly_visible: " + (affects_directly_visible ? "true" : "false") + ")"; - ; } OperationNode *ComponentNode::find_operation(OperationIDKey key) const @@ -365,6 +364,7 @@ DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0); DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0); DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0); +DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0); DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0); /* Node Types Register =================================== */ @@ -391,6 +391,7 @@ void deg_register_component_depsnodes() register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER); register_node_typeinfo(&DNTI_DUPLI); register_node_typeinfo(&DNTI_SYNCHRONIZATION); + register_node_typeinfo(&DNTI_AUDIO); register_node_typeinfo(&DNTI_GENERIC_DATABLOCK); } diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 038b5917a86..733d32e9c2d 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -186,6 +186,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform); DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer); DEG_COMPONENT_NODE_DECLARE_GENERIC(Dupli); DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio); DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock); /* Bone Component */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index 154563303ad..62a61675bcc 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -100,6 +100,8 @@ const char *operationCodeAsString(OperationCode opcode) return "LIGHT_PROBE_EVAL"; case OperationCode::SPEAKER_EVAL: return "SPEAKER_EVAL"; + case OperationCode::SOUND_EVAL: + return "SOUND_EVAL"; case OperationCode::ARMATURE_EVAL: return "ARMATURE_EVAL"; /* Pose. */ diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index c959f7f34e0..ab6242a6196 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -106,6 +106,7 @@ enum class OperationCode { /* Object data. --------------------------------------------------------- */ LIGHT_PROBE_EVAL, SPEAKER_EVAL, + SOUND_EVAL, ARMATURE_EVAL, /* Pose. ---------------------------------------------------------------- */ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index abbf8a2b47b..b31cb7bf770 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -131,6 +131,7 @@ set(SRC intern/DRW_render.h intern/draw_cache.h intern/draw_cache_impl.h + intern/draw_cache_inline.h intern/draw_common.h intern/draw_debug.h intern/draw_hair_private.h diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index da1f5c7863a..5919e100ddd 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -38,6 +38,7 @@ struct IDProperty; struct Main; struct Material; struct Object; +struct RegionView3D; struct RenderEngine; struct RenderEngineType; struct Scene; @@ -135,6 +136,15 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, void DRW_draw_depth_object(struct ARegion *ar, struct GPUViewport *viewport, struct Object *object); +void DRW_draw_select_id_object(struct Scene *scene, + struct RegionView3D *rv3d, + struct Object *ob, + short select_mode, + bool draw_facedot, + uint initial_offset, + uint *r_vert_offset, + uint *r_edge_offset, + uint *r_face_offset); void DRW_framebuffer_select_id_setup(struct ARegion *ar, const bool clear); void DRW_framebuffer_select_id_release(struct ARegion *ar); @@ -146,7 +156,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph void DRW_gpencil_freecache(struct Object *ob); /* This is here because GPUViewport needs it */ -void DRW_pass_free(struct DRWPass *pass); struct DRWInstanceDataList *DRW_instance_data_list_create(void); void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist); diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 05ee485e053..d6902dddc61 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -96,18 +96,14 @@ static void basic_cache_init(void *vedata) BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; const RegionView3D *rv3d = draw_ctx->rv3d; - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } - if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); } { - psl->depth_pass = DRW_pass_create( - "Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE); + psl->depth_pass = DRW_pass_create("Depth Pass", + DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); stl->g_data->depth_shgrp = DRW_shgroup_create(sh_data->depth, psl->depth_pass); if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(stl->g_data->depth_shgrp, rv3d); @@ -143,7 +139,7 @@ static void basic_cache_populate(void *vedata, Object *ob) const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; if (draw_as == PART_DRAW_PATH) { struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL); - DRW_shgroup_call_add(stl->g_data->depth_shgrp, hairs, NULL); + DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL); } } } @@ -159,7 +155,7 @@ static void basic_cache_populate(void *vedata, Object *ob) if (is_flat_object_viewed_from_side) { /* Avoid losing flat objects when in ortho views (see T56549) */ struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob); - DRW_shgroup_call_object_add(stl->g_data->depth_shgrp, geom, ob); + DRW_shgroup_call_object(stl->g_data->depth_shgrp, geom, ob); return; } } @@ -169,7 +165,7 @@ static void basic_cache_populate(void *vedata, Object *ob) const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); /* Depth Prepass */ - DRW_shgroup_call_object_add( + DRW_shgroup_call_object( (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob); } } diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index b0013151a70..e0165ea020a 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -186,7 +186,7 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name, *pass = DRW_pass_create(name, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); DRW_shgroup_uniform_texture_ref(grp, "sourceBuffer", &effects->unf_source_buffer); DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1); if (upsample) { diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index b7b8702b41a..0ce271275d0 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -62,7 +62,6 @@ void EEVEE_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); - DRW_UBO_FREE_SAFE(sldata->clip_ubo); } EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index 8fb73bd605f..c14f08857c3 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -79,7 +79,9 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - if (scene_eval->eevee.flag & SCE_EEVEE_DOF_ENABLED) { + Camera *cam = (camera != NULL) ? camera->data : NULL; + + if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) { RegionView3D *rv3d = draw_ctx->rv3d; const bool use_alpha = !DRW_state_draw_background(); @@ -87,94 +89,82 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), eevee_create_shader_depth_of_field(use_alpha); } - if (camera) { - const float *viewport_size = DRW_viewport_size_get(); - Camera *cam = (Camera *)camera->data; - - /* Retrieve Near and Far distance */ - effects->dof_near_far[0] = -cam->clip_start; - effects->dof_near_far[1] = -cam->clip_end; - - int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2}; - - eGPUTextureFormat down_format = DRW_state_draw_background() ? GPU_R11F_G11F_B10F : - GPU_RGBA16F; - - effects->dof_down_near = DRW_texture_pool_query_2d( - buffer_size[0], buffer_size[1], down_format, &draw_engine_eevee_type); - effects->dof_down_far = DRW_texture_pool_query_2d( - buffer_size[0], buffer_size[1], down_format, &draw_engine_eevee_type); - effects->dof_coc = DRW_texture_pool_query_2d( - buffer_size[0], buffer_size[1], GPU_RG16F, &draw_engine_eevee_type); - - GPU_framebuffer_ensure_config(&fbl->dof_down_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(effects->dof_down_near), - GPU_ATTACHMENT_TEXTURE(effects->dof_down_far), - GPU_ATTACHMENT_TEXTURE(effects->dof_coc)}); - - /* Go full 32bits for rendering and reduce the color artifacts. */ - eGPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F; - - effects->dof_blur = DRW_texture_pool_query_2d( - buffer_size[0] * 2, buffer_size[1], fb_format, &draw_engine_eevee_type); - - GPU_framebuffer_ensure_config(&fbl->dof_scatter_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(effects->dof_blur), - }); - - if (!DRW_state_draw_background()) { - effects->dof_blur_alpha = DRW_texture_pool_query_2d( - buffer_size[0] * 2, buffer_size[1], GPU_R32F, &draw_engine_eevee_type); - GPU_framebuffer_texture_attach(fbl->dof_scatter_fb, effects->dof_blur_alpha, 1, 0); - } - - /* Parameters */ - /* TODO UI Options */ - float fstop = cam->gpu_dof.fstop; - float blades = cam->gpu_dof.num_blades; - float rotation = cam->gpu_dof.rotation; - float ratio = 1.0f / cam->gpu_dof.ratio; - float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - float focus_dist = BKE_camera_object_dof_distance(camera); - float focal_len = cam->lens; - - /* this is factor that converts to the scene scale. focal length and sensor are expressed in - * mm unit.scale_length is how many meters per blender unit we have. We want to convert to - * blender units though because the shader reads coordinates in world space, which is in - * blender units. - * Note however that focus_distance is already in blender units and shall not be scaled here - * (see T48157). */ - float scale = (scene_eval->unit.system) ? scene_eval->unit.scale_length : 1.0f; - float scale_camera = 0.001f / scale; - /* we want radius here for the aperture number */ - float aperture = 0.5f * scale_camera * focal_len / fstop; - float focal_len_scaled = scale_camera * focal_len; - float sensor_scaled = scale_camera * sensor; - - if (rv3d != NULL) { - sensor_scaled *= rv3d->viewcamtexcofac[0]; - } - - effects->dof_params[1] = aperture * - fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); - effects->dof_params[1] *= viewport_size[0] / sensor_scaled; - effects->dof_params[0] = -focus_dist * effects->dof_params[1]; - - effects->dof_bokeh[0] = rotation; - effects->dof_bokeh[1] = ratio; - effects->dof_bokeh[2] = scene_eval->eevee.bokeh_max_size; - - /* Precompute values to save instructions in fragment shader. */ - effects->dof_bokeh_sides[0] = blades; - effects->dof_bokeh_sides[1] = blades > 0.0f ? 2.0f * M_PI / blades : 0.0f; - effects->dof_bokeh_sides[2] = blades / (2.0f * M_PI); - effects->dof_bokeh_sides[3] = blades > 0.0f ? cosf(M_PI / blades) : 0.0f; - - return EFFECT_DOF | EFFECT_POST_BUFFER; + const float *viewport_size = DRW_viewport_size_get(); + + /* Retrieve Near and Far distance */ + effects->dof_near_far[0] = -cam->clip_start; + effects->dof_near_far[1] = -cam->clip_end; + + int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2}; + + eGPUTextureFormat down_format = DRW_state_draw_background() ? GPU_R11F_G11F_B10F : GPU_RGBA16F; + + effects->dof_down_near = DRW_texture_pool_query_2d( + buffer_size[0], buffer_size[1], down_format, &draw_engine_eevee_type); + effects->dof_down_far = DRW_texture_pool_query_2d( + buffer_size[0], buffer_size[1], down_format, &draw_engine_eevee_type); + effects->dof_coc = DRW_texture_pool_query_2d( + buffer_size[0], buffer_size[1], GPU_RG16F, &draw_engine_eevee_type); + + GPU_framebuffer_ensure_config(&fbl->dof_down_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->dof_down_near), + GPU_ATTACHMENT_TEXTURE(effects->dof_down_far), + GPU_ATTACHMENT_TEXTURE(effects->dof_coc)}); + + /* Go full 32bits for rendering and reduce the color artifacts. */ + eGPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F; + + effects->dof_blur = DRW_texture_pool_query_2d( + buffer_size[0] * 2, buffer_size[1], fb_format, &draw_engine_eevee_type); + + GPU_framebuffer_ensure_config(&fbl->dof_scatter_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->dof_blur), + }); + + if (!DRW_state_draw_background()) { + effects->dof_blur_alpha = DRW_texture_pool_query_2d( + buffer_size[0] * 2, buffer_size[1], GPU_R32F, &draw_engine_eevee_type); + GPU_framebuffer_texture_attach(fbl->dof_scatter_fb, effects->dof_blur_alpha, 1, 0); + } + + /* Parameters */ + /* TODO UI Options */ + float fstop = cam->dof.aperture_fstop; + float blades = cam->dof.aperture_blades; + float rotation = cam->dof.aperture_rotation; + float ratio = 1.0f / cam->dof.aperture_ratio; + float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); + float focus_dist = BKE_camera_object_dof_distance(camera); + float focal_len = cam->lens; + + const float scale_camera = 0.001f; + /* we want radius here for the aperture number */ + float aperture = 0.5f * scale_camera * focal_len / fstop; + float focal_len_scaled = scale_camera * focal_len; + float sensor_scaled = scale_camera * sensor; + + if (rv3d != NULL) { + sensor_scaled *= rv3d->viewcamtexcofac[0]; } + + effects->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); + effects->dof_params[1] *= viewport_size[0] / sensor_scaled; + effects->dof_params[0] = -focus_dist * effects->dof_params[1]; + + effects->dof_bokeh[0] = rotation; + effects->dof_bokeh[1] = ratio; + effects->dof_bokeh[2] = scene_eval->eevee.bokeh_max_size; + + /* Precompute values to save instructions in fragment shader. */ + effects->dof_bokeh_sides[0] = blades; + effects->dof_bokeh_sides[1] = blades > 0.0f ? 2.0f * M_PI / blades : 0.0f; + effects->dof_bokeh_sides[2] = blades / (2.0f * M_PI); + effects->dof_bokeh_sides[3] = blades > 0.0f ? cosf(M_PI / blades) : 0.0f; + + return EFFECT_DOF | EFFECT_POST_BUFFER; } /* Cleanup to release memory */ @@ -205,31 +195,31 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); const bool use_alpha = !DRW_state_draw_background(); - psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->dof_down, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.dof_downsample_sh[use_alpha], psl->dof_down); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1); DRW_shgroup_uniform_vec2(grp, "dofParams", effects->dof_params, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->dof_scatter = DRW_pass_create("DoF Scatter", - DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL); + DRW_PASS_CREATE(psl->dof_scatter, DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL); /* This create an empty batch of N triangles to be positioned * by the vertex shader 0.4ms against 6ms with instancing */ const float *viewport_size = DRW_viewport_size_get(); const int sprite_len = ((int)viewport_size[0] / 2) * ((int)viewport_size[1] / 2); /* brackets matters */ - grp = DRW_shgroup_empty_tri_batch_create( - e_data.dof_scatter_sh[use_alpha], psl->dof_scatter, sprite_len); + grp = DRW_shgroup_create(e_data.dof_scatter_sh[use_alpha], psl->dof_scatter); DRW_shgroup_uniform_texture_ref(grp, "nearBuffer", &effects->dof_down_near); DRW_shgroup_uniform_texture_ref(grp, "farBuffer", &effects->dof_down_far); DRW_shgroup_uniform_texture_ref(grp, "cocBuffer", &effects->dof_coc); DRW_shgroup_uniform_vec4(grp, "bokehParams", effects->dof_bokeh, 2); - psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR); + DRW_shgroup_call_procedural_triangles(grp, sprite_len, NULL); + + DRW_PASS_CREATE(psl->dof_resolve, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.dof_resolve_sh[use_alpha], psl->dof_resolve); DRW_shgroup_uniform_texture_ref(grp, "scatterBuffer", &effects->dof_blur); @@ -237,7 +227,7 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1); DRW_shgroup_uniform_vec2(grp, "dofParams", effects->dof_params, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); if (use_alpha) { DRW_shgroup_uniform_texture_ref(grp, "scatterAlphaBuffer", &effects->dof_blur_alpha); diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index a8b4159e030..3562afc9134 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -159,9 +159,10 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); - effects->enabled_effects |= EEVEE_subsurface_init(sldata, vedata); effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata); - effects->enabled_effects |= EEVEE_volumes_init(sldata, vedata); + + EEVEE_volumes_init(sldata, vedata); + EEVEE_subsurface_init(sldata, vedata); /* Force normal buffer creation. */ if (DRW_state_is_image_render() && !minimal && (view_layer->passflag & SCE_PASS_NORMAL) != 0) { @@ -262,16 +263,6 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_depth_fb); } - /** - * Setup double buffer so we can access last frame as it was before post processes. - */ - if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) { - SETUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb); - } - else { - CLEANUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb); - } - if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { SETUP_BUFFER(txl->taa_history, fbl->taa_history_fb, fbl->taa_history_color_fb); } @@ -286,7 +277,8 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - int downsample_write = DRW_STATE_WRITE_DEPTH; + DRWState downsample_write = DRW_STATE_WRITE_DEPTH; + DRWShadingGroup *grp; /* Intel gpu seems to have problem rendering to only depth format. * Use color texture instead. */ @@ -297,91 +289,101 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); { - psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps); + DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps); DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { - static int zero = 0; - static uint six = 6; - psl->color_downsample_cube_ps = DRW_pass_create("Downsample Cube", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_cube_sh, - psl->color_downsample_cube_ps); + DRW_PASS_CREATE(psl->color_downsample_cube_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps); DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); DRW_shgroup_uniform_float(grp, "texelSize", &e_data.cube_texel_size, 1); - DRW_shgroup_uniform_int(grp, "Layer", &zero, 1); - DRW_shgroup_call_instances_add(grp, quad, NULL, &six); + DRW_shgroup_uniform_int_copy(grp, "Layer", 0); + DRW_shgroup_call_instances(grp, quad, NULL, 6); } { /* Perform min/max downsample */ - DRWShadingGroup *grp; - - psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", - downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); /* Copy depth buffer to halfres top level of HiZ */ - psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", - downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_downdepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", - downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_downdepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", - downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->maxz_copydepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", - downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_copydepth_layer_sh, psl->maxz_copydepth_layer_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { /* This pass compute camera motions to the non moving objects. */ - psl->velocity_resolve = DRW_pass_create("Velocity Resolve", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), - psl->velocity_resolve); + DRW_PASS_CREATE(psl->velocity_resolve, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } if ((effects->enabled_effects & EFFECT_ALPHA_CHECKER) != 0) { - psl->alpha_checker = DRW_pass_create("Alpha Checker", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL_UNDER); - GPUShader *checker_sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_CHECKER); - DRWShadingGroup *grp = DRW_shgroup_create(checker_sh, psl->alpha_checker); - copy_v4_fl4(effects->color_checker_dark, 0.15f, 0.15f, 0.15f, 1.0f); copy_v4_fl4(effects->color_checker_light, 0.2f, 0.2f, 0.2f, 1.0f); + DRW_PASS_CREATE(psl->alpha_checker, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL_UNDER); + grp = DRW_shgroup_create(checker_sh, psl->alpha_checker); DRW_shgroup_uniform_vec4(grp, "color1", effects->color_checker_dark, 1); DRW_shgroup_uniform_vec4(grp, "color2", effects->color_checker_light, 1); DRW_shgroup_uniform_int_copy(grp, "size", 8); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); + + float mat[4][4]; + unit_m4(mat); + + /* Using default view bypasses the culling. */ + const DRWView *default_view = DRW_view_default_get(); + effects->checker_view = DRW_view_create_sub(default_view, mat, mat); + } +} + +void EEVEE_effects_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /** + * Setup double buffer so we can access last frame as it was before post processes. + */ + if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) { + SETUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb); + } + else { + CLEANUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb); } } @@ -520,16 +522,11 @@ void EEVEE_draw_alpha_checker(EEVEE_Data *vedata) EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_ALPHA_CHECKER) != 0) { - float mat[4][4]; - unit_m4(mat); - - /* Fragile, rely on the fact that GPU_SHADER_2D_CHECKER - * only use the persmat. */ - DRW_viewport_matrix_override_set(mat, DRW_MAT_PERS); + DRW_view_set_active(effects->checker_view); DRW_draw_pass(psl->alpha_checker); - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); + DRW_view_set_active(NULL); } } @@ -539,16 +536,17 @@ static void EEVEE_velocity_resolve(EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + struct DRWView *view = effects->taa_view; if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); e_data.depth_src = dtxl->depth; - DRW_viewport_matrix_get(effects->velocity_curr_persinv, DRW_MAT_PERSINV); + DRW_view_persmat_get(view, effects->velocity_curr_persinv, true); GPU_framebuffer_bind(fbl->velocity_resolve_fb); DRW_draw_pass(psl->velocity_resolve); } - DRW_viewport_matrix_get(effects->velocity_past_persmat, DRW_MAT_PERS); + DRW_view_persmat_get(view, effects->velocity_past_persmat, false); } void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -572,7 +570,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) /* NOTE: Lookdev drawing happens before TAA but after * motion blur and dof to avoid distortions. * Velocity resolve use a hack to exclude lookdev - * balls from creating shimering reprojection vectors. */ + * spheres from creating shimering reprojection vectors. */ EEVEE_lookdev_draw(vedata); EEVEE_velocity_resolve(vedata); @@ -599,7 +597,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) } /* Record pers matrix for the next frame. */ - DRW_viewport_matrix_get(stl->effects->prev_persmat, DRW_MAT_PERS); + DRW_view_persmat_get(effects->taa_view, effects->prev_persmat, false); /* Update double buffer status if render mode. */ if (DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 962bc8e5efb..bb37f36f935 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -79,20 +79,12 @@ static void eevee_engine_init(void *ved) sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); } - if (sldata->clip_ubo == NULL) { - sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); - } /* EEVEE_effects_init needs to go first for TAA */ EEVEE_effects_init(sldata, vedata, camera, false); EEVEE_materials_init(sldata, stl, fbl); EEVEE_lights_init(sldata); EEVEE_lightprobes_init(sldata, vedata); - - if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { - /* XXX otherwise it would break the other engines. */ - DRW_viewport_matrix_override_unset_all(); - } } static void eevee_cache_init(void *vedata) @@ -154,9 +146,13 @@ static void eevee_cache_finish(void *vedata) { EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_materials_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); } /* As renders in an HDR offscreen buffer, we need draw everything once @@ -180,12 +176,13 @@ static void eevee_draw_background(void *vedata) /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); - /* Number of iteration: needed for all temporal effect (SSR, volumetrics) - * when using opengl render. */ - int loop_len = (DRW_state_is_image_render() && - (stl->effects->enabled_effects & (EFFECT_VOLUMETRIC | EFFECT_SSR)) != 0) ? - 4 : - 1; + /* Number of iteration: Use viewport taa_samples when using viewport rendering */ + int loop_len = 1; + if (DRW_state_is_image_render()) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + loop_len = MAX2(1, scene->eevee.taa_samples); + } while (loop_len--) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; @@ -209,30 +206,30 @@ static void eevee_draw_background(void *vedata) /* Copy previous persmat to UBO data */ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); - if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && - (stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render() && - !taa_use_reprojection) { - DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); - } - /* Refresh Probes */ DRW_stats_group_start("Probes Refresh"); EEVEE_lightprobes_refresh(sldata, vedata); - /* Probes refresh can have reset the current sample. */ - if (stl->effects->taa_current_sample == 1) { - DRW_viewport_matrix_override_unset_all(); - } EEVEE_lightprobes_refresh_planar(sldata, vedata); DRW_stats_group_end(); /* Refresh shadows */ DRW_stats_group_start("Shadows"); - EEVEE_draw_shadows(sldata, vedata); + EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view); DRW_stats_group_end(); + if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && + (stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render() && + !taa_use_reprojection) { + DRW_view_set_active(stl->effects->taa_view); + } + /* when doing viewport rendering the overrides needs to be recalculated for + * every loop as this normally happens once inside + * `EEVEE_temporal_sampling_init` */ + else if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && + (stl->effects->taa_current_sample > 1) && DRW_state_is_image_render()) { + EEVEE_temporal_sampling_update_matrices(vedata); + } + /* Set ray type. */ sldata->common_data.ray_type = EEVEE_RAY_CAMERA; sldata->common_data.ray_depth = 0.0f; @@ -240,8 +237,8 @@ static void eevee_draw_background(void *vedata) GPU_framebuffer_bind(fbl->main_fb); eGPUFrameBufferBits clear_bits = GPU_DEPTH_BIT; - clear_bits |= (DRW_state_draw_background()) ? 0 : GPU_COLOR_BIT; - clear_bits |= ((stl->effects->enabled_effects & EFFECT_SSS) != 0) ? GPU_STENCIL_BIT : 0; + SET_FLAG_FROM_TEST(clear_bits, !DRW_state_draw_background(), GPU_COLOR_BIT); + SET_FLAG_FROM_TEST(clear_bits, (stl->effects->enabled_effects & EFFECT_SSS), GPU_STENCIL_BIT); GPU_framebuffer_clear(fbl->main_fb, clear_bits, clear_col, clear_depth, clear_stencil); /* Depth prepass */ @@ -296,9 +293,7 @@ static void eevee_draw_background(void *vedata) EEVEE_draw_effects(sldata, vedata); DRW_stats_group_end(); - if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { - DRW_viewport_matrix_override_unset_all(); - } + DRW_view_set_active(NULL); } /* Tonemapping and transfer result to default framebuffer. */ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 33cb2e87dc7..536ecb1bc42 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -717,16 +717,20 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb stl->g_data->background_alpha = 1.0f; /* XXX TODO remove this. This is in order to make the init functions work. */ - DRWMatrixState dummy_mats = {{{{{0}}}}}; - DRW_viewport_matrix_override_set_all(&dummy_mats); + if (DRW_view_default_get() == NULL) { + float winmat[4][4], viewmat[4][4]; + unit_m4(viewmat); + unit_m4(winmat); + negate_v3(winmat[2]); + DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + DRW_view_default_set(view); + DRW_view_set_active(view); + } if (sldata->common_ubo == NULL) { sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); } - if (sldata->clip_ubo == NULL) { - sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); - } /* HACK: set txl->color but unset it before Draw Manager frees it. */ txl->color = lbake->rt_color; @@ -743,6 +747,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb EEVEE_effects_cache_init(sldata, vedata); EEVEE_materials_cache_init(sldata, vedata); + EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_lights_cache_init(sldata, vedata); EEVEE_lightprobes_cache_init(sldata, vedata); @@ -757,10 +762,14 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb } DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache); - EEVEE_materials_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); + txl->color = NULL; DRW_render_instance_buffer_finish(); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index a4a17de7a57..388a8b5e73d 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -167,6 +167,11 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE); } + memset(stl->g_data->bake_views, 0, sizeof(stl->g_data->bake_views)); + memset(stl->g_data->cube_views, 0, sizeof(stl->g_data->cube_views)); + memset(stl->g_data->world_views, 0, sizeof(stl->g_data->world_views)); + memset(stl->g_data->planar_views, 0, sizeof(stl->g_data->planar_views)); + /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */ bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) || ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) && @@ -227,8 +232,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_LightProbesInfo *pinfo = sldata->probes; { - psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", - DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->probe_glossy_compute, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_filter_glossy_sh_get(), psl->probe_glossy_compute); @@ -249,13 +253,11 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } { - psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", - DRW_STATE_WRITE_COLOR); - + DRW_PASS_CREATE(psl->probe_diffuse_compute, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_filter_diffuse_sh_get(), psl->probe_diffuse_compute); #ifdef IRRADIANCE_SH_L2 @@ -272,13 +274,11 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } { - psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", - DRW_STATE_WRITE_COLOR); - + DRW_PASS_CREATE(psl->probe_visibility_compute, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_filter_visibility_sh_get(), psl->probe_visibility_compute); DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1); @@ -294,11 +294,11 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } { - psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->probe_grid_fill, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_grid_fill_sh_get(), psl->probe_grid_fill); @@ -306,7 +306,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &light_cache->grid_tx.tex); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } } @@ -326,8 +326,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat pinfo->do_cube_update = false; { - psl->probe_background = DRW_pass_create("World Probe Background Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + DRW_PASS_CREATE(psl->probe_background, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; @@ -360,7 +359,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); break; default: col = error_col; @@ -374,20 +373,20 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background); DRW_shgroup_uniform_vec3(grp, "color", col, 1); DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } } if (DRW_state_draw_support() && !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - psl->probe_display = DRW_pass_create("LightProbe Display", state); + DRW_PASS_CREATE(psl->probe_display, state); /* Cube Display */ if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_CUBEMAPS && lcache->cube_len > 1) { int cube_len = lcache->cube_len - 1; /* don't count the world. */ - DRWShadingGroup *grp = DRW_shgroup_empty_tri_batch_create( - EEVEE_shaders_probe_cube_display_sh_get(), psl->probe_display, cube_len * 2); + DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_cube_display_sh_get(), + psl->probe_display); DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); @@ -398,6 +397,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat /* TODO (fclem) get rid of those UBO. */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + + DRW_shgroup_call_procedural_triangles(grp, cube_len * 2, NULL); } /* Grid Display */ @@ -423,7 +424,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2; - DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, NULL); + DRW_shgroup_call_procedural_triangles(shgrp, tri_count, NULL); } } @@ -434,29 +435,16 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat {"probe_mat", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(EEVEE_shaders_probe_planar_display_sh_get(), - psl->probe_display, - DRW_cache_quad_get(), - e_data.format_probe_display_planar); - stl->g_data->planar_display_shgrp = grp; + DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_display_sh_get(), + psl->probe_display); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); + + stl->g_data->planar_display_shgrp = DRW_shgroup_call_buffer_instance( + grp, e_data.format_probe_display_planar, DRW_cache_quad_get()); } else { stl->g_data->planar_display_shgrp = NULL; } - - { - psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", - DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_downsample_sh_get(), - psl->probe_planar_downsample_ps); - - DRW_shgroup_uniform_texture_ref(grp, "source", &txl->planar_pool); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); - DRW_shgroup_call_instances_add( - grp, DRW_cache_fullscreen_quad_get(), NULL, (uint *)&pinfo->num_planar); - } } static bool eevee_lightprobes_culling_test(Object *ob) @@ -480,7 +468,8 @@ static bool eevee_lightprobes_culling_test(Object *ob) for (int v = 0; v < 8; ++v) { mul_m4_v3(tmp, bbox.vec[v]); } - return DRW_culling_box_test(&bbox); + const DRWView *default_view = DRW_view_default_get(); + return DRW_culling_box_test(default_view, &bbox); } case LIGHTPROBE_TYPE_CUBE: return true; /* TODO */ @@ -504,15 +493,17 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata } if (probe->type == LIGHTPROBE_TYPE_PLANAR) { + /* TODO(fclem): Culling should be done after cache generation. + * This is needed for future draw cache persistence. */ if (!eevee_lightprobes_culling_test(ob)) { return; /* Culled */ } EEVEE_lightprobes_planar_data_from_object( ob, &pinfo->planar_data[pinfo->num_planar], &pinfo->planar_vis_tests[pinfo->num_planar]); /* Debug Display */ - DRWShadingGroup *grp = vedata->stl->g_data->planar_display_shgrp; + DRWCallBuffer *grp = vedata->stl->g_data->planar_display_shgrp; if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { - DRW_shgroup_call_dynamic_add(grp, &pinfo->num_planar, ob->obmat); + DRW_buffer_add_entry(grp, &pinfo->num_planar, ob->obmat); } pinfo->num_planar++; @@ -690,22 +681,35 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob, eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale; } -static void lightbake_planar_compute_render_matrices(EEVEE_PlanarReflection *eplanar, - DRWMatrixState *r_matstate, - const float viewmat[4][4], - const float winmat[4][4]) +static void lightbake_planar_ensure_view(EEVEE_PlanarReflection *eplanar, + const DRWView *main_view, + DRWView **r_planar_view) { + float winmat[4][4], viewmat[4][4]; + DRW_view_viewmat_get(main_view, viewmat, false); /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ - copy_m4_m4(r_matstate->winmat, winmat); + DRW_view_winmat_get(main_view, winmat, false); /* Invert X to avoid flipping the triangle facing direction. */ - r_matstate->winmat[0][0] = -r_matstate->winmat[0][0]; - r_matstate->winmat[1][0] = -r_matstate->winmat[1][0]; - r_matstate->winmat[2][0] = -r_matstate->winmat[2][0]; - r_matstate->winmat[3][0] = -r_matstate->winmat[3][0]; + winmat[0][0] = -winmat[0][0]; + winmat[1][0] = -winmat[1][0]; + winmat[2][0] = -winmat[2][0]; + winmat[3][0] = -winmat[3][0]; /* Reflect Camera Matrix. */ - mul_m4_m4m4(r_matstate->viewmat, viewmat, eplanar->mtx); - /* Apply Projection Matrix. */ - mul_m4_m4m4(r_matstate->persmat, r_matstate->winmat, r_matstate->viewmat); + mul_m4_m4m4(viewmat, viewmat, eplanar->mtx); + + if (*r_planar_view == NULL) { + *r_planar_view = DRW_view_create( + viewmat, winmat, NULL, NULL, EEVEE_lightprobes_obj_visibility_cb); + /* Compute offset plane equation (fix missing texels near reflection plane). */ + float clip_plane[4]; + copy_v4_v4(clip_plane, eplanar->plane_equation); + clip_plane[3] += eplanar->clipsta; + /* Set clipping plane */ + DRW_view_clip_planes_set(*r_planar_view, &clip_plane, 1); + } + else { + DRW_view_update(*r_planar_view, viewmat, winmat, NULL, NULL); + } } static void eevee_lightprobes_extract_from_cache(EEVEE_LightProbesInfo *pinfo, LightCache *lcache) @@ -772,6 +776,19 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } } } + + if (pinfo->num_planar > 0) { + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + DRW_PASS_CREATE(psl->probe_planar_downsample_ps, DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_downsample_sh_get(), + psl->probe_planar_downsample_ps); + + DRW_shgroup_uniform_texture_ref(grp, "source", &txl->planar_pool); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); + DRW_shgroup_call_procedural_triangles(grp, pinfo->num_planar, NULL); + } } /* -------------------------------------------------------------------- */ @@ -787,32 +804,43 @@ typedef struct EEVEE_BakeRenderData { static void render_cubemap(void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data, const float pos[3], - float clipsta, - float clipend) + float near, + float far, + bool do_culling) { - DRWMatrixState matstate; - - /* Move to capture position */ - float posmat[4][4]; - unit_m4(posmat); - negate_v3_v3(posmat[3], pos); + EEVEE_StorageList *stl = user_data->vedata->stl; + DRWView **views = do_culling ? stl->g_data->bake_views : stl->g_data->world_views; - perspective_m4(matstate.winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend); - invert_m4_m4(matstate.wininv, matstate.winmat); + float winmat[4][4], viewmat[4][4]; + perspective_m4(winmat, -near, near, -near, near, near, far); - /* 1 - Render to each cubeface individually. - * We do this instead of using geometry shader because a) it's faster, - * b) it's easier than fixing the nodetree shaders (for view dependent effects). */ - for (int i = 0; i < 6; ++i) { - /* Setup custom matrices */ - mul_m4_m4m4(matstate.viewmat, cubefacemat[i], posmat); - mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat); - invert_m4_m4(matstate.persinv, matstate.persmat); - invert_m4_m4(matstate.viewinv, matstate.viewmat); - invert_m4_m4(matstate.wininv, matstate.winmat); + /* Prepare views at the same time for faster culling. */ + for (int i = 0; i < 6; i++) { + unit_m4(viewmat); + negate_v3_v3(viewmat[3], pos); + mul_m4_m4m4(viewmat, cubefacemat[i], viewmat); - DRW_viewport_matrix_override_set_all(&matstate); + if (do_culling) { + if (views[i] == NULL) { + views[i] = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + } + else { + DRW_view_update(views[i], viewmat, winmat, NULL, NULL); + } + } + else { + if (views[i] == NULL) { + const DRWView *default_view = DRW_view_default_get(); + views[i] = DRW_view_create_sub(default_view, viewmat, winmat); + } + else { + DRW_view_update_sub(views[i], viewmat, winmat); + } + } + } + for (int i = 0; i < 6; ++i) { + DRW_view_set_active(views[i]); callback(i, user_data); } } @@ -822,21 +850,16 @@ static void render_reflections(void (*callback)(int face, EEVEE_BakeRenderData * EEVEE_PlanarReflection *planar_data, int ref_count) { - DRWMatrixState matstate; - - float original_viewmat[4][4], original_winmat[4][4]; - DRW_viewport_matrix_get(original_viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(original_winmat, DRW_MAT_WIN); - + EEVEE_StorageList *stl = user_data->vedata->stl; + DRWView *main_view = stl->effects->taa_view; + DRWView **views = stl->g_data->planar_views; + /* Prepare views at the same time for faster culling. */ for (int i = 0; i < ref_count; ++i) { - /* Setup custom matrices */ - lightbake_planar_compute_render_matrices( - planar_data + i, &matstate, original_viewmat, original_winmat); - invert_m4_m4(matstate.persinv, matstate.persmat); - invert_m4_m4(matstate.viewinv, matstate.viewmat); - invert_m4_m4(matstate.wininv, matstate.winmat); - DRW_viewport_matrix_override_set_all(&matstate); + lightbake_planar_ensure_view(&planar_data[i], main_view, &views[i]); + } + for (int i = 0; i < ref_count; ++i) { + DRW_view_set_active(views[i]); callback(i, user_data); } } @@ -862,17 +885,20 @@ void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *UNUSED(sldata), .face_fb = face_fb, }; - render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f); + render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f, false); } static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_data) { EEVEE_ViewLayerData *sldata = user_data->sldata; EEVEE_PassList *psl = user_data->vedata->psl; + EEVEE_PrivateData *g_data = user_data->vedata->stl->g_data; + DRWView **views = g_data->bake_views; + struct GPUFrameBuffer **face_fb = user_data->face_fb; /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, user_data->vedata); + EEVEE_draw_shadows(sldata, user_data->vedata, views[face]); GPU_framebuffer_bind(face_fb[face]); GPU_framebuffer_clear_depth(face_fb[face], 1.0f); @@ -901,7 +927,7 @@ void EEVEE_lightbake_render_scene(EEVEE_ViewLayerData *sldata, .face_fb = face_fb, }; - render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip); + render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip, true); } static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *user_data) @@ -910,9 +936,9 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us EEVEE_ViewLayerData *sldata = user_data->sldata; EEVEE_PassList *psl = vedata->psl; EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_LightProbesInfo *pinfo = sldata->probes; - EEVEE_PlanarReflection *eplanar = pinfo->planar_data + layer; GPU_framebuffer_ensure_config(&fbl->planarref_fb, {GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer), @@ -928,18 +954,10 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us txl->planar_pool = e_data.planar_pool_placeholder; txl->planar_depth = e_data.depth_array_placeholder; - /* Be sure that cascaded shadow maps are updated. */ DRW_stats_group_start("Planar Reflection"); /* Be sure that cascaded shadow maps are updated. */ - EEVEE_draw_shadows(sldata, vedata); - - /* Compute offset plane equation (fix missing texels near reflection plane). */ - copy_v4_v4(sldata->clip_data.clip_planes[0], eplanar->plane_equation); - sldata->clip_data.clip_planes[0][3] += eplanar->clipsta; - /* Set clipping plane */ - DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data); - DRW_state_clip_planes_len_set(1); + EEVEE_draw_shadows(sldata, vedata, stl->g_data->planar_views[layer]); GPU_framebuffer_bind(fbl->planarref_fb); GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0); @@ -976,8 +994,6 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us } DRW_draw_pass(psl->transparent_pass); - DRW_state_clip_planes_reset(); - DRW_stats_group_end(); /* Restore */ @@ -1225,7 +1241,6 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_LightProbesInfo *pinfo = sldata->probes; - DRWMatrixState saved_mats; if (pinfo->num_planar == 0) { /* Disable SSR if we cannot read previous frame */ @@ -1234,9 +1249,6 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v return; } - /* We need to save the Matrices before overidding them */ - DRW_viewport_matrix_get_all(&saved_mats); - /* Temporary Remove all planar reflections (avoid lag effect). */ common_data->prb_num_planar = 0; /* Turn off ssr to avoid black specular */ @@ -1265,8 +1277,6 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v EEVEE_lightbake_filter_planar(vedata); } - DRW_viewport_matrix_override_set_all(&saved_mats); - if (DRW_state_is_image_render()) { /* Sort transparents because planar reflections could have re-sorted them. */ DRW_pass_sort_shgroup_z(vedata->psl->transparent_pass); @@ -1284,10 +1294,7 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if ((light_cache->flag & LIGHTCACHE_UPDATE_WORLD) && (light_cache->flag & LIGHTCACHE_BAKED) == 0) { - DRWMatrixState saved_mats; - DRW_viewport_matrix_get_all(&saved_mats); EEVEE_lightbake_update_world_quick(sldata, vedata, scene_eval); - DRW_viewport_matrix_override_set_all(&saved_mats); } } diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 270defb039b..e966fadbcdb 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -53,6 +53,8 @@ extern char datatoc_shadow_store_frag_glsl[]; extern char datatoc_shadow_copy_frag_glsl[]; extern char datatoc_concentric_samples_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + /* Prototypes */ static void eevee_light_setup(Object *ob, EEVEE_Light *evli); static float light_attenuation_radius_get(Light *la, float light_threshold); @@ -111,8 +113,11 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); if (!e_data.shadow_sh) { - e_data.shadow_sh = DRW_shader_create( - datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_glsl, NULL); + e_data.shadow_sh = DRW_shader_create_with_lib(datatoc_shadow_vert_glsl, + NULL, + datatoc_shadow_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } if (!sldata->lights) { @@ -258,7 +263,7 @@ static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl, DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur); DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } return *pass; } @@ -280,7 +285,7 @@ static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } return *pass; } @@ -314,7 +319,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) psl->shadow_cascade_store_high_pass = NULL; { - psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->shadow_cube_copy_pass, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_pass); @@ -322,12 +327,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } { - psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", - DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->shadow_cascade_copy_pass, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_pass); @@ -335,12 +339,12 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - psl->shadow_pass = DRW_pass_create("Shadow Pass", state); + DRW_PASS_CREATE(psl->shadow_pass, state); stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); } @@ -449,7 +453,7 @@ void EEVEE_lights_cache_shcaster_add(EEVEE_ViewLayerData *UNUSED(sldata), struct GPUBatch *geom, Object *ob) { - DRW_shgroup_call_object_add(stl->g_data->shadow_shgrp, geom, ob); + DRW_shgroup_call_object(stl->g_data->shadow_shgrp, geom, ob); } void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, @@ -479,7 +483,7 @@ void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); } - DRW_shgroup_call_object_add(grp, geom, ob); + DRW_shgroup_call_object(grp, geom, ob); } /* Make that object update shadow casting lights inside its influence bounding box. */ @@ -640,7 +644,7 @@ float light_attenuation_radius_get(Light *la, float light_threshold) /* Compute max light power. */ float power = max_fff(la->r, la->g, la->b); - power *= fabsf(la->energy); + power *= fabsf(la->energy / 100.0f); power *= max_ff(1.0f, la->spec_fac); /* Compute the distance (using the inverse square law) * at which the light power reaches the light_threshold. */ @@ -667,6 +671,9 @@ static void light_shape_parameters_set(EEVEE_Light *evli, const Light *la, float evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f); } } + else if (la->type == LA_SUN) { + evli->radius = max_ff(0.001f, tanf(la->sun_angle / 2.0f)); + } else { evli->radius = max_ff(0.001f, la->area_size); } @@ -678,7 +685,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) /* Make illumination power constant */ if (la->type == LA_AREA) { power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */ - 80.0f; /* XXX : Empirical, Fit cycles power */ + 0.8f; /* XXX : Empirical, Fit cycles power */ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { /* Scale power to account for the lower area of the ellipse compared to the surrounding * rectangle. */ @@ -686,8 +693,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) } } else if (la->type == LA_SPOT || la->type == LA_LOCAL) { - power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */ - M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */ + power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* 1/(4*r²*Pi²) */ /* for point lights (a.k.a radius == 0.0) */ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ @@ -964,7 +970,7 @@ static void frustum_min_bounding_sphere(const float corners[8][3], static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LightsInfo *linfo, EEVEE_LightEngineData *led, - DRWMatrixState *saved_mats, + DRWView *view, float view_near, float view_far, int sample_ofs) @@ -972,9 +978,10 @@ static void eevee_shadow_cascade_setup(Object *ob, Light *la = (Light *)ob->data; /* Camera Matrices */ - float(*persinv)[4] = saved_mats->mat[DRW_MAT_PERSINV]; - float(*vp_projmat)[4] = saved_mats->mat[DRW_MAT_WIN]; - bool is_persp = DRW_viewport_is_persp_get(); + float persinv[4][4], vp_projmat[4][4]; + DRW_view_persmat_get(view, persinv, true); + DRW_view_winmat_get(view, vp_projmat, false); + bool is_persp = DRW_view_is_persp_get(view); /* Lights Matrices */ int cascade_nbr = la->cascade_count; @@ -1280,19 +1287,52 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } } +static void eevee_ensure_cube_views(float near, float far, const float pos[3], DRWView *view[6]) +{ + float winmat[4][4], viewmat[4][4]; + perspective_m4(winmat, -near, near, -near, near, near, far); + + for (int i = 0; i < 6; i++) { + unit_m4(viewmat); + negate_v3_v3(viewmat[3], pos); + mul_m4_m4m4(viewmat, cubefacemat[i], viewmat); + + if (view[i] == NULL) { + view[i] = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + } + else { + DRW_view_update(view[i], viewmat, winmat, NULL, NULL); + } + } +} + +static void eevee_ensure_cascade_views(EEVEE_ShadowCascadeData *cascade_data, + int cascade_count, + DRWView *view[4]) +{ + for (int i = 0; i < cascade_count; i++) { + if (view[i] == NULL) { + view[i] = DRW_view_create(cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL, NULL); + } + else { + DRW_view_update(view[i], cascade_data->viewmat, cascade_data->projmat[i], NULL, NULL); + } + } +} + /* this refresh lights shadow buffers */ -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView *view) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_PrivateData *g_data = stl->g_data; EEVEE_LightsInfo *linfo = sldata->lights; const DRWContextState *draw_ctx = DRW_context_state_get(); const float light_threshold = draw_ctx->scene->eevee.light_threshold; Object *ob; int i; - DRWMatrixState saved_mats; int saved_ray_type = sldata->common_data.ray_type; /* TODO: make it optionnal if we don't draw shadows. */ @@ -1307,8 +1347,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]}, .radius = light_attenuation_radius_get(la, light_threshold), }; - cube_visible[i] = DRW_culling_sphere_test(&bsphere); + cube_visible[i] = DRW_culling_sphere_test(view, &bsphere); } + bool cascade_visible[MAX_SHADOW_CASCADE]; for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) { EEVEE_LightEngineData *led = EEVEE_light_data_get(ob); @@ -1319,12 +1360,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]); /* TODO: check against near/far instead of "local Z = 0" plane. * Or even the cascades AABB. */ - cascade_visible[i] = DRW_culling_plane_test(plane); + cascade_visible[i] = DRW_culling_plane_test(view, plane); } - /* We need to save the Matrices before overidding them */ - DRW_viewport_matrix_get_all(&saved_mats); - /* Cube Shadow Maps */ DRW_stats_group_start("Cube Shadow Maps"); /* Render each shadow to one layer of the array */ @@ -1336,11 +1374,6 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) continue; } - DRWMatrixState render_mats; - float(*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; - float(*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; - float(*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; - EEVEE_ShadowRender *srd = &linfo->shadow_render_data; EEVEE_ShadowCubeData *evscd = &led->data.scd; EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id; @@ -1351,32 +1384,16 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) srd->exponent = la->bleedexp; copy_v3_v3(srd->position, cube_data->position); - perspective_m4(winmat, - -srd->clip_near, - srd->clip_near, - -srd->clip_near, - srd->clip_near, - srd->clip_near, - srd->clip_far); - DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); + eevee_ensure_cube_views(srd->clip_near, srd->clip_far, srd->position, g_data->cube_views); + /* Render shadow cube */ /* Render 6 faces separately: seems to be faster for the general case. * The only time it's more beneficial is when the CPU culling overhead * outweigh the instancing overhead. which is rarely the case. */ for (int j = 0; j < 6; j++) { - /* TODO optimize */ - float tmp[4][4]; - unit_m4(tmp); - negate_v3_v3(tmp[3], srd->position); - mul_m4_m4m4(viewmat, cubefacemat[j], tmp); - mul_m4_m4m4(persmat, winmat, viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); - invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); - - DRW_viewport_matrix_override_set_all(&render_mats); + DRW_view_set_active(g_data->cube_views[j]); GPU_framebuffer_texture_cubeface_attach( sldata->shadow_cube_target_fb, sldata->shadow_cube_target, 0, j, 0); @@ -1442,9 +1459,8 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE; DRW_stats_group_end(); - DRW_viewport_matrix_override_set_all(&saved_mats); - float near = DRW_viewport_near_distance_get(); - float far = DRW_viewport_far_distance_get(); + float near = DRW_view_near_distance_get(view); + float far = DRW_view_far_distance_get(view); /* Cascaded Shadow Maps */ DRW_stats_group_start("Cascaded Shadow Maps"); @@ -1459,34 +1475,24 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_ShadowCascadeData *evscd = &led->data.scad; EEVEE_ShadowRender *srd = &linfo->shadow_render_data; - DRWMatrixState render_mats; - float(*winmat)[4] = render_mats.mat[DRW_MAT_WIN]; - float(*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW]; - float(*persmat)[4] = render_mats.mat[DRW_MAT_PERS]; - - eevee_shadow_cascade_setup( - ob, linfo, led, &saved_mats, near, far, effects->taa_current_sample - 1); - srd->clip_near = la->clipsta; srd->clip_far = la->clipend; srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size; DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); - copy_m4_m4(viewmat, evscd->viewmat); - invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat); + eevee_shadow_cascade_setup(ob, linfo, led, view, near, far, effects->taa_current_sample - 1); + + /* Meh, Reusing the cube views. */ + BLI_assert(MAX_CASCADE_NUM <= 6); + eevee_ensure_cascade_views(evscd, la->cascade_count, g_data->cube_views); /* Render shadow cascades */ /* Render cascade separately: seems to be faster for the general case. * The only time it's more beneficial is when the CPU culling overhead * outweigh the instancing overhead. which is rarely the case. */ for (int j = 0; j < la->cascade_count; j++) { - copy_m4_m4(winmat, evscd->projmat[j]); - copy_m4_m4(persmat, evscd->viewprojmat[j]); - invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat); - invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat); - - DRW_viewport_matrix_override_set_all(&render_mats); + DRW_view_set_active(g_data->cube_views[j]); GPU_framebuffer_texture_layer_attach( sldata->shadow_cascade_target_fb, sldata->shadow_cascade_target, 0, j, 0); @@ -1548,7 +1554,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_stats_group_end(); - DRW_viewport_matrix_override_set_all(&saved_mats); + DRW_view_set_active(view); DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data); DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */ diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 4be87bf1a5e..a998bd3a71b 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -72,17 +72,21 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, Scene *scene = draw_ctx->scene; if (LOOK_DEV_OVERLAY_ENABLED(v3d)) { - /* Viewport / Ball size. */ + /* Viewport / Spheres size. */ rcti rect; ED_region_visible_rect(draw_ctx->ar, &rect); - const int ball_size = max_ii(BLI_rcti_size_x(&rect) * 0.1f, 100.0f) * U.dpi_fac; + /* Make the viewport width scale the lookdev spheres a bit. + * Scale between 1000px and 2000px. */ + const float viewport_scale = clamp_f( + BLI_rcti_size_x(&rect) / (2000.0f * U.dpi_fac), 0.5f, 1.0f); + const int sphere_size = U.lookdev_sphere_size * U.dpi_fac * viewport_scale; - if (ball_size != effects->ball_size || rect.xmax != effects->anchor[0] || + if (sphere_size != effects->sphere_size || rect.xmax != effects->anchor[0] || rect.ymin != effects->anchor[1]) { - /* If ball size or anchor point moves, reset TAA to avoid ghosting issue. + /* If sphere size or anchor point moves, reset TAA to avoid ghosting issue. * This needs to happen early because we are changing taa_current_sample. */ - effects->ball_size = ball_size; + effects->sphere_size = sphere_size; effects->anchor[0] = rect.xmax; effects->anchor[1] = rect.ymin; EEVEE_temporal_sampling_reset(vedata); @@ -147,7 +151,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix); DRW_shgroup_uniform_float_copy(*grp, "backgroundAlpha", background_alpha); DRW_shgroup_uniform_vec3(*grp, "color", background_color, 1); - DRW_shgroup_call_add(*grp, geom, NULL); + DRW_shgroup_call(*grp, geom, NULL); if (!pinfo) { /* Do not fadeout when doing probe rendering, only when drawing the background */ DRW_shgroup_uniform_float( @@ -180,7 +184,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, } static void eevee_lookdev_apply_taa(const EEVEE_EffectsInfo *effects, - int ball_size, + int sphere_size, float winmat[4][4]) { if (DRW_state_is_image_render() || ((effects->enabled_effects & EFFECT_TAA) != 0)) { @@ -191,8 +195,8 @@ static void eevee_lookdev_apply_taa(const EEVEE_EffectsInfo *effects, BLI_halton_2d(ht_primes, ht_offset, effects->taa_current_sample, ht_point); EEVEE_temporal_sampling_offset_calc(ht_point, 1.5f, ofs); - winmat[3][0] += ofs[0] / ball_size; - winmat[3][1] += ofs[1] / ball_size; + winmat[3][0] += ofs[0] / sphere_size; + winmat[3][1] += ofs[1] / sphere_size; } } @@ -219,20 +223,28 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata) DRW_uniformbuffer_update(sldata->common_ubo, common); /* override matrices */ - DRWMatrixState matstate; - unit_m4(matstate.winmat); + float winmat[4][4], viewmat[4][4]; + unit_m4(winmat); + /* Look through the negative Z. */ + negate_v3(winmat[2]); - eevee_lookdev_apply_taa(effects, effects->ball_size, matstate.winmat); + eevee_lookdev_apply_taa(effects, effects->sphere_size, winmat); /* "Remove" view matrix location. Leaving only rotation. */ - DRW_viewport_matrix_get(matstate.viewmat, DRW_MAT_VIEW); - zero_v3(matstate.viewmat[3]); - mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat); - invert_m4_m4(matstate.wininv, matstate.winmat); - invert_m4_m4(matstate.viewinv, matstate.viewmat); - invert_m4_m4(matstate.persinv, matstate.persmat); + DRW_view_viewmat_get(NULL, viewmat, false); + zero_v3(viewmat[3]); - DRW_viewport_matrix_override_set_all(&matstate); + if (effects->lookdev_view) { + /* When rendering just update the view. This avoids recomputing the culling. */ + DRW_view_update_sub(effects->lookdev_view, viewmat, winmat); + } + else { + /* Using default view bypasses the culling. */ + const DRWView *default_view = DRW_view_default_get(); + effects->lookdev_view = DRW_view_create_sub(default_view, viewmat, winmat); + } + + DRW_view_set_active(effects->lookdev_view); /* Find the right framebuffers to render to. */ GPUFrameBuffer *fb = (effects->target_buffer == fbl->effect_color_fb) ? fbl->main_fb : @@ -242,30 +254,30 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata) GPU_framebuffer_bind(fb); - const int ball_margin = effects->ball_size / 6.0f; - float offset[2] = {0.0f, ball_margin}; + const int sphere_margin = effects->sphere_size / 6.0f; + float offset[2] = {0.0f, sphere_margin}; - offset[0] = effects->ball_size + ball_margin; + offset[0] = effects->sphere_size + sphere_margin; GPU_framebuffer_viewport_set(fb, effects->anchor[0] - offset[0], effects->anchor[1] + offset[1], - effects->ball_size, - effects->ball_size); + effects->sphere_size, + effects->sphere_size); DRW_draw_pass(psl->lookdev_diffuse_pass); - offset[0] = (effects->ball_size + ball_margin) + - (ball_margin + effects->ball_size + ball_margin); + offset[0] = (effects->sphere_size + sphere_margin) + + (sphere_margin + effects->sphere_size + sphere_margin); GPU_framebuffer_viewport_set(fb, effects->anchor[0] - offset[0], effects->anchor[1] + offset[1], - effects->ball_size, - effects->ball_size); + effects->sphere_size, + effects->sphere_size); DRW_draw_pass(psl->lookdev_glossy_pass); DRW_stats_group_end(); - DRW_viewport_matrix_override_unset_all(); + DRW_view_set_active(NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 456f4bdb5f1..456f312f1df 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -48,6 +48,7 @@ static struct { char *frag_shader_lib; char *vert_shader_str; + char *vert_shadow_shader_str; char *volume_shader_lib; struct GPUShader *default_prepass_sh; @@ -133,7 +134,7 @@ static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); @@ -196,7 +197,7 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut"); @@ -296,9 +297,6 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_PROBE) != 0) { BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n"); } - if ((options & VAR_MAT_FLAT) != 0) { - BLI_dynstr_append(ds, "#define USE_FLAT_NORMAL\n"); - } if ((options & VAR_MAT_CLIP) != 0) { BLI_dynstr_append(ds, "#define USE_ALPHA_CLIP\n"); } @@ -317,9 +315,6 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_REFRACT) != 0) { BLI_dynstr_append(ds, "#define USE_REFRACTION\n"); } - if ((options & VAR_MAT_SSS) != 0) { - BLI_dynstr_append(ds, "#define USE_SSS\n"); - } if ((options & VAR_MAT_SSSALBED) != 0) { BLI_dynstr_append(ds, "#define USE_SSS_ALBEDO\n"); } @@ -332,9 +327,6 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_ESM) != 0) { BLI_dynstr_append(ds, "#define SHADOW_ESM\n"); } - if (((options & VAR_MAT_VOLUME) != 0) && ((options & VAR_MAT_BLEND) != 0)) { - BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND_VOLUMETRICS\n"); - } if ((options & VAR_MAT_LOOKDEV) != 0) { /* Auto config shadow method. Avoid more permutation. */ BLI_assert((options & (VAR_MAT_VSM | VAR_MAT_ESM)) == 0); @@ -381,6 +373,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, bool use_alpha_blend) { LightCache *lcache = vedata->stl->g_data->light_cache; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (ssr_id == NULL) { static int no_ssr = -1.0f; @@ -393,7 +386,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo); if (use_diffuse || use_glossy || use_refract) { DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); @@ -402,14 +394,7 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); } if ((use_diffuse || use_glossy) && !use_ssrefraction) { - if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) { - DRW_shgroup_uniform_texture_ref( - shgrp, "horizonBuffer", &vedata->stl->effects->gtao_horizons); - } - else { - /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); - } + DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &effects->gtao_horizons); } if (use_diffuse) { DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex); @@ -428,11 +413,9 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp, DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); } } - - if ((vedata->stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0 && use_alpha_blend) { - /* Do not use history buffers as they already have been swapped */ - DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &vedata->txl->volume_scatter); - DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &vedata->txl->volume_transmittance); + if (use_alpha_blend) { + DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &effects->volume_scatter); + DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &effects->volume_transmit); } } @@ -612,18 +595,23 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, e_data.vert_shader_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl); - e_data.default_background = DRW_shader_create( - datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); + e_data.vert_shadow_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl); - e_data.default_prepass_sh = DRW_shader_create( - datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, NULL); - - e_data.default_prepass_clip_sh = DRW_shader_create( - datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); + e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); char *vert_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_prepass_vert_glsl); + e_data.default_prepass_sh = DRW_shader_create(vert_str, NULL, datatoc_prepass_frag_glsl, NULL); + + e_data.default_prepass_clip_sh = DRW_shader_create( + vert_str, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); + e_data.default_hair_prepass_sh = DRW_shader_create( vert_str, NULL, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n"); @@ -656,8 +644,8 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, { /* Update view_vecs */ float invproj[4][4], winmat[4][4]; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_get(invproj, DRW_MAT_WININV); + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_winmat_get(NULL, invproj, true); EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs); } @@ -743,7 +731,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, bool use_blend, bool use_multiply, bool use_refract, - bool use_sss, bool use_translucency, int shadow_method) { @@ -751,27 +738,11 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; - if (use_blend) { - options |= VAR_MAT_BLEND; - } - if (use_multiply) { - options |= VAR_MAT_MULT; - } - if (use_refract) { - options |= VAR_MAT_REFRACT; - } - if (use_sss) { - options |= VAR_MAT_SSS; - } - if (use_sss && effects->sss_separate_albedo) { - options |= VAR_MAT_SSSALBED; - } - if (use_translucency) { - options |= VAR_MAT_TRANSLUC; - } - if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) { - options |= VAR_MAT_VOLUME; - } + SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); + SET_FLAG_FROM_TEST(options, use_multiply, VAR_MAT_MULT); + SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT); + SET_FLAG_FROM_TEST(options, effects->sss_separate_albedo, VAR_MAT_SSSALBED); + SET_FLAG_FROM_TEST(options, use_translucency, VAR_MAT_TRANSLUC); options |= eevee_material_shadow_option(shadow_method); @@ -832,16 +803,9 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; - if (use_hashed_alpha) { - options |= VAR_MAT_HASH; - } - else { - options |= VAR_MAT_CLIP; - } - - if (is_shadow) { - options |= VAR_MAT_SHADOW; - } + SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH); + SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP); + SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW); GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true); if (mat) { @@ -856,7 +820,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, ma, engine, options, - (is_shadow) ? datatoc_shadow_vert_glsl : + (is_shadow) ? e_data.vert_shadow_shader_str : e_data.vert_shader_str, NULL, frag_str, @@ -905,28 +869,16 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLaye EEVEE_Data *vedata, DRWPass *pass, bool is_hair, - bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) { - EEVEE_EffectsInfo *effects = vedata->stl->effects; static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; int options = VAR_MAT_MESH; - if (is_hair) { - options |= VAR_MAT_HAIR; - } - if (is_flat_normal) { - options |= VAR_MAT_FLAT; - } - if (use_blend) { - options |= VAR_MAT_BLEND; - } - if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) { - options |= VAR_MAT_VOLUME; - } + SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); + SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND); options |= eevee_material_shadow_option(shadow_method); @@ -949,7 +901,6 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa ParticleSystem *psys, ModifierData *md, bool is_hair, - bool is_flat_normal, bool use_ssr, int shadow_method) { @@ -957,14 +908,11 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa ssr_id = (use_ssr) ? 1 : -1; int options = VAR_MAT_MESH; + EEVEE_PassList *psl = vedata->psl; + BLI_assert(!is_hair || (ob && psys && md)); - if (is_hair) { - options |= VAR_MAT_HAIR; - } - if (is_flat_normal) { - options |= VAR_MAT_FLAT; - } + SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR); options |= eevee_material_shadow_option(shadow_method); @@ -972,17 +920,16 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa create_default_shader(options); } - if (vedata->psl->default_pass[options] == NULL) { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE; - vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); + if (psl->default_pass[options] == NULL) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; + DRW_PASS_CREATE(psl->default_pass[options], state); /* XXX / WATCH: This creates non persistent binds for the ubos and textures. * But it's currently OK because the following shgroups does not add any bind. * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ if (!is_hair) { DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], - vedata->psl->default_pass[options]); + psl->default_pass[options]); add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false); } } @@ -1010,8 +957,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } { - psl->background_pass = DRW_pass_create("Background Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + DRW_PASS_CREATE(psl->background_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = NULL; @@ -1043,7 +989,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); break; case GPU_MAT_QUEUED: /* TODO Bypass probe compilation. */ @@ -1062,96 +1008,85 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp = DRW_shgroup_create(e_data.default_background, psl->background_pass); DRW_shgroup_uniform_vec3(grp, "color", col, 1); DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - DRW_shgroup_call_add(grp, geom, NULL); + DRW_shgroup_call(grp, geom, NULL); } } { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE; - psl->depth_pass = DRW_pass_create("Depth Pass", state); + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRW_PASS_CREATE(psl->depth_pass, state); stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", state); + DRW_PASS_CREATE(psl->depth_pass_cull, state); stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass_cull); - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE; - psl->depth_pass_clip = DRW_pass_create("Depth Pass Clip", state); + state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; + DRW_PASS_CREATE(psl->depth_pass_clip, state); stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip); - DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip, "clip_block", sldata->clip_ubo); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK; - psl->depth_pass_clip_cull = DRW_pass_create("Depth Pass Cull Clip", state); + DRW_PASS_CREATE(psl->depth_pass_clip_cull, state); stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip_cull); - DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE; - psl->material_pass = DRW_pass_create("Material Pass", state); - psl->material_pass_cull = DRW_pass_create("Material Pass Cull", state | DRW_STATE_CULL_BACK); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES; + DRW_PASS_CREATE(psl->material_pass, state); + DRW_PASS_CREATE(psl->material_pass_cull, state | DRW_STATE_CULL_BACK); } { - DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE; - psl->refract_depth_pass = DRW_pass_create("Refract Depth Pass", state); + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + DRW_PASS_CREATE(psl->refract_depth_pass, state); stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->refract_depth_pass); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; - psl->refract_depth_pass_cull = DRW_pass_create("Refract Depth Pass Cull", state); + DRW_PASS_CREATE(psl->refract_depth_pass_cull, state); stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, psl->refract_depth_pass_cull); - state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE; - psl->refract_depth_pass_clip = DRW_pass_create("Refract Depth Pass Clip", state); + state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; + DRW_PASS_CREATE(psl->refract_depth_pass_clip, state); stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip); - DRW_shgroup_uniform_block( - stl->g_data->refract_depth_shgrp_clip, "clip_block", sldata->clip_ubo); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK; - psl->refract_depth_pass_clip_cull = DRW_pass_create("Refract Depth Pass Cull Clip", state); + DRW_PASS_CREATE(psl->refract_depth_pass_clip_cull, state); stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create( e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull); - DRW_shgroup_uniform_block( - stl->g_data->refract_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); } { - DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE); - psl->refract_pass = DRW_pass_create("Opaque Refraction Pass", state); + DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES); + DRW_PASS_CREATE(psl->refract_pass, state); } { DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL); - psl->sss_pass = DRW_pass_create("Subsurface Pass", state); - psl->sss_pass_cull = DRW_pass_create("Subsurface Pass Cull", state | DRW_STATE_CULL_BACK); + DRW_STATE_WRITE_STENCIL); + DRW_PASS_CREATE(psl->sss_pass, state); + DRW_PASS_CREATE(psl->sss_pass_cull, state | DRW_STATE_CULL_BACK); e_data.sss_count = 0; } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE; - psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES; + DRW_PASS_CREATE(psl->transparent_pass, state); } { - psl->update_noise_pass = DRW_pass_create("Update Noise Pass", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->update_noise_pass, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass); DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex); DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } if (LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { @@ -1169,45 +1104,39 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_CULL_BACK; - psl->lookdev_diffuse_pass = DRW_pass_create("LookDev Diffuse Pass", state); + DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state); shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass); add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1); DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f); DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f); DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f); - DRW_shgroup_call_add(shgrp, sphere, NULL); + DRW_shgroup_call(shgrp, sphere, NULL); - psl->lookdev_glossy_pass = DRW_pass_create("LookDev Glossy Pass", state); + DRW_PASS_CREATE(psl->lookdev_glossy_pass, state); shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass); add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, true, true, false, false, false); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1); DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f); DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f); - DRW_shgroup_call_add(shgrp, sphere, NULL); + DRW_shgroup_call(shgrp, sphere, NULL); } } -#define ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata) \ +#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ do { \ - if (is_sculpt_mode_draw) { \ - DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); \ + if (oedata) { \ + DRW_shgroup_call_object_with_callback(shgrp, geom, ob, oedata); \ } \ else { \ - if (oedata) { \ - DRW_shgroup_call_object_add_with_callback( \ - shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \ - } \ - else { \ - DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \ - } \ + DRW_shgroup_call_object(shgrp, geom, ob); \ } \ } while (0) -#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, ma, geom, oedata) \ +#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \ do { \ if (shgrp) { \ - ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata); \ + ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \ } \ } while (0) @@ -1221,8 +1150,6 @@ static void material_opaque(Material *ma, GHash *material_hash, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - bool do_cull, - bool use_flat_nor, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth, struct DRWShadingGroup **shgrp, @@ -1242,11 +1169,11 @@ static void material_opaque(Material *ma, float *spec_p = &ma->spec; float *rough_p = &ma->roughness; + const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_ssrefract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((effects->enabled_effects & EFFECT_REFRACT) != 0); - bool use_sss = ((effects->enabled_effects & EFFECT_SSS) != 0); - const bool use_translucency = use_sss && ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); + const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); @@ -1262,7 +1189,6 @@ static void material_opaque(Material *ma, false, false, use_ssrefract, - use_sss, use_translucency, linfo->shadow_method) : NULL; @@ -1278,15 +1204,8 @@ static void material_opaque(Material *ma, static float half = 0.5f; /* Shading */ - *gpumat = EEVEE_material_mesh_get(scene, - ma, - vedata, - false, - false, - use_ssrefract, - use_sss, - use_translucency, - linfo->shadow_method); + *gpumat = EEVEE_material_mesh_get( + scene, ma, vedata, false, false, use_ssrefract, use_translucency, linfo->shadow_method); eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); @@ -1364,10 +1283,10 @@ static void material_opaque(Material *ma, int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? &first_ssr : &no_ssr; + const bool use_sss = GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS); use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE); use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY); use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT); - use_sss = use_sss && GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS); *shgrp = DRW_shgroup_material_create( *gpumat, @@ -1442,7 +1361,7 @@ static void material_opaque(Material *ma, if (*shgrp == NULL) { bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); *shgrp = EEVEE_default_shading_group_get( - sldata, vedata, NULL, NULL, NULL, false, use_flat_nor, use_ssr, linfo->shadow_method); + sldata, vedata, NULL, NULL, NULL, false, use_ssr, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1474,8 +1393,6 @@ static void material_opaque(Material *ma, static void material_transparent(Material *ma, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - bool do_cull, - bool use_flat_nor, struct GPUMaterial **gpumat, struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth) @@ -1486,6 +1403,7 @@ static void material_transparent(Material *ma, EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_LightsInfo *linfo = sldata->lights; + const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0; const bool use_ssrefract = (((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0)); float *color_p = &ma->r; @@ -1506,7 +1424,6 @@ static void material_transparent(Material *ma, (ma->blend_method == MA_BM_MULTIPLY), use_ssrefract, false, - false, linfo->shadow_method); switch (GPU_material_status(*gpumat)) { @@ -1548,14 +1465,8 @@ static void material_transparent(Material *ma, /* Fallback to default shader */ if (*shgrp == NULL) { - *shgrp = EEVEE_default_shading_group_create(sldata, - vedata, - psl->transparent_pass, - false, - use_flat_nor, - true, - false, - linfo->shadow_method); + *shgrp = EEVEE_default_shading_group_create( + sldata, vedata, psl->transparent_pass, false, true, false, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1594,7 +1505,6 @@ static void material_transparent(Material *ma, /* Depth prepass */ if (use_prepass) { *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); - DRW_shgroup_uniform_block(*shgrp_depth, "clip_block", sldata->clip_ubo); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; @@ -1604,6 +1514,16 @@ static void material_transparent(Material *ma, } } +/* Return correct material or &defmaterial if slot is empty. */ +BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot) +{ + Material *ma = give_current_material(ob, slot + 1); + if (ma == NULL) { + ma = &defmaterial; + } + return ma; +} + void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, @@ -1615,17 +1535,14 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, Scene *scene = draw_ctx->scene; GHash *material_hash = stl->g_data->material_hash; - const bool do_cull = (draw_ctx->v3d && - (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING)); - const bool is_sculpt_mode = (ob->sculpt != NULL); + bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); /* For now just force fully shaded with eevee when supported. */ - const bool is_sculpt_mode_draw = ob->sculpt && ob->sculpt->pbvh && - BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES; - const bool is_default_mode_shader = is_sculpt_mode; + is_sculpt_mode = is_sculpt_mode && + !(ob->sculpt->pbvh && BKE_pbvh_type(ob->sculpt->pbvh) == PBVH_FACES); /* First get materials for this mesh. */ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol)); + const int materials_len = MAX2(1, ob->totcol); struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len); struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array, @@ -1635,45 +1552,24 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len); - - bool use_flat_nor = false; - - if (is_default_mode_shader) { - if (is_sculpt_mode_draw) { - use_flat_nor = DRW_object_is_flat_normal(ob); - } - } + struct Material **ma_array = BLI_array_alloca(ma_array, materials_len); for (int i = 0; i < materials_len; ++i) { - Material *ma; - - if (is_sculpt_mode_draw) { - ma = NULL; - } - else { - ma = give_current_material(ob, i + 1); - } - + ma_array[i] = eevee_object_material_get(ob, i); gpumat_array[i] = NULL; gpumat_depth_array[i] = NULL; shgrp_array[i] = NULL; shgrp_depth_array[i] = NULL; shgrp_depth_clip_array[i] = NULL; - if (ma == NULL) { - ma = &defmaterial; - } - - switch (ma->blend_method) { + switch (ma_array[i]->blend_method) { case MA_BM_SOLID: case MA_BM_CLIP: case MA_BM_HASHED: - material_opaque(ma, + material_opaque(ma_array[i], material_hash, sldata, vedata, - do_cull, - use_flat_nor, &gpumat_array[i], &gpumat_depth_array[i], &shgrp_array[i], @@ -1683,11 +1579,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, case MA_BM_ADD: case MA_BM_MULTIPLY: case MA_BM_BLEND: - material_transparent(ma, + material_transparent(ma_array[i], sldata, vedata, - do_cull, - use_flat_nor, &gpumat_array[i], &shgrp_array[i], &shgrp_depth_array[i]); @@ -1698,10 +1592,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, } } - if (is_sculpt_mode && is_sculpt_mode_draw == false) { - DRW_cache_mesh_sculpt_coords_ensure(ob); - } - /* Only support single volume material for now. */ /* XXX We rely on the previously compiled surface shader * to know if the material has a "volume nodetree". @@ -1716,7 +1606,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, int auto_layer_count; struct GPUBatch **mat_geom = NULL; - if (!is_sculpt_mode_draw) { + if (!is_sculpt_mode) { mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len, @@ -1725,17 +1615,19 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, &auto_layer_count); } - if (is_sculpt_mode_draw || mat_geom) { + if (is_sculpt_mode) { + /* Vcol is not supported in the modes that require PBVH drawing. */ + bool use_vcol = false; + DRW_shgroup_call_sculpt_with_materials(shgrp_array, ob, use_vcol); + DRW_shgroup_call_sculpt_with_materials(shgrp_depth_array, ob, use_vcol); + DRW_shgroup_call_sculpt_with_materials(shgrp_depth_clip_array, ob, use_vcol); + /* TODO(fclem): Support shadows in sculpt mode. */ + } + else if (mat_geom) { for (int i = 0; i < materials_len; ++i) { - if (!is_sculpt_mode_draw && mat_geom[i] == NULL) { + if (mat_geom[i] == NULL) { continue; } - EEVEE_ObjectEngineData *oedata = NULL; - Material *ma = give_current_material(ob, i + 1); - - if (ma == NULL) { - ma = &defmaterial; - } /* Do not render surface if we are rendering a volume object * and do not have a surface closure. */ @@ -1746,23 +1638,16 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* XXX TODO rewrite this to include the dupli objects. * This means we cannot exclude dupli objects from reflections!!! */ + EEVEE_ObjectEngineData *oedata = NULL; if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { oedata = EEVEE_object_data_ensure(ob); oedata->ob = ob; oedata->test_data = &sldata->probes->vis_data; } - /* Shading pass */ - ADD_SHGROUP_CALL(shgrp_array[i], ob, ma, mat_geom[i], oedata); - - /* Depth Prepass */ - ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma, mat_geom[i], oedata); - ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma, mat_geom[i], oedata); - - /* TODO(fclem): Don't support shadows in sculpt mode. */ - if (is_sculpt_mode_draw) { - break; - } + ADD_SHGROUP_CALL(shgrp_array[i], ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata); + ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata); char *name = auto_layer_names; for (int j = 0; j < auto_layer_count; ++j) { @@ -1785,19 +1670,19 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Shadow Pass */ struct GPUMaterial *gpumat; - switch (ma->blend_shadow) { + switch (ma_array[i]->blend_shadow) { case MA_BS_SOLID: EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob); *cast_shadow = true; break; case MA_BS_CLIP: - gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true); + gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true); EEVEE_lights_cache_shcaster_material_add( - sldata, psl, gpumat, mat_geom[i], ob, &ma->alpha_threshold); + sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold); *cast_shadow = true; break; case MA_BS_HASHED: - gpumat = EEVEE_material_mesh_depth_get(scene, ma, true, true); + gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true); EEVEE_lights_cache_shcaster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL); *cast_shadow = true; break; @@ -1810,7 +1695,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, } /* Volumetrics */ - if (((stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_volume_material) { + if (use_volume_material) { EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob); } } @@ -1845,11 +1730,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, } DRWShadingGroup *shgrp = NULL; - Material *ma = give_current_material(ob, part->omat); - - if (ma == NULL) { - ma = &defmaterial; - } + Material *ma = eevee_object_material_get(ob, part->omat - 1); float *color_p = &ma->r; float *metal_p = &ma->metallic; @@ -1861,7 +1742,6 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, shgrp = DRW_shgroup_hair_create( ob, psys, md, psl->depth_pass_clip, e_data.default_hair_prepass_clip_sh); - DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo); shgrp = NULL; if (ma->use_nodes && ma->nodetree) { @@ -1916,7 +1796,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, /* Fallback to default shader */ if (shgrp == NULL) { shgrp = EEVEE_default_shading_group_get( - sldata, vedata, ob, psys, md, true, false, use_ssr, sldata->lights->shadow_method); + sldata, vedata, ob, psys, md, true, use_ssr, sldata->lights->shadow_method); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); @@ -1931,11 +1811,16 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, } } -void EEVEE_materials_cache_finish(EEVEE_Data *vedata) +void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN); + + SET_FLAG_FROM_TEST(stl->effects->enabled_effects, e_data.sss_count > 0, EFFECT_SSS); + + /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ + EEVEE_subsurface_draw_init(sldata, vedata); } void EEVEE_materials_free(void) @@ -1945,6 +1830,7 @@ void EEVEE_materials_free(void) } MEM_SAFE_FREE(e_data.frag_shader_lib); MEM_SAFE_FREE(e_data.vert_shader_str); + MEM_SAFE_FREE(e_data.vert_shadow_shader_str); MEM_SAFE_FREE(e_data.volume_shader_lib); DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh); DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh); diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index 1ea1e086aea..9f989146b05 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -106,12 +106,12 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) g_data->mist_falloff *= 0.5f; /* Create Pass and shgroup. */ - psl->mist_accum_ps = DRW_pass_create("Mist Accum", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + DRW_PASS_CREATE(psl->mist_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index f8795a7ff0e..abd5bb82815 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -127,7 +127,7 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda /* Viewport Matrix */ /* Note: This does not have TAA jitter applied. */ - DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); + DRW_view_persmat_get(NULL, persmat, false); bool view_is_valid = (stl->g_data->view_updated == false); @@ -195,7 +195,7 @@ void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - psl->motion_blur = DRW_pass_create("Motion Blur", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 1); @@ -203,7 +203,7 @@ void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", effects->past_world_to_ndc); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 822df19f899..59def366695 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -41,6 +41,8 @@ static struct { struct GPUShader *gtao_layer_sh; struct GPUShader *gtao_debug_sh; struct GPUTexture *src_depth; + + struct GPUTexture *dummy_horizon_tx; } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; @@ -74,6 +76,11 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + if (!e_data.dummy_horizon_tx) { + float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + e_data.dummy_horizon_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, DRW_TEX_WRAP, pixel); + } + if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) { const float *viewport_size = DRW_viewport_size_get(); const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; @@ -117,7 +124,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } /* Cleanup */ - effects->gtao_horizons = NULL; + effects->gtao_horizons = e_data.dummy_horizon_tx; GPU_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); common_data->ao_settings = 0.0f; @@ -151,7 +158,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata /* Accumulation pass */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE; - psl->ao_accum_ps = DRW_pass_create("AO Accum", state); + DRW_PASS_CREATE(psl->ao_accum_ps, state); DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_accum_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); @@ -159,7 +166,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { /* Cleanup to release memory */ @@ -190,26 +197,25 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * the shading stage. This let us do correct shadowing for each diffuse / specular * lobe present in the shader using the correct normal. */ - psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->ao_horizon_search, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->ao_horizon_search_layer = DRW_pass_create("GTAO Horizon Search Layer", - DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.gtao_layer_sh, psl->ao_horizon_search_layer); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); if (G.debug_value == 6) { - psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->ao_horizon_debug, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); @@ -217,7 +223,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } } } @@ -304,4 +310,5 @@ void EEVEE_occlusion_free(void) DRW_SHADER_FREE_SAFE(e_data.gtao_sh); DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh); DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh); + DRW_TEXTURE_FREE_SAFE(e_data.dummy_horizon_tx); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index c3cd25923b2..2e652dff232 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -147,26 +147,24 @@ enum { VAR_MAT_MESH = (1 << 0), VAR_MAT_PROBE = (1 << 1), VAR_MAT_HAIR = (1 << 2), - VAR_MAT_FLAT = (1 << 3), - VAR_MAT_BLEND = (1 << 4), - VAR_MAT_VSM = (1 << 5), - VAR_MAT_ESM = (1 << 6), - VAR_MAT_VOLUME = (1 << 7), - VAR_MAT_LOOKDEV = (1 << 8), + VAR_MAT_BLEND = (1 << 3), + VAR_MAT_VSM = (1 << 4), + VAR_MAT_ESM = (1 << 5), + VAR_MAT_VOLUME = (1 << 6), + VAR_MAT_LOOKDEV = (1 << 7), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 9), + VAR_MAT_MAX = (1 << 8), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 10), - VAR_MAT_HASH = (1 << 11), - VAR_MAT_MULT = (1 << 12), - VAR_MAT_SHADOW = (1 << 13), - VAR_MAT_REFRACT = (1 << 14), - VAR_MAT_SSS = (1 << 15), - VAR_MAT_TRANSLUC = (1 << 16), - VAR_MAT_SSSALBED = (1 << 17), + VAR_MAT_CLIP = (1 << 9), + VAR_MAT_HASH = (1 << 10), + VAR_MAT_MULT = (1 << 11), + VAR_MAT_SHADOW = (1 << 12), + VAR_MAT_REFRACT = (1 << 13), + VAR_MAT_TRANSLUC = (1 << 15), + VAR_MAT_SSSALBED = (1 << 16), }; /* ************ PROBE UBO ************* */ @@ -335,9 +333,9 @@ typedef struct EEVEE_TextureList { struct GPUTexture *volume_prop_emission; struct GPUTexture *volume_prop_phase; struct GPUTexture *volume_scatter; - struct GPUTexture *volume_transmittance; + struct GPUTexture *volume_transmit; struct GPUTexture *volume_scatter_history; - struct GPUTexture *volume_transmittance_history; + struct GPUTexture *volume_transmit_history; struct GPUTexture *lookdev_grid_tx; struct GPUTexture *lookdev_cube_tx; @@ -554,6 +552,8 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *sss_stencil; /* Volumetrics */ int volume_current_sample; + struct GPUTexture *volume_scatter; + struct GPUTexture *volume_transmit; /* SSR */ bool reflection_trace_full; bool ssr_was_persp; @@ -571,10 +571,7 @@ typedef struct EEVEE_EffectsInfo { float taa_alpha; bool prev_drw_support; float prev_drw_persmat[4][4]; - float overide_persmat[4][4]; - float overide_persinv[4][4]; - float overide_winmat[4][4]; - float overide_wininv[4][4]; + struct DRWView *taa_view; /* Ambient Occlusion */ int ao_depth_layer; struct GPUTexture *ao_src_depth; /* pointer copy */ @@ -604,11 +601,13 @@ typedef struct EEVEE_EffectsInfo { /* Alpha Checker */ float color_checker_dark[4]; float color_checker_light[4]; + struct DRWView *checker_view; /* Other */ float prev_persmat[4][4]; /* Lookdev */ - int ball_size; + int sphere_size; int anchor[2]; + struct DRWView *lookdev_view; /* Bloom */ int bloom_iteration_len; float source_texel_size[2]; @@ -694,12 +693,6 @@ typedef struct EEVEE_CommonUniformBuffer { #define EEVEE_RAY_DIFFUSE 2 #define EEVEE_RAY_GLOSSY 3 -/* ***************** CLIP PLANES DATA **************** */ - -typedef struct EEVEE_ClipPlanesUniformBuffer { - float clip_planes[1][4]; /* must be less than MAX_CLIP_PLANES */ -} EEVEE_ClipPlanesUniformBuffer; - /* ************** SCENE LAYER DATA ************** */ typedef struct EEVEE_ViewLayerData { /* Lights */ @@ -735,9 +728,6 @@ typedef struct EEVEE_ViewLayerData { struct EEVEE_CommonUniformBuffer common_data; struct GPUUniformBuffer *common_ubo; - struct EEVEE_ClipPlanesUniformBuffer clip_data; - struct GPUUniformBuffer *clip_ubo; - struct LightCache *fallback_lightcache; } EEVEE_ViewLayerData; @@ -754,7 +744,7 @@ typedef struct EEVEE_ShadowCubeData { typedef struct EEVEE_ShadowCascadeData { short light_id, shadow_id, cascade_id, layer_id; /* World->Light->NDC : used for rendering the shadow map. */ - float viewprojmat[MAX_CASCADE_NUM][4][4]; + float viewprojmat[MAX_CASCADE_NUM][4][4]; /* Could be removed. */ float projmat[MAX_CASCADE_NUM][4][4]; float viewmat[4][4], viewinv[4][4]; float radius[MAX_CASCADE_NUM]; @@ -817,8 +807,7 @@ typedef struct EEVEE_PrivateData { struct DRWShadingGroup *refract_depth_shgrp_cull; struct DRWShadingGroup *refract_depth_shgrp_clip; struct DRWShadingGroup *refract_depth_shgrp_clip_cull; - struct DRWShadingGroup *cube_display_shgrp; - struct DRWShadingGroup *planar_display_shgrp; + struct DRWCallBuffer *planar_display_shgrp; struct GHash *material_hash; float background_alpha; /* TODO find a better place for this. */ /* Chosen lightcache: can come from Lookdev or the viewlayer. */ @@ -830,9 +819,6 @@ typedef struct EEVEE_PrivateData { bool valid_double_buffer; bool valid_taa_history; /* Render Matrices */ - float persmat[4][4], persinv[4][4]; - float viewmat[4][4], viewinv[4][4]; - float winmat[4][4], wininv[4][4]; float studiolight_matrix[3][3]; float overscan, overscan_pixels; float size_orig[2]; @@ -850,6 +836,14 @@ typedef struct EEVEE_PrivateData { float studiolight_glossy_clamp; float studiolight_filter_quality; + /** For rendering shadows. */ + struct DRWView *cube_views[6]; + /** For rendering probes. */ + struct DRWView *bake_views[6]; + /** Same as bake_views but does not generate culling infos. */ + struct DRWView *world_views[6]; + /** For rendering planar reflections. */ + struct DRWView *planar_views[MAX_PLANAR]; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -880,7 +874,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow); -void EEVEE_materials_cache_finish(EEVEE_Data *vedata); +void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo); struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo); @@ -890,7 +884,6 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, bool use_blend, bool use_multiply, bool use_refract, - bool use_sss, bool use_translucency, int shadow_method); struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma); @@ -921,7 +914,7 @@ void EEVEE_lights_cache_shcaster_material_add(EEVEE_ViewLayerData *sldata, void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct DRWView *view); void EEVEE_lights_free(void); /* eevee_shaders.c */ @@ -1027,7 +1020,8 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ -int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, @@ -1056,21 +1050,21 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], const float filter_size, float r_offset[2]); -void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, - float viewmat[4][4], - float persmat[4][4], - const double ht_point[2]); +void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2]); +void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata); void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata); /* eevee_volumes.c */ -int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample); void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob); +void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_free_smoke_textures(void); @@ -1082,6 +1076,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, Object *camera, const bool minimal); void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 961fe103251..8ef613f3711 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -53,6 +53,8 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); Scene *scene = DEG_get_evaluated_scene(depsgraph); const float *size_orig = DRW_viewport_size_get(); + float size_final[2]; + float camtexcofac[4]; /* Init default FB and render targets: * In render mode the default framebuffer is not generated @@ -73,10 +75,22 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * if (scene->eevee.flag & SCE_EEVEE_OVERSCAN) { g_data->overscan = scene->eevee.overscan / 100.0f; g_data->overscan_pixels = roundf(max_ff(size_orig[0], size_orig[1]) * g_data->overscan); + + madd_v2_v2v2fl(size_final, size_orig, (float[2]){2.0f, 2.0f}, g_data->overscan_pixels); + + camtexcofac[0] = size_final[0] / size_orig[0]; + camtexcofac[1] = size_final[1] / size_orig[1]; + + camtexcofac[2] = -camtexcofac[0] * g_data->overscan_pixels / size_final[0]; + camtexcofac[3] = -camtexcofac[1] * g_data->overscan_pixels / size_final[1]; + + print_v4_id(camtexcofac); } else { + copy_v2_v2(size_final, size_orig); g_data->overscan = 0.0f; g_data->overscan_pixels = 0.0f; + copy_v4_fl4(camtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); } /* XXX overiding viewport size. Simplify things but is not really 100% safe. */ @@ -100,30 +114,23 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); } - if (sldata->clip_ubo == NULL) { - sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); - } /* Set the pers & view matrix. */ + float winmat[4][4], viewmat[4][4], viewinv[4][4]; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); float frame = BKE_scene_frame_get(scene); - RE_GetCameraWindow(engine->re, ob_camera_eval, frame, g_data->winmat); - RE_GetCameraModelMatrix(engine->re, ob_camera_eval, g_data->viewinv); - RE_GetCameraWindowWithOverscan(engine->re, g_data->winmat, g_data->overscan); + RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat); + RE_GetCameraWindowWithOverscan(engine->re, winmat, g_data->overscan); + RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv); - invert_m4_m4(g_data->viewmat, g_data->viewinv); - mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat); - invert_m4_m4(g_data->persinv, g_data->persmat); - invert_m4_m4(g_data->wininv, g_data->winmat); + invert_m4_m4(viewmat, viewinv); - DRW_viewport_matrix_override_set(g_data->persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(g_data->persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(g_data->winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(g_data->wininv, DRW_MAT_WININV); - DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); + DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + DRW_view_camtexco_set(view, camtexcofac); + DRW_view_default_set(view); + DRW_view_set_active(view); /* EEVEE_effects_init needs to go first for TAA */ EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); @@ -304,6 +311,9 @@ static void eevee_render_result_normal(RenderLayer *rl, 1, rp->rect); + float viewinv[4][4]; + DRW_view_viewmat_get(NULL, viewinv, true); + /* Convert Eevee encoded normals to Blender normals. */ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) { if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) { @@ -322,7 +332,7 @@ static void eevee_render_result_normal(RenderLayer *rl, rp->rect[i + 1] = fenc[1] * g; rp->rect[i + 2] = 1.0f - f / 2.0f; - mul_mat3_m4_v3(g_data->viewinv, &rp->rect[i]); + mul_mat3_m4_v3(viewinv, &rp->rect[i]); } } } @@ -355,7 +365,10 @@ static void eevee_render_result_z(RenderLayer *rl, BLI_rcti_size_y(rect), rp->rect); - bool is_persp = DRW_viewport_is_persp_get(); + bool is_persp = DRW_view_is_persp_get(NULL); + + float viewmat[4][4]; + DRW_view_viewmat_get(NULL, viewmat, false); /* Convert ogl depth [0..1] to view Z [near..far] */ for (int i = 0; i < rp->rectx * rp->recty; ++i) { @@ -365,7 +378,7 @@ static void eevee_render_result_z(RenderLayer *rl, else { if (is_persp) { rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; - rp->rect[i] = g_data->winmat[3][2] / (rp->rect[i] + g_data->winmat[2][2]); + rp->rect[i] = viewmat[3][2] / (rp->rect[i] + viewmat[2][2]); } else { rp->rect[i] = -common_data->view_vecs[0][2] + @@ -486,10 +499,14 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_PrivateData *g_data = stl->g_data; /* FINISH CACHE */ - EEVEE_materials_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); + /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); @@ -529,25 +546,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl double offset[3] = {0.0, 0.0, 0.0}; double r[3]; - /* Restore winmat before jittering again. */ - copy_m4_m4(stl->effects->overide_winmat, g_data->winmat); /* Copy previous persmat to UBO data */ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); BLI_halton_3d(primes, offset, stl->effects->taa_current_sample, r); EEVEE_update_noise(psl, fbl, r); - EEVEE_temporal_sampling_matrices_calc(stl->effects, g_data->viewmat, g_data->persmat, r); + EEVEE_temporal_sampling_matrices_calc(stl->effects, r); EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); EEVEE_materials_init(sldata, stl, fbl); - /* Set matrices. */ - DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); - DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); - /* Refresh Probes */ EEVEE_lightprobes_refresh(sldata, vedata); EEVEE_lightprobes_refresh_planar(sldata, vedata); @@ -562,7 +569,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Refresh Shadows */ EEVEE_lights_update(sldata, vedata); - EEVEE_draw_shadows(sldata, vedata); + EEVEE_draw_shadows(sldata, vedata, stl->effects->taa_view); + + /* Set matrices. */ + DRW_view_set_active(stl->effects->taa_view); /* Set ray type. */ sldata->common_data.ray_type = EEVEE_RAY_CAMERA; diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 22c7dd00b97..33a8383fe90 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -127,7 +127,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)}); } - const bool is_persp = DRW_viewport_is_persp_get(); + const bool is_persp = DRW_view_is_persp_get(NULL); if (effects->ssr_was_persp != is_persp) { effects->ssr_was_persp = is_persp; DRW_viewport_request_redraw(); @@ -215,7 +215,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v * mipmap for each ray using its pdf. (filtered importance sampling) * We then evaluate the lighting from the probes and mix the results together. */ - psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->ssr_raytrace, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); @@ -230,9 +230,9 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v if (!effects->reflection_trace_full) { DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); } - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); - psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + DRW_PASS_CREATE(psl->ssr_resolve, DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); @@ -253,7 +253,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); } - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index dbb43e16385..34a3e723161 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -110,8 +110,11 @@ void EEVEE_shaders_lightprobe_shaders_init(void) e_data.probe_filter_glossy_sh = DRW_shader_create( datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines); - e_data.probe_default_sh = DRW_shader_create( - datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL); + e_data.probe_default_sh = DRW_shader_create_with_lib(datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); MEM_freeN(shader_str); @@ -178,8 +181,12 @@ GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void) GPUShader *EEVEE_shaders_default_studiolight_sh_get(void) { if (e_data.probe_default_studiolight_sh == NULL) { - e_data.probe_default_studiolight_sh = DRW_shader_create( - datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, "#define LOOKDEV\n"); + e_data.probe_default_studiolight_sh = DRW_shader_create_with_lib( + datatoc_background_vert_glsl, + NULL, + datatoc_default_world_frag_glsl, + datatoc_common_view_lib_glsl, + "#define LOOKDEV\n"); } return e_data.probe_default_studiolight_sh; } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index cbe0f474ac7..19aefd03e72 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -59,30 +59,30 @@ static void eevee_create_shader_subsurface(void) MEM_freeN(frag_str); } -int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const float *viewport_size = DRW_viewport_size_get(); - const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - if (scene_eval->eevee.flag & SCE_EEVEE_SSS_ENABLED) { - effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; - effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0; - common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; + effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0; + common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; +} - /* Shaders */ - if (!e_data.sss_sh[0]) { - eevee_create_shader_subsurface(); - } +void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const float *viewport_size = DRW_viewport_size_get(); + const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; + if (effects->enabled_effects & EFFECT_SSS) { /* NOTE : we need another stencil because the stencil buffer is on the same texture * as the depth buffer we are sampling from. This could be avoided if the stencil is * a separate texture but that needs OpenGL 4.4 or ARB_texture_stencil8. @@ -124,18 +124,16 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) else { effects->sss_albedo = NULL; } - return EFFECT_SSS; } - - /* Cleanup to release memory */ - GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); - effects->sss_stencil = NULL; - effects->sss_blur = NULL; - effects->sss_data = NULL; - - return 0; + else { + /* Cleanup to release memory */ + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); + effects->sss_stencil = NULL; + effects->sss_blur = NULL; + effects->sss_data = NULL; + } } static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp) @@ -150,17 +148,14 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - - if (scene_eval->eevee.flag & SCE_EEVEE_SSS_ENABLED) { + if (effects->enabled_effects & EFFECT_SSS) { DRW_texture_ensure_fullscreen_2d(&txl->sss_dir_accum, GPU_RGBA16F, 0); DRW_texture_ensure_fullscreen_2d(&txl->sss_col_accum, GPU_RGBA16F, 0); GPUTexture *stencil_tex = effects->sss_stencil; if (GPU_depth_blitting_workaround()) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); /* Blitting stencil buffer does not work on macOS + Radeon Pro. * Blit depth instead and use sss_stencil's depth as depth texture, * and dtxl->depth as stencil mask. */ @@ -179,7 +174,7 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat /* Make the opaque refraction pass mask the sss. */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | - DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL; + DRW_STATE_WRITE_STENCIL; DRW_pass_state_set(vedata->psl->refract_pass, state); DRW_pass_foreach_shgroup(vedata->psl->refract_pass, &set_shgrp_stencil, NULL); } @@ -194,20 +189,19 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & EFFECT_SSS) != 0) { - /** Screen Space SubSurface Scattering overview - * TODO - */ - psl->sss_blur_ps = DRW_pass_create("Blur Horiz", - DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); - - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL; - psl->sss_resolve_ps = DRW_pass_create("Blur Vert", state); - psl->sss_accum_ps = DRW_pass_create("Resolve Accum", state); + /* Shaders */ + if (!e_data.sss_sh[0]) { + eevee_create_shader_subsurface(); } + + /** Screen Space SubSurface Scattering overview + * TODO + */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL; + DRW_PASS_CREATE(psl->sss_blur_ps, state); + DRW_PASS_CREATE(psl->sss_resolve_ps, state | DRW_STATE_ADDITIVE); + DRW_PASS_CREATE(psl->sss_accum_ps, state | DRW_STATE_ADDITIVE); } void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, @@ -229,7 +223,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1]; grp = DRW_shgroup_create(sh, psl->sss_resolve_ps); @@ -239,7 +233,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); if (effects->sss_separate_albedo) { DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); @@ -253,7 +247,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); if (effects->sss_separate_albedo) { DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 194fff9b93c..099147a82dd 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -139,25 +139,45 @@ void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], r_offset[1] = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size; } -void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, - float viewmat[4][4], - float persmat[4][4], - const double ht_point[2]) +void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2]) { const float *viewport_size = DRW_viewport_size_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; RenderData *rd = &scene->r; + float persmat[4][4], viewmat[4][4], winmat[4][4]; + DRW_view_persmat_get(NULL, persmat, false); + DRW_view_viewmat_get(NULL, viewmat, false); + DRW_view_winmat_get(NULL, winmat, false); + float ofs[2]; EEVEE_temporal_sampling_offset_calc(ht_point, rd->gauss, ofs); - window_translate_m4( - effects->overide_winmat, persmat, ofs[0] / viewport_size[0], ofs[1] / viewport_size[1]); + window_translate_m4(winmat, persmat, ofs[0] / viewport_size[0], ofs[1] / viewport_size[1]); + + BLI_assert(effects->taa_view != NULL); + + /* When rendering just update the view. This avoids recomputing the culling. */ + DRW_view_update_sub(effects->taa_view, viewmat, winmat); +} + +/* Update the matrices based on the current sample. + * Note: `DRW_MAT_PERS` and `DRW_MAT_VIEW` needs to read the original matrices. */ +void EEVEE_temporal_sampling_update_matrices(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + uint ht_primes[2] = {2, 3}; + + BLI_halton_2d(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); - mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); - invert_m4_m4(effects->overide_persinv, effects->overide_persmat); - invert_m4_m4(effects->overide_wininv, effects->overide_winmat); + EEVEE_temporal_sampling_matrices_calc(effects, ht_point); + + DRW_view_set_active(effects->taa_view); } void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata) @@ -169,8 +189,6 @@ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata) int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; - // EEVEE_FramebufferList *fbl = vedata->fbl; - // EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; int repro_flag = 0; @@ -178,17 +196,26 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data eevee_create_cdf_table_temporal_sampling(); } - /* Reset for each "redraw". When rendering using ogl render, + /** + * Reset for each "redraw". When rendering using ogl render, * we accumulate the redraw inside the drawing loop in eevee_draw_background(). - * But we do NOT accumulate between "redraw" (as in full draw manager drawloop) - * because the opengl render already does that. */ + **/ effects->taa_render_sample = 1; + effects->taa_view = NULL; + + /* Create a sub view to disable clipping planes (if any). */ + const DRWView *default_view = DRW_view_default_get(); + float viewmat[4][4], winmat[4][4]; + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_winmat_get(default_view, winmat, false); + effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); + DRW_view_clip_planes_set(effects->taa_view, NULL, 0); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); if ((scene_eval->eevee.taa_samples != 1) || DRW_state_is_image_render()) { - float persmat[4][4], viewmat[4][4]; + float persmat[4][4]; if (!DRW_state_is_image_render() && (scene_eval->eevee.flag & SCE_EEVEE_TAA_REPROJECTION)) { repro_flag = EFFECT_TAA_REPROJECT | EFFECT_VELOCITY_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | @@ -210,14 +237,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data effects->taa_total_sample = scene_eval->eevee.taa_samples; MAX2(effects->taa_total_sample, 0); - DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN); - /* The view is jittered by the oglrenderer. So avoid testing in this case. */ - if (!DRW_state_is_image_render()) { - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - copy_m4_m4(effects->prev_drw_persmat, persmat); - } + DRW_view_persmat_get(NULL, persmat, false); + view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); + copy_m4_m4(effects->prev_drw_persmat, persmat); /* Prevent ghosting from probe data. */ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()); @@ -227,23 +249,11 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data (effects->taa_current_sample < effects->taa_total_sample)) || DRW_state_is_image_render()) { if (view_is_valid) { - /* OGL render already jitter the camera. */ + /* Viewport rendering updates the matrices in `eevee_draw_background` */ if (!DRW_state_is_image_render()) { effects->taa_current_sample += 1; repro_flag = 0; - - double ht_point[2]; - double ht_offset[2] = {0.0, 0.0}; - uint ht_primes[2] = {2, 3}; - - BLI_halton_2d(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); - - EEVEE_temporal_sampling_matrices_calc(effects, viewmat, persmat, ht_point); - - DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV); + EEVEE_temporal_sampling_update_matrices(vedata); } } else { @@ -273,7 +283,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { struct GPUShader *sh = EEVEE_shaders_taa_resolve_sh_get(effects->enabled_effects); - psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->taa_resolve, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->taa_resolve); DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history); @@ -287,7 +297,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data else { DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); } - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -313,19 +323,15 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) DRW_draw_pass(psl->taa_resolve); /* Restore the depth from sample 1. */ - if (!DRW_state_is_image_render()) { - GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, fbl->main_fb, 0, GPU_DEPTH_BIT); - } + GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, fbl->main_fb, 0, GPU_DEPTH_BIT); SWAP_BUFFERS_TAA(); } else { - if (!DRW_state_is_image_render()) { - /* Save the depth buffer for the next frame. - * This saves us from doing anything special - * in the other mode engines. */ - GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT); - } + /* Save the depth buffer for the next frame. + * This saves us from doing anything special + * in the other mode engines. */ + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT); /* Do reprojection for noise reduction */ /* TODO : do AA jitter if in only render view. */ diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 76c8f010142..59f144b1faf 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -49,8 +49,8 @@ static struct { char *volumetric_common_lights_lib; struct GPUShader *volumetric_clear_sh; - struct GPUShader *volumetric_scatter_sh; - struct GPUShader *volumetric_scatter_with_lights_sh; + struct GPUShader *scatter_sh; + struct GPUShader *scatter_with_lights_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; @@ -60,6 +60,9 @@ static struct { GPUTexture *dummy_density; GPUTexture *dummy_flame; + GPUTexture *dummy_scatter; + GPUTexture *dummy_transmit; + /* List of all smoke domains rendered within this frame. */ ListBase smoke_domains; } e_data = {NULL}; /* Engine data */ @@ -100,22 +103,21 @@ static void eevee_create_shader_volumes(void) e_data.volumetric_common_lib, "#define VOLUMETRICS\n" "#define CLEAR\n"); - e_data.volumetric_scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, - datatoc_volumetric_scatter_frag_glsl, - e_data.volumetric_common_lights_lib, - SHADER_DEFINES - "#define VOLUMETRICS\n" - "#define VOLUME_SHADOW\n"); - e_data.volumetric_scatter_with_lights_sh = DRW_shader_create_with_lib( - datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, - datatoc_volumetric_scatter_frag_glsl, - e_data.volumetric_common_lights_lib, - SHADER_DEFINES - "#define VOLUMETRICS\n" - "#define VOLUME_LIGHTING\n" - "#define VOLUME_SHADOW\n"); + e_data.scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_scatter_frag_glsl, + e_data.volumetric_common_lights_lib, + SHADER_DEFINES + "#define VOLUMETRICS\n" + "#define VOLUME_SHADOW\n"); + e_data.scatter_with_lights_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_scatter_frag_glsl, + e_data.volumetric_common_lights_lib, + SHADER_DEFINES + "#define VOLUMETRICS\n" + "#define VOLUME_LIGHTING\n" + "#define VOLUME_SHADOW\n"); e_data.volumetric_integration_sh = DRW_shader_create_with_lib( datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, @@ -150,7 +152,7 @@ void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample) common_data->vol_jitter[2] = (float)ht_point[2]; } -int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -165,309 +167,207 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) BLI_listbase_clear(&e_data.smoke_domains); - if (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_ENABLED) { - - /* Shaders */ - if (!e_data.volumetric_scatter_sh) { - eevee_create_shader_volumes(); - } - - const int tile_size = scene_eval->eevee.volumetric_tile_size; - - /* Find Froxel Texture resolution. */ - int tex_size[3]; - - tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); - tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); - tex_size[2] = max_ii(scene_eval->eevee.volumetric_samples, 1); - - common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]); - common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]); - - /* TODO compute snap to maxZBuffer for clustered rendering */ - - if ((common_data->vol_tex_size[0] != tex_size[0]) || - (common_data->vol_tex_size[1] != tex_size[1]) || - (common_data->vol_tex_size[2] != tex_size[2])) { - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - common_data->vol_tex_size[0] = tex_size[0]; - common_data->vol_tex_size[1] = tex_size[1]; - common_data->vol_tex_size[2] = tex_size[2]; - - common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]); - common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]); - common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]); - } - - /* Like frostbite's paper, 5% blend of the new frame. */ - common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; - - if (txl->volume_prop_scattering == NULL) { - /* Volume properties: We evaluate all volumetric objects - * and store their final properties into each froxel */ - txl->volume_prop_scattering = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - txl->volume_prop_extinction = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - txl->volume_prop_emission = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - txl->volume_prop_phase = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_RG16F, DRW_TEX_FILTER, NULL); - - /* Volume scattering: We compute for each froxel the - * Scattered light towards the view. We also resolve temporal - * super sampling during this stage. */ - txl->volume_scatter = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - txl->volume_transmittance = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + const int tile_size = scene_eval->eevee.volumetric_tile_size; + + /* Find Froxel Texture resolution. */ + int tex_size[3]; + + tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); + tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); + tex_size[2] = max_ii(scene_eval->eevee.volumetric_samples, 1); + + common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]); + common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]); + + /* TODO compute snap to maxZBuffer for clustered rendering */ + if ((common_data->vol_tex_size[0] != tex_size[0]) || + (common_data->vol_tex_size[1] != tex_size[1]) || + (common_data->vol_tex_size[2] != tex_size[2])) { + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmit); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmit_history); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + copy_v3_v3_int(common_data->vol_tex_size, tex_size); + + common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]); + common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]); + common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]); + } - /* Final integration: We compute for each froxel the - * amount of scattered light and extinction coef at this - * given depth. We use theses textures as double buffer - * for the volumetric history. */ - txl->volume_scatter_history = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - txl->volume_transmittance_history = DRW_texture_create_3d( - tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); - } + /* Like frostbite's paper, 5% blend of the new frame. */ + common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; - /* Temporal Super sampling jitter */ - uint ht_primes[3] = {3, 7, 2}; - uint current_sample = 0; + /* Temporal Super sampling jitter */ + uint ht_primes[3] = {3, 7, 2}; + uint current_sample = 0; - /* If TAA is in use do not use the history buffer. */ - bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0); + /* If TAA is in use do not use the history buffer. */ + bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0); - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL); - } + if (draw_ctx->evil_C != NULL) { + struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); + do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL); + } - if (do_taa) { - common_data->vol_history_alpha = 0.0f; - current_sample = effects->taa_current_sample - 1; - effects->volume_current_sample = -1; - } - else { - const uint max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]); - current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) % - max_sample; - if (current_sample != max_sample - 1) { - DRW_viewport_request_redraw(); - } + if (do_taa) { + common_data->vol_history_alpha = 0.0f; + current_sample = effects->taa_current_sample - 1; + effects->volume_current_sample = -1; + } + else { + const uint max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]); + current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) % + max_sample; + if (current_sample != max_sample - 1) { + DRW_viewport_request_redraw(); } + } - EEVEE_volumes_set_jitter(sldata, current_sample); + EEVEE_volumes_set_jitter(sldata, current_sample); - /* Framebuffer setup */ - GPU_framebuffer_ensure_config(&fbl->volumetric_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->volume_prop_scattering), - GPU_ATTACHMENT_TEXTURE(txl->volume_prop_extinction), - GPU_ATTACHMENT_TEXTURE(txl->volume_prop_emission), - GPU_ATTACHMENT_TEXTURE(txl->volume_prop_phase)}); - GPU_framebuffer_ensure_config(&fbl->volumetric_scat_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->volume_scatter), - GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance)}); - GPU_framebuffer_ensure_config(&fbl->volumetric_integ_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_history), - GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_history)}); - - float integration_start = scene_eval->eevee.volumetric_start; - float integration_end = scene_eval->eevee.volumetric_end; - common_data->vol_light_clamp = scene_eval->eevee.volumetric_light_clamp; - common_data->vol_shadow_steps = (float)scene_eval->eevee.volumetric_shadow_samples; - if ((scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_SHADOWS) == 0) { - common_data->vol_shadow_steps = 0; - } + float integration_start = scene_eval->eevee.volumetric_start; + float integration_end = scene_eval->eevee.volumetric_end; + common_data->vol_light_clamp = scene_eval->eevee.volumetric_light_clamp; + common_data->vol_shadow_steps = (float)scene_eval->eevee.volumetric_shadow_samples; + if ((scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_SHADOWS) == 0) { + common_data->vol_shadow_steps = 0; + } - /* Update view_vecs */ - float invproj[4][4], winmat[4][4]; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_get(invproj, DRW_MAT_WININV); - EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs); - - if (DRW_viewport_is_persp_get()) { - float sample_distribution = scene_eval->eevee.volumetric_sample_distribution; - sample_distribution = 4.0f * (1.00001f - sample_distribution); - - const float clip_start = common_data->view_vecs[0][2]; - /* Negate */ - float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f); - float far = integration_end = min_ff(-integration_end, near - 1e-4f); - - common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) / - (far - near); - common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near; - common_data->vol_depth_param[2] = sample_distribution; - } - else { - const float clip_start = common_data->view_vecs[0][2]; - const float clip_end = clip_start + common_data->view_vecs[1][2]; - integration_start = min_ff(integration_end, clip_start); - integration_end = max_ff(-integration_end, clip_end); - - common_data->vol_depth_param[0] = integration_start; - common_data->vol_depth_param[1] = integration_end; - common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start); - } + /* Update view_vecs */ + float invproj[4][4], winmat[4][4]; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_winmat_get(NULL, invproj, true); + EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs); + + if (DRW_view_is_persp_get(NULL)) { + float sample_distribution = scene_eval->eevee.volumetric_sample_distribution; + sample_distribution = 4.0f * (1.00001f - sample_distribution); + + const float clip_start = common_data->view_vecs[0][2]; + /* Negate */ + float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f); + float far = integration_end = min_ff(-integration_end, near - 1e-4f); + + common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) / + (far - near); + common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near; + common_data->vol_depth_param[2] = sample_distribution; + } + else { + const float clip_start = common_data->view_vecs[0][2]; + const float clip_end = clip_start + common_data->view_vecs[1][2]; + integration_start = min_ff(integration_end, clip_start); + integration_end = max_ff(-integration_end, clip_end); + + common_data->vol_depth_param[0] = integration_start; + common_data->vol_depth_param[1] = integration_end; + common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start); + } - /* Disable clamp if equal to 0. */ - if (common_data->vol_light_clamp == 0.0) { - common_data->vol_light_clamp = FLT_MAX; - } + /* Disable clamp if equal to 0. */ + if (common_data->vol_light_clamp == 0.0) { + common_data->vol_light_clamp = FLT_MAX; + } - common_data->vol_use_lights = (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_LIGHTS) != 0; + common_data->vol_use_lights = (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_LIGHTS) != 0; - return EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER; + if (!e_data.dummy_scatter) { + float scatter[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float transmit[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + e_data.dummy_scatter = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, scatter); + e_data.dummy_transmit = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, transmit); } - - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - - return 0; } void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - LightCache *lcache = stl->g_data->light_cache; EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - DRWShadingGroup *grp = NULL; - - /* Quick breakdown of the Volumetric rendering: - * - * The rendering is separated in 4 stages: - * - * - Material Parameters : we collect volume properties of - * all participating media in the scene and store them in - * a 3D texture aligned with the 3D frustum. - * This is done in 2 passes, one that clear the texture - * and/or evaluate the world volumes, and the 2nd one that - * additively render object volumes. - * - * - Light Scattering : the volume properties then are sampled - * and light scattering is evaluated for each cell of the - * volume texture. Temporal super-sampling (if enabled) occurs here. - * - * - Volume Integration : the scattered light and extinction is - * integrated (accumulated) along the view-rays. The result is stored - * for every cell in another texture. - * - * - Full-screen Resolve : From the previous stage, we get two - * 3D textures that contains integrated scattered light and extinction - * for "every" positions in the frustum. We only need to sample - * them and blend the scene color with those factors. This also - * work for alpha blended materials. - */ - - /* World pass is not additive as it also clear the buffer. */ - psl->volumetric_world_ps = DRW_pass_create("Volumetric World", DRW_STATE_WRITE_COLOR); - - /* World Volumetric */ - struct World *wo = scene->world; - if (wo != NULL && wo->use_nodes && wo->nodetree && - !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - - grp = DRW_shgroup_material_empty_tri_batch_create( - mat, psl->volumetric_world_ps, common_data->vol_tex_size[2]); - - if (grp) { - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - /* TODO (fclem): remove those (need to clean the GLSL files). */ - DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - - /* Fix principle volumetric not working with world materials. */ - DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); - DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); - DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1); - } - } + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + DRWShadingGroup *grp = NULL; - if (grp == NULL) { - /* If no world or volume material is present just clear the buffer with this drawcall */ - grp = DRW_shgroup_empty_tri_batch_create( - e_data.volumetric_clear_sh, psl->volumetric_world_ps, common_data->vol_tex_size[2]); + /* Shaders */ + if (!e_data.scatter_sh) { + eevee_create_shader_volumes(); + } - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + /* Quick breakdown of the Volumetric rendering: + * + * The rendering is separated in 4 stages: + * + * - Material Parameters : we collect volume properties of + * all participating media in the scene and store them in + * a 3D texture aligned with the 3D frustum. + * This is done in 2 passes, one that clear the texture + * and/or evaluate the world volumes, and the 2nd one that + * additively render object volumes. + * + * - Light Scattering : the volume properties then are sampled + * and light scattering is evaluated for each cell of the + * volume texture. Temporal super-sampling (if enabled) occurs here. + * + * - Volume Integration : the scattered light and extinction is + * integrated (accumulated) along the view-rays. The result is stored + * for every cell in another texture. + * + * - Full-screen Resolve : From the previous stage, we get two + * 3D textures that contains integrated scattered light and extinction + * for "every" positions in the frustum. We only need to sample + * them and blend the scene color with those factors. This also + * work for alpha blended materials. + */ + + /* World pass is not additive as it also clear the buffer. */ + DRW_PASS_CREATE(psl->volumetric_world_ps, DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->volumetric_objects_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + + /* World Volumetric */ + struct World *wo = scene->world; + if (wo != NULL && wo->use_nodes && wo->nodetree && + !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { + struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); + + if (GPU_material_use_domain_volume(mat)) { + grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); } - /* Volumetric Objects */ - psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", - DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + if (grp) { + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + /* TODO (fclem): remove those (need to clean the GLSL files). */ + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - struct GPUShader *scatter_sh = (common_data->vol_use_lights) ? - e_data.volumetric_scatter_with_lights_sh : - e_data.volumetric_scatter_sh; - psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create( - scatter_sh, psl->volumetric_scatter_ps, common_data->vol_tex_size[2]); - DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex); - DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); - DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); - DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering); - DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_prop_extinction); - DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &txl->volume_prop_emission); - DRW_shgroup_uniform_texture_ref(grp, "volumePhase", &txl->volume_prop_phase); - DRW_shgroup_uniform_texture_ref(grp, "historyScattering", &txl->volume_scatter_history); - DRW_shgroup_uniform_texture_ref( - grp, "historyTransmittance", &txl->volume_transmittance_history); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + /* Fix principle volumetric not working with world materials. */ + DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); + DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); + DRW_shgroup_uniform_vec2_copy(grp, "unftemperature", (float[2]){0.0f, 1.0f}); - psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", - DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, - psl->volumetric_integration_ps, - common_data->vol_tex_size[2]); - DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); - DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmittance); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_call_procedural_triangles(grp, common_data->vol_tex_size[2], NULL); - psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); - DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); - DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmittance); - DRW_shgroup_uniform_texture_ref(grp, "inSceneColor", &e_data.color_src); - DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); + effects->enabled_effects |= (EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER); + } + } + + if (grp == NULL) { + /* If no world or volume material is present just clear the buffer with this drawcall */ + grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + + DRW_shgroup_call_procedural_triangles(grp, common_data->vol_tex_size[2], NULL); } } @@ -500,28 +400,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, return; } - DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create( - mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]); - - /* Making sure it's updated. */ - invert_m4_m4(ob->imat, ob->obmat); + DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps); BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); - float(*imat)[4] = ob->imat; - - if ((ob->base_flag & BASE_FROM_DUPLI) != 0) { - /* TODO Remove from here and use a dedicated buffer. */ - EEVEE_InstanceVolumeMatrix *ivm = (EEVEE_InstanceVolumeMatrix *)DRW_drawdata_ensure( - &ob->id, - (DrawEngineType *)EEVEE_volumes_cache_object_add, - sizeof(EEVEE_InstanceVolumeMatrix), - NULL, - NULL); - copy_m4_m4(ivm->volume_mat, ob->imat); - imat = ivm->volume_mat; - } - /* TODO(fclem) remove those "unnecessary" UBOs */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); @@ -530,7 +412,6 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", imat); DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); @@ -578,6 +459,139 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1); DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1); } + + /* TODO Reduce to number of slices intersecting. */ + /* TODO Preemptive culling. */ + DRW_shgroup_call_procedural_triangles(grp, sldata->common_data.vol_tex_size[2], ob->obmat); + + vedata->stl->effects->enabled_effects |= (EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER); +} + +void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + LightCache *lcache = vedata->stl->g_data->light_cache; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + DRWShadingGroup *grp; + struct GPUShader *sh; + + DRW_PASS_CREATE(psl->volumetric_scatter_ps, DRW_STATE_WRITE_COLOR); + sh = (common_data->vol_use_lights) ? e_data.scatter_with_lights_sh : e_data.scatter_sh; + grp = DRW_shgroup_create(sh, psl->volumetric_scatter_ps); + DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex); + DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering); + DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_prop_extinction); + DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &txl->volume_prop_emission); + DRW_shgroup_uniform_texture_ref(grp, "volumePhase", &txl->volume_prop_phase); + DRW_shgroup_uniform_texture_ref(grp, "historyScattering", &txl->volume_scatter_history); + DRW_shgroup_uniform_texture_ref(grp, "historyTransmittance", &txl->volume_transmit_history); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + + DRW_shgroup_call_procedural_triangles(grp, common_data->vol_tex_size[2], NULL); + + DRW_PASS_CREATE(psl->volumetric_integration_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps); + DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + + DRW_shgroup_call_procedural_triangles(grp, common_data->vol_tex_size[2], NULL); + + DRW_PASS_CREATE(psl->volumetric_resolve_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); + DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit); + DRW_shgroup_uniform_texture_ref(grp, "inSceneColor", &e_data.color_src); + DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + + DRW_shgroup_call_procedural_triangles(grp, 1, NULL); + } +} + +void EEVEE_volumes_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + int *tex_size = common_data->vol_tex_size; + + if (txl->volume_prop_scattering == NULL) { + /* Volume properties: We evaluate all volumetric objects + * and store their final properties into each froxel */ + txl->volume_prop_scattering = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + txl->volume_prop_extinction = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + txl->volume_prop_emission = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + txl->volume_prop_phase = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_RG16F, DRW_TEX_FILTER, NULL); + + /* Volume scattering: We compute for each froxel the + * Scattered light towards the view. We also resolve temporal + * super sampling during this stage. */ + txl->volume_scatter = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + txl->volume_transmit = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + + /* Final integration: We compute for each froxel the + * amount of scattered light and extinction coef at this + * given depth. We use theses textures as double buffer + * for the volumetric history. */ + txl->volume_scatter_history = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + txl->volume_transmit_history = DRW_texture_create_3d( + tex_size[0], tex_size[1], tex_size[2], GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL); + } + + GPU_framebuffer_ensure_config(&fbl->volumetric_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_scattering), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_extinction), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_emission), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_phase)}); + GPU_framebuffer_ensure_config(&fbl->volumetric_scat_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_scatter), + GPU_ATTACHMENT_TEXTURE(txl->volume_transmit)}); + GPU_framebuffer_ensure_config(&fbl->volumetric_integ_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_history), + GPU_ATTACHMENT_TEXTURE(txl->volume_transmit_history)}); + + /* Usage happens after buffer have been swapped. */ + effects->volume_scatter = txl->volume_scatter_history; + effects->volume_transmit = txl->volume_transmit_history; + } + else { + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmit); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmit_history); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + + effects->volume_scatter = e_data.dummy_scatter; + effects->volume_transmit = e_data.dummy_transmit; + } } void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -590,23 +604,19 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { DRW_stats_group_start("Volumetrics"); - /* Step 1: Participating Media Properties */ GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); DRW_draw_pass(psl->volumetric_objects_ps); - /* Step 2: Scatter Light */ GPU_framebuffer_bind(fbl->volumetric_scat_fb); DRW_draw_pass(psl->volumetric_scatter_ps); - /* Step 3: Integration */ GPU_framebuffer_bind(fbl->volumetric_integ_fb); DRW_draw_pass(psl->volumetric_integration_ps); - /* Swap volume history buffers */ SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb); SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history); - SWAP(GPUTexture *, txl->volume_transmittance, txl->volume_transmittance_history); + SWAP(GPUTexture *, txl->volume_transmit, txl->volume_transmit_history); /* Restore */ GPU_framebuffer_bind(fbl->main_fb); @@ -660,12 +670,15 @@ void EEVEE_volumes_free(void) MEM_SAFE_FREE(e_data.volumetric_common_lib); MEM_SAFE_FREE(e_data.volumetric_common_lights_lib); + DRW_TEXTURE_FREE_SAFE(e_data.dummy_scatter); + DRW_TEXTURE_FREE_SAFE(e_data.dummy_transmit); + DRW_TEXTURE_FREE_SAFE(e_data.dummy_density); DRW_TEXTURE_FREE_SAFE(e_data.dummy_flame); DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); - DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh); - DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_with_lights_sh); + DRW_SHADER_FREE_SAFE(e_data.scatter_sh); + DRW_SHADER_FREE_SAFE(e_data.scatter_with_lights_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 3a5f20b952e..d7160aee340 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -15,7 +15,7 @@ uniform sampler2D maxzBuffer; uniform sampler2D minzBuffer; uniform sampler2DArray planarDepth; -#define cameraForward normalize(ViewMatrixInverse[2].xyz) +#define cameraForward ViewMatrixInverse[2].xyz #define cameraPos ViewMatrixInverse[3].xyz #define cameraVec \ ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward) @@ -836,18 +836,22 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) cl.radiance /= max(1e-8, cl.opacity); # ifdef USE_SSS - cl.sss_data.rgb = mix(cl1.sss_data.rgb, cl2.sss_data.rgb, fac); - cl.sss_data.a = (cl1.sss_data.a > 0.0) ? cl1.sss_data.a : cl2.sss_data.a; + /* Apply Mix on input */ + cl1.sss_data.rgb *= 1.0 - fac; + cl2.sss_data.rgb *= fac; + + /* Select biggest radius. */ + bool use_cl1 = (cl1.sss_data.a > cl2.sss_data.a); + cl.sss_data = (use_cl1) ? cl1.sss_data : cl2.sss_data; # ifdef USE_SSS_ALBEDO /* TODO Find a solution to this. Dither? */ - cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo; + cl.sss_albedo = (use_cl1) ? cl1.sss_albedo : cl2.sss_albedo; /* Add radiance that was supposed to be filtered but was rejected. */ - cl.radiance += (cl1.sss_data.a > 0.0) ? cl2.sss_data.rgb * cl2.sss_albedo : - cl1.sss_data.rgb * cl1.sss_albedo; + cl.radiance += (use_cl1) ? cl2.sss_data.rgb * cl2.sss_albedo : cl1.sss_data.rgb * cl1.sss_albedo; # else /* Add radiance that was supposed to be filtered but was rejected. */ - cl.radiance += (cl1.sss_data.a > 0.0) ? cl2.sss_data.rgb : cl1.sss_data.rgb; + cl.radiance += (use_cl1) ? cl2.sss_data.rgb : cl1.sss_data.rgb; # endif # endif @@ -894,7 +898,7 @@ layout(location = 4) out vec4 sssAlbedo; Closure nodetree_exec(void); /* Prototype */ -# if defined(USE_ALPHA_BLEND_VOLUMETRICS) +# if defined(USE_ALPHA_BLEND) /* Prototype because this file is included before volumetric_lib.glsl */ vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth); # endif @@ -908,7 +912,7 @@ void main() cl.opacity = 1.0; # endif -# if defined(USE_ALPHA_BLEND_VOLUMETRICS) +# if defined(USE_ALPHA_BLEND) /* XXX fragile, better use real viewport resolution */ vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy); fragColor.rgb = volumetric_resolve(vec4(cl.radiance, cl.opacity), uvs, gl_FragCoord.z).rgb; diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl index 0be2a8d6a12..70466479a29 100644 --- a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl @@ -5,9 +5,6 @@ uniform vec3 color; out vec4 FragColor; #ifdef LOOKDEV -uniform mat4 ProjectionMatrix; -uniform mat4 ProjectionMatrixInverse; -uniform mat4 ViewMatrixInverse; uniform mat3 StudioLightMatrix; uniform sampler2D image; uniform float studioLightBackground = 1.0; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl index 1c943bd51bc..588cd402bb3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl @@ -1,11 +1,12 @@ -in vec2 pos; - out int instance; out vec2 vPos; void main() { - instance = gl_InstanceID; - vPos = pos; + int v = gl_VertexID % 3; + vPos.x = -1.0 + float((v & 1) << 2); + vPos.y = -1.0 + float((v & 2) << 1); + + instance = gl_VertexID / 3; } diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 37b0ebb33cf..fe3225b1086 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -13,13 +13,8 @@ uniform sampler2DArray utilTex; in vec3 worldPosition; in vec3 viewPosition; -#ifdef USE_FLAT_NORMAL -flat in vec3 worldNormal; -flat in vec3 viewNormal; -#else in vec3 worldNormal; in vec3 viewNormal; -#endif #ifdef HAIR_SHADER in vec3 hairTangent; /* world space */ diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index 29ecbd694c9..cf20b3ff5b9 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -1,13 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelViewMatrix; -uniform mat3 WorldNormalMatrix; -#ifndef USE_ATTR -uniform mat4 ModelMatrix; -uniform mat3 NormalMatrix; -uniform mat4 ModelMatrixInverse; -#endif - #ifndef HAIR_SHADER in vec3 pos; in vec3 nor; @@ -16,20 +7,8 @@ in vec3 nor; out vec3 worldPosition; out vec3 viewPosition; -/* Used for planar reflections */ -/* keep in sync with EEVEE_ClipPlanesUniformBuffer */ -layout(std140) uniform clip_block -{ - vec4 ClipPlanes[1]; -}; - -#ifdef USE_FLAT_NORMAL -flat out vec3 worldNormal; -flat out vec3 viewNormal; -#else out vec3 worldNormal; out vec3 viewNormal; -#endif #ifdef HAIR_SHADER out vec3 hairTangent; @@ -61,23 +40,21 @@ void main() hairTime, hairThickness, hairThickTime); - - gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); - viewPosition = (ViewMatrix * vec4(pos, 1.0)).xyz; + worldNormal = cross(hairTangent, binor); worldPosition = pos; - hairTangent = normalize(hairTangent); - worldNormal = cross(binor, hairTangent); - viewNormal = mat3(ViewMatrix) * worldNormal; #else - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; - worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz; - worldNormal = normalize(WorldNormalMatrix * nor); - viewNormal = normalize(NormalMatrix * nor); + worldPosition = point_object_to_world(pos); + worldNormal = normalize(normal_object_to_world(nor)); #endif + /* No need to normalize since this is just a rotation. */ + viewNormal = normal_world_to_view(worldNormal); + + viewPosition = point_world_to_view(worldPosition); + gl_Position = point_world_to_ndc(worldPosition); + /* Used for planar reflections */ - gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), ClipPlanes[0]); + gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), clipPlanes[0]); #ifdef USE_ATTR pass_attr(pos); diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl index 9196253478a..2c7e0aca3fb 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl @@ -1,45 +1,38 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; -uniform mat4 ModelMatrixInverse; - -#ifdef CLIP_PLANES -/* keep in sync with DRWManager.view_data */ -layout(std140) uniform clip_block -{ - vec4 ClipPlanes[1]; -}; -#endif - #ifndef HAIR_SHADER in vec3 pos; #endif void main() { +#ifdef GPU_INTEL + /* Due to some shader compiler bug, we somewhat + * need to access gl_VertexID to make it work. even + * if it's actually dead code. */ + gl_Position.x = float(gl_VertexID); +#endif + #ifdef HAIR_SHADER float time, thick_time, thickness; - vec3 pos, tan, binor; + vec3 worldPosition, tan, binor; hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), ModelMatrixInverse, ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, - pos, + worldPosition, tan, binor, time, thickness, thick_time); - - gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); - vec4 worldPosition = vec4(pos, 1.0); #else - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0)); + vec3 worldPosition = point_object_to_world(pos); #endif + gl_Position = point_world_to_ndc(worldPosition); + #ifdef CLIP_PLANES - gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), ClipPlanes[0]); + gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), clipPlanes[0]); #endif /* TODO motion vectors */ } diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index f9225cd100b..6b06aab34d2 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -1,14 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -#ifdef MESH_SHADER -uniform mat4 ModelViewMatrix; -uniform mat3 WorldNormalMatrix; -# ifndef USE_ATTR -uniform mat4 ModelMatrix; -uniform mat3 NormalMatrix; -# endif -#endif - in vec3 pos; in vec3 nor; @@ -21,12 +11,22 @@ out vec3 viewNormal; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +#ifdef GPU_INTEL + /* Due to some shader compiler bug, we somewhat + * need to access gl_VertexID to make it work. even + * if it's actually dead code. */ + gl_Position.x = float(gl_VertexID); +#endif + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); #ifdef MESH_SHADER - viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; - worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz; - viewNormal = normalize(NormalMatrix * nor); - worldNormal = normalize(WorldNormalMatrix * nor); + worldPosition = world_pos; + viewPosition = point_world_to_view(worldPosition); + + worldNormal = normalize(normal_object_to_world(nor)); + /* No need to normalize since this is just a rotation. */ + viewNormal = normal_world_to_view(worldNormal); # ifdef USE_ATTR pass_attr(pos); # endif diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 0164a04c64b..052fdbb43a2 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -5,7 +5,6 @@ #define NODETREE_EXEC #ifdef MESH_SHADER -uniform mat4 volumeObjectMatrix; uniform vec3 volumeOrcoLoc; uniform vec3 volumeOrcoSize; #endif @@ -33,9 +32,9 @@ void main() 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); - worldPosition = transform_point(ViewMatrixInverse, viewPosition); + worldPosition = point_view_to_world(viewPosition); #ifdef MESH_SHADER - volumeObjectLocalCoord = transform_point(volumeObjectMatrix, worldPosition); + volumeObjectLocalCoord = point_world_to_object(worldPosition); volumeObjectLocalCoord = (volumeObjectLocalCoord - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0); diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index ed8c609c01f..7e03ce525d7 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -90,8 +90,7 @@ typedef struct EXTERNAL_PrivateData { bool update_depth; bool view_updated; - float last_mat[4][4]; - float curr_mat[4][4]; + float last_persmat[4][4]; } EXTERNAL_PrivateData; /* Transient data */ /* Functions */ @@ -126,13 +125,11 @@ static void external_engine_init(void *vedata) } { - float view[4][4]; - float win[4][4]; - DRW_viewport_matrix_get(view, DRW_MAT_VIEW); - DRW_viewport_matrix_get(win, DRW_MAT_WIN); - mul_m4_m4m4(stl->g_data->curr_mat, view, win); - if (!equals_m4m4(stl->g_data->curr_mat, stl->g_data->last_mat)) { + float persmat[4][4]; + DRW_view_persmat_get(NULL, persmat, false); + if (!equals_m4m4(persmat, stl->g_data->last_persmat)) { stl->g_data->update_depth = true; + copy_m4_m4(stl->g_data->last_persmat, persmat); } } } @@ -191,7 +188,7 @@ static void external_cache_populate(void *vedata, Object *ob) struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { /* Depth Prepass */ - DRW_shgroup_call_add(stl->g_data->depth_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob->obmat); } } } @@ -221,7 +218,7 @@ static void external_draw_scene_do(void *vedata) RenderEngine *engine = RE_engine_create_ex(engine_type, true); engine->tile_x = scene->r.tilex; engine->tile_y = scene->r.tiley; - engine_type->view_update(engine, draw_ctx->evil_C); + engine_type->view_update(engine, draw_ctx->evil_C, draw_ctx->depsgraph); rv3d->render_engine = engine; } @@ -231,7 +228,7 @@ static void external_draw_scene_do(void *vedata) /* Render result draw. */ type = rv3d->render_engine->type; - type->view_draw(rv3d->render_engine, draw_ctx->evil_C); + type->view_draw(rv3d->render_engine, draw_ctx->evil_C, draw_ctx->depsgraph); GPU_matrix_pop_projection(); @@ -270,8 +267,6 @@ static void external_draw_scene(void *vedata) // copy tmp buffer to default GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT); } - - copy_m4_m4(stl->g_data->last_mat, stl->g_data->curr_mat); } static void external_view_update(void *vedata) diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c index 7dabbcf4c41..7b2c0ed168e 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -133,7 +133,8 @@ static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex) void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, - const float ink[4]) + const float ink[4], + const int alignment_mode) { int totvertex = gps->totpoints; if (be->vbo == NULL) { @@ -177,26 +178,34 @@ void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, /* use previous point to determine stroke direction */ bGPDspoint *pt2 = NULL; float fpt[3]; - if (i == 0) { - if (gps->totpoints > 1) { - /* extrapolate a point before first point */ - pt2 = &gps->points[1]; - interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f); - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); + if (alignment_mode != GP_STYLE_FOLLOW_PATH) { + /* add small offset to get a vector */ + copy_v3_v3(fpt, &pt->x); + fpt[0] += 0.00001f; + fpt[1] += 0.00001f; + GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); + } + else { + if (i == 0) { + if (gps->totpoints > 1) { + /* extrapolate a point before first point */ + pt2 = &gps->points[1]; + interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f); + GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); + } + else { + /* add small offset to get a vector */ + copy_v3_v3(fpt, &pt->x); + fpt[0] += 0.00001f; + fpt[1] += 0.00001f; + GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); + } } else { - /* add small offset to get a vector */ - copy_v3_v3(fpt, &pt->x); - fpt[0] += 0.00001f; - fpt[1] += 0.00001f; - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); + pt2 = &gps->points[i - 1]; + GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x); } } - else { - pt2 = &gps->points[i - 1]; - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x); - } - be->vbo_len++; } } diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index 4b6c913785d..7f979c4fed1 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -465,7 +465,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_fill_create(GPENCIL_e_data *e_data, BKE_image_release_ibuf(image, ibuf, NULL); } else { - GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D, true); + GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(grp, "myTexture", texture); stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0; @@ -631,7 +631,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data, BKE_image_release_ibuf(image, ibuf, NULL); } else { - GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true); + GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(grp, "myTexture", texture); BKE_image_release_ibuf(image, ibuf, NULL); @@ -725,8 +725,8 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(GPENCIL_e_data *e_data, DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1); /* lock rotation of dots and boxes */ - stl->shgroups[id].use_follow_path = (gp_style->flag & GP_STYLE_COLOR_LOCK_DOTS) ? 0 : 1; - DRW_shgroup_uniform_int(grp, "use_follow_path", &stl->shgroups[id].use_follow_path, 1); + stl->shgroups[id].alignment_mode = gp_style->alignment_mode; + DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->shgroups[id].alignment_mode, 1); } else { stl->storage->obj_scale = 1.0f; @@ -758,7 +758,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(GPENCIL_e_data *e_data, DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1); /* lock rotation of dots and boxes */ - DRW_shgroup_uniform_int(grp, "use_follow_path", &stl->storage->use_follow_path, 1); + DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->storage->alignment_mode, 1); } DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1); @@ -787,7 +787,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create(GPENCIL_e_data *e_data, BKE_image_release_ibuf(image, ibuf, NULL); } else { - GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true); + GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(grp, "myTexture", texture); BKE_image_release_ibuf(image, ibuf, NULL); @@ -870,6 +870,7 @@ static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache, float ink[4]; short sthickness; MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + const int alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH; /* set color using base color, tint color and opacity */ if (cache->is_dirty) { @@ -919,7 +920,7 @@ static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache, else { /* create vertex data */ const int old_len = cache->b_point.vbo_len; - DRW_gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink); + DRW_gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink, alignment_mode); /* add to list of groups */ if (old_len < cache->b_point.vbo_len) { @@ -1228,6 +1229,7 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, int last = gpf->framenum; colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL; + const short onion_keytype = gpd->onion_keytype; /* ------------------------------- * 1) Draw Previous Frames First @@ -1248,6 +1250,10 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) { continue; } + /* verify keyframe type */ + if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) { + continue; + } /* absolute range */ if (mode == GP_ONION_MODE_ABSOLUTE) { if ((gpf->framenum - gf->framenum) > step) { @@ -1304,6 +1310,10 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache, if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) { continue; } + /* verify keyframe type */ + if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) { + continue; + } /* absolute range */ if (mode == GP_ONION_MODE_ABSOLUTE) { if ((gf->framenum - gpf->framenum) > step) { @@ -1490,7 +1500,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, /* save gradient info */ stl->storage->gradient_f = brush->gpencil_settings->gradient_f; copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s); - stl->storage->use_follow_path = (gp_style->flag & GP_STYLE_COLOR_LOCK_DOTS) ? 0 : 1; + stl->storage->alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH; /* if only one point, don't need to draw buffer because the user has no time to see it */ if (gpd->runtime.sbuffer_size > 1) { @@ -1543,9 +1553,9 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, } /* buffer strokes, must show stroke always */ - DRW_shgroup_call_add(stl->g_data->shgrps_drawing_stroke, - e_data->batch_buffer_stroke, - stl->storage->unit_matrix); + DRW_shgroup_call(stl->g_data->shgrps_drawing_stroke, + e_data->batch_buffer_stroke, + stl->storage->unit_matrix); if ((gpd->runtime.sbuffer_size >= 3) && (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) && @@ -1567,9 +1577,9 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, } e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd); - DRW_shgroup_call_add(stl->g_data->shgrps_drawing_fill, - e_data->batch_buffer_fill, - stl->storage->unit_matrix); + DRW_shgroup_call(stl->g_data->shgrps_drawing_fill, + e_data->batch_buffer_fill, + stl->storage->unit_matrix); stl->storage->buffer_fill = true; } stl->storage->buffer_stroke = true; @@ -1599,7 +1609,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, e_data->batch_buffer_ctrlpoint = DRW_gpencil_get_buffer_ctrlpoint_geom(gpd); - DRW_shgroup_call_add(shgrp, e_data->batch_buffer_ctrlpoint, stl->storage->unit_matrix); + DRW_shgroup_call(shgrp, e_data->batch_buffer_ctrlpoint, stl->storage->unit_matrix); stl->storage->buffer_ctrlpoint = true; } @@ -1721,12 +1731,12 @@ static void DRW_gpencil_shgroups_create(GPENCIL_e_data *e_data, scale, cache_ob->shading_type); if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_add(shgrp, - cache->b_stroke.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : - cache_ob->obmat, - start_stroke, - len); + DRW_shgroup_call_range(shgrp, + cache->b_stroke.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : + cache_ob->obmat, + start_stroke, + len); } stl->storage->shgroup_id++; start_stroke = elm->vertex_idx; @@ -1750,12 +1760,12 @@ static void DRW_gpencil_shgroups_create(GPENCIL_e_data *e_data, cache_ob->shading_type); if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_add(shgrp, - cache->b_point.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : - cache_ob->obmat, - start_point, - len); + DRW_shgroup_call_range(shgrp, + cache->b_point.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : + cache_ob->obmat, + start_point, + len); } stl->storage->shgroup_id++; start_point = elm->vertex_idx; @@ -1776,12 +1786,12 @@ static void DRW_gpencil_shgroups_create(GPENCIL_e_data *e_data, cache_ob->shading_type); if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range_add(shgrp, - cache->b_fill.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : - cache_ob->obmat, - start_fill, - len); + DRW_shgroup_call_range(shgrp, + cache->b_fill.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : + cache_ob->obmat, + start_fill, + len); } stl->storage->shgroup_id++; start_fill = elm->vertex_idx; @@ -1791,12 +1801,12 @@ static void DRW_gpencil_shgroups_create(GPENCIL_e_data *e_data, if (stl->g_data->shgrps_edit_point) { const int len = elm->vertex_idx - start_edit; /* use always the same group */ - DRW_shgroup_call_range_add(stl->g_data->shgrps_edit_point, - cache->b_edit.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : - cache_ob->obmat, - start_edit, - len); + DRW_shgroup_call_range(stl->g_data->shgrps_edit_point, + cache->b_edit.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : + cache_ob->obmat, + start_edit, + len); start_edit = elm->vertex_idx; } @@ -1806,12 +1816,12 @@ static void DRW_gpencil_shgroups_create(GPENCIL_e_data *e_data, if (stl->g_data->shgrps_edit_line) { const int len = elm->vertex_idx - start_edlin; /* use always the same group */ - DRW_shgroup_call_range_add(stl->g_data->shgrps_edit_line, - cache->b_edlin.batch, - (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : - cache_ob->obmat, - start_edlin, - len); + DRW_shgroup_call_range(stl->g_data->shgrps_edit_line, + cache->b_edlin.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : + cache_ob->obmat, + start_edlin, + len); start_edlin = elm->vertex_idx; } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index ea578187765..280702020df 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -61,6 +61,8 @@ extern char datatoc_gpencil_edit_point_geom_glsl[]; extern char datatoc_gpencil_edit_point_frag_glsl[]; extern char datatoc_gpencil_blend_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + /* *********** STATIC *********** */ static GPENCIL_e_data e_data = {NULL}; /* Engine data */ @@ -167,31 +169,37 @@ static void GPENCIL_create_shaders(void) { /* normal fill shader */ if (!e_data.gpencil_fill_sh) { - e_data.gpencil_fill_sh = DRW_shader_create( - datatoc_gpencil_fill_vert_glsl, NULL, datatoc_gpencil_fill_frag_glsl, NULL); + e_data.gpencil_fill_sh = DRW_shader_create_with_lib(datatoc_gpencil_fill_vert_glsl, + NULL, + datatoc_gpencil_fill_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } /* normal stroke shader using geometry to display lines (line mode) */ if (!e_data.gpencil_stroke_sh) { - e_data.gpencil_stroke_sh = DRW_shader_create(datatoc_gpencil_stroke_vert_glsl, - datatoc_gpencil_stroke_geom_glsl, - datatoc_gpencil_stroke_frag_glsl, - NULL); + e_data.gpencil_stroke_sh = DRW_shader_create_with_lib(datatoc_gpencil_stroke_vert_glsl, + datatoc_gpencil_stroke_geom_glsl, + datatoc_gpencil_stroke_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } /* dot/rectangle mode for normal strokes using geometry */ if (!e_data.gpencil_point_sh) { - e_data.gpencil_point_sh = DRW_shader_create(datatoc_gpencil_point_vert_glsl, - datatoc_gpencil_point_geom_glsl, - datatoc_gpencil_point_frag_glsl, - NULL); + e_data.gpencil_point_sh = DRW_shader_create_with_lib(datatoc_gpencil_point_vert_glsl, + datatoc_gpencil_point_geom_glsl, + datatoc_gpencil_point_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } /* used for edit points or strokes with one point only */ if (!e_data.gpencil_edit_point_sh) { - e_data.gpencil_edit_point_sh = DRW_shader_create(datatoc_gpencil_edit_point_vert_glsl, - datatoc_gpencil_edit_point_geom_glsl, - datatoc_gpencil_edit_point_frag_glsl, - NULL); + e_data.gpencil_edit_point_sh = DRW_shader_create_with_lib(datatoc_gpencil_edit_point_vert_glsl, + datatoc_gpencil_edit_point_geom_glsl, + datatoc_gpencil_edit_point_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } /* used for edit lines for edit modes */ @@ -454,7 +462,7 @@ void GPENCIL_cache_init(void *vedata) DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass); - DRW_shgroup_call_add(mix_shgrp, quad, NULL); + DRW_shgroup_call(mix_shgrp, quad, NULL); DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &e_data.input_color_tx); DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &e_data.input_depth_tx); DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1); @@ -472,7 +480,7 @@ void GPENCIL_cache_init(void *vedata) DRW_STATE_DEPTH_LESS); DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass_noblend); - DRW_shgroup_call_add(mix_shgrp_noblend, quad, NULL); + DRW_shgroup_call(mix_shgrp_noblend, quad, NULL); DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeColor", &e_data.input_color_tx); DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeDepth", &e_data.input_depth_tx); DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1); @@ -490,7 +498,7 @@ void GPENCIL_cache_init(void *vedata) DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh, psl->background_pass); - DRW_shgroup_call_add(background_shgrp, quad, NULL); + DRW_shgroup_call(background_shgrp, quad, NULL); DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &e_data.background_color_tx); DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &e_data.background_depth_tx); @@ -503,7 +511,7 @@ void GPENCIL_cache_init(void *vedata) psl->paper_pass = DRW_pass_create("GPencil Paper Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND); DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass); - DRW_shgroup_call_add(paper_shgrp, quad, NULL); + DRW_shgroup_call(paper_shgrp, quad, NULL); DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1); DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1); } @@ -522,7 +530,7 @@ void GPENCIL_cache_init(void *vedata) DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, psl->blend_pass); - DRW_shgroup_call_add(blend_shgrp, quad, NULL); + DRW_shgroup_call(blend_shgrp, quad, NULL); DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &e_data.temp_color_tx_a); DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &e_data.temp_depth_tx_a); DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &e_data.temp_color_tx_fx); @@ -674,7 +682,7 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) copy_v3_v3(stl->storage->grid_matrix[3], ob->obmat[3]); } - DRW_shgroup_call_add(stl->g_data->shgrps_grid, e_data.batch_grid, stl->storage->grid_matrix); + DRW_shgroup_call(stl->g_data->shgrps_grid, e_data.batch_grid, stl->storage->grid_matrix); } } } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 2ac1dc3211c..5dab0a56b63 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -129,7 +129,7 @@ typedef struct GPENCIL_shgroup { int caps_mode[2]; float obj_scale; int xray_mode; - int use_follow_path; + int alignment_mode; float gradient_f; float gradient_s[2]; @@ -182,14 +182,12 @@ typedef struct GPENCIL_Storage { float gradient_f; float gradient_s[2]; - int use_follow_path; + int alignment_mode; float mix_stroke_factor; /* Render Matrices and data */ - float persmat[4][4], persinv[4][4]; - float viewmat[4][4], viewinv[4][4]; - float winmat[4][4], wininv[4][4]; + DRWView *view; float view_vecs[2][4]; /* vec4[2] */ float grid_matrix[4][4]; @@ -437,7 +435,8 @@ void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int void DRW_gpencil_get_point_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, - const float ink[4]); + const float ink[4], + const int follow_mode); void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, @@ -514,7 +513,7 @@ void GPENCIL_render_to_image(void *vedata, /* Use of multisample framebuffers. */ #define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) \ { \ - if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \ + if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \ DRW_stats_query_start("GP Multisample Blit"); \ GPU_framebuffer_bind(fbl->multisample_fb); \ GPU_framebuffer_clear_color_depth(fbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \ @@ -525,7 +524,7 @@ void GPENCIL_render_to_image(void *vedata, #define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) \ { \ - if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \ + if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \ DRW_stats_query_start("GP Multisample Resolve"); \ GPU_framebuffer_bind(fb); \ DRW_multisamples_resolve(txl->multisample_depth, txl->multisample_color, true); \ diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index e6a3f45d60d..8f3382fc138 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -94,26 +94,26 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra } /* Set the pers & view matrix. */ + float winmat[4][4], viewmat[4][4], viewinv[4][4], persmat[4][4]; + struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); float frame = BKE_scene_frame_get(scene); - RE_GetCameraWindow(engine->re, camera, frame, stl->storage->winmat); - RE_GetCameraModelMatrix(engine->re, camera, stl->storage->viewinv); + RE_GetCameraWindow(engine->re, camera, frame, winmat); + RE_GetCameraModelMatrix(engine->re, camera, viewinv); + + invert_m4_m4(viewmat, viewinv); - invert_m4_m4(stl->storage->viewmat, stl->storage->viewinv); - mul_m4_m4m4(stl->storage->persmat, stl->storage->winmat, stl->storage->viewmat); - invert_m4_m4(stl->storage->persinv, stl->storage->persmat); - invert_m4_m4(stl->storage->wininv, stl->storage->winmat); + DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + DRW_view_default_set(view); + DRW_view_set_active(view); - DRW_viewport_matrix_override_set(stl->storage->persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(stl->storage->persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(stl->storage->winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(stl->storage->wininv, DRW_MAT_WININV); - DRW_viewport_matrix_override_set(stl->storage->viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(stl->storage->viewinv, DRW_MAT_VIEWINV); + DRW_view_persmat_get(view, persmat, false); /* calculate pixel size for render */ - stl->storage->render_pixsize = get_render_pixelsize( - stl->storage->persmat, viewport_size[0], viewport_size[1]); + stl->storage->render_pixsize = get_render_pixelsize(persmat, viewport_size[0], viewport_size[1]); + + stl->storage->view = view; + /* INIT CACHE */ GPENCIL_cache_init(vedata); } @@ -180,8 +180,8 @@ static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata) GPENCIL_StorageList *stl = vedata->stl; float invproj[4][4], winmat[4][4]; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_get(invproj, DRW_MAT_WININV); + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_winmat_get(NULL, invproj, true); /* this is separated to keep function equal to Eevee for future reuse of same code */ GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs); @@ -207,10 +207,13 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, BLI_rcti_size_y(rect), rp->rect); - bool is_persp = DRW_viewport_is_persp_get(); + bool is_persp = DRW_view_is_persp_get(NULL); GPENCIL_render_update_vecs(vedata); + float winmat[4][4]; + DRW_view_persmat_get(stl->storage->view, winmat, false); + /* Convert ogl depth [0..1] to view Z [near..far] */ for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) { if (rp->rect[i] == 1.0f) { @@ -219,7 +222,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, else { if (is_persp) { rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; - rp->rect[i] = stl->storage->winmat[3][2] / (rp->rect[i] + stl->storage->winmat[2][2]); + rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]); } else { rp->rect[i] = -stl->storage->view_vecs[0][2] + diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index 355235618f6..9eb4123e5bc 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -110,22 +110,13 @@ static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2]) if (camera == NULL) { return; } + Camera *cam = camera->data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - Camera *cam = (Camera *)camera->data; - - float fstop = cam->gpu_dof.fstop; + float fstop = cam->dof.aperture_fstop; float focus_dist = BKE_camera_object_dof_distance(camera); float focal_len = cam->lens; - /* This is factor that converts to the scene scale. focal length and sensor are expressed in mm - * unit.scale_length is how many meters per blender unit we have. We want to convert to blender - * units though because the shader reads coordinates in world space, which is in blender units. - * Note however that focus_distance is already in blender units and shall not be scaled here - * (see T48157). */ - float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f; - float scale_camera = 0.001f / scale; + const float scale_camera = 0.001f; /* we want radius here for the aperture number */ float aperture_scaled = 0.5f * scale_camera * focal_len / fstop; float focal_len_scaled = scale_camera * focal_len; @@ -210,7 +201,7 @@ static void DRW_gpencil_fx_blur(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -235,7 +226,7 @@ static void DRW_gpencil_fx_colorize(ShaderFxData *fx, GPENCIL_e_data *e_data, GP GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_colorize_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_vec4(fx_shgrp, "low_color", &fxd->low_color[0], 1); @@ -267,7 +258,7 @@ static void DRW_gpencil_fx_flip(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCI GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1); @@ -297,7 +288,7 @@ static void DRW_gpencil_fx_light(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); @@ -352,7 +343,7 @@ static void DRW_gpencil_fx_pixel(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_int(fx_shgrp, "size", &fxd->size[0], 3); @@ -386,7 +377,7 @@ static void DRW_gpencil_fx_rim(ShaderFxData *fx, /* prepare pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -403,7 +394,7 @@ static void DRW_gpencil_fx_rim(ShaderFxData *fx, /* blur pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -417,7 +408,7 @@ static void DRW_gpencil_fx_rim(ShaderFxData *fx, /* resolve pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_resolve_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &e_data->temp_color_tx_fx); @@ -453,7 +444,7 @@ static void DRW_gpencil_fx_shadow(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); /* prepare pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -488,7 +479,7 @@ static void DRW_gpencil_fx_shadow(ShaderFxData *fx, /* blur pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -502,7 +493,7 @@ static void DRW_gpencil_fx_shadow(ShaderFxData *fx, /* resolve pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_resolve_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowColor", &e_data->temp_color_tx_fx); @@ -531,7 +522,7 @@ static void DRW_gpencil_fx_glow(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); /* prepare pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); @@ -544,7 +535,7 @@ static void DRW_gpencil_fx_glow(ShaderFxData *fx, /* blur pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx); DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); @@ -558,7 +549,7 @@ static void DRW_gpencil_fx_glow(ShaderFxData *fx, /* resolve pass */ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_resolve_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowColor", &e_data->temp_color_tx_fx); @@ -593,7 +584,7 @@ static void DRW_gpencil_fx_swirl(ShaderFxData *fx, GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); @@ -624,7 +615,7 @@ static void DRW_gpencil_fx_wave(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCI GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass); - DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_call(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl index 8c3fd022004..e0634a7d1a7 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl @@ -1,4 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; uniform vec2 Viewport; layout(points) in; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl index eea28755ae6..a1cfb2ae4ae 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl @@ -1,4 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; in vec3 pos; in vec4 color; @@ -9,7 +8,7 @@ out float finalThickness; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position = point_object_to_ndc(pos); finalColor = color; finalThickness = size; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl index acf60fc2d59..192720a4e98 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl @@ -89,6 +89,27 @@ void set_color(in vec4 color, ocolor.a *= layer_opacity; } +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) { + return (c < 0.0) ? 0.0 : c * 12.92; + } + else { + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; + } +} + +vec4 texture_read_as_srgb(sampler2D tex, vec2 co) +{ + /* By convention image textures return scene linear colors, but + * grease pencil still works in srgb. */ + vec4 color = texture(tex, co); + color.r = linearrgb_to_srgb(color.r); + color.g = linearrgb_to_srgb(color.g); + color.b = linearrgb_to_srgb(color.b); + return color; +} + void main() { vec2 t_center = vec2(0.5, 0.5); @@ -97,8 +118,8 @@ void main() vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset; vec4 tmp_color; tmp_color = (texture_clamp == 0) ? - texture2D(myTexture, rot_tex * texture_scale) : - texture2D(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0)); + texture_read_as_srgb(myTexture, rot_tex * texture_scale) : + texture_read_as_srgb(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0)); vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity); vec4 chesscolor; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl index d71f57eb98c..eb452f4c660 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl @@ -1,14 +1,14 @@ -uniform mat4 ModelViewProjectionMatrix; in vec3 pos; in vec4 color; in vec2 texCoord; + out vec4 finalColor; out vec2 texCoord_interp; void main(void) { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position = point_object_to_ndc(pos); finalColor = color; texCoord_interp = texCoord; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl index 3c1424f98ff..1d1cd6349dc 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl @@ -5,5 +5,5 @@ out vec4 FragColor; void main() { - FragColor = vec4(color, opacity); + FragColor = vec4(color, 1.0 - opacity); } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl index cc47e12b303..569a68679b4 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl @@ -47,6 +47,27 @@ vec2 check_box_point(vec2 pt, vec2 radius) return rtn; } +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) { + return (c < 0.0) ? 0.0 : c * 12.92; + } + else { + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; + } +} + +vec4 texture_read_as_srgb(sampler2D tex, vec2 co) +{ + /* By convention image textures return scene linear colors, but + * grease pencil still works in srgb. */ + vec4 color = texture(tex, co); + color.r = linearrgb_to_srgb(color.r); + color.g = linearrgb_to_srgb(color.g); + color.b = linearrgb_to_srgb(color.b); + return color; +} + void main() { vec2 centered = mTexCoord - vec2(0.5); @@ -65,7 +86,7 @@ void main() } } - vec4 tmp_color = texture2D(myTexture, mTexCoord); + vec4 tmp_color = texture_read_as_srgb(myTexture, mTexCoord); /* Solid */ if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) { @@ -73,7 +94,7 @@ void main() } /* texture */ if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) { - vec4 text_color = texture2D(myTexture, mTexCoord); + vec4 text_color = texture_read_as_srgb(myTexture, mTexCoord); if (mix_stroke_factor > 0.0) { fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor); fragColor.a = text_color.a; @@ -87,7 +108,7 @@ void main() } /* pattern */ if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) { - vec4 text_color = texture2D(myTexture, mTexCoord); + vec4 text_color = texture_read_as_srgb(myTexture, mTexCoord); fragColor = mColor; /* mult both alpha factor to use strength factor with color alpha limit */ fragColor.a = min(text_color.a * mColor.a, mColor.a); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl index a64a7ecb9be..a2f4c1f9b15 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl @@ -1,7 +1,6 @@ -uniform mat4 ModelViewProjectionMatrix; uniform vec2 Viewport; uniform int xraymode; -uniform int use_follow_path; +uniform int alignment_mode; layout(points) in; layout(triangle_strip, max_vertices = 4) out; @@ -21,6 +20,9 @@ out vec2 mTexCoord; #define M_2PI 6.28318530717958647692 /* 2*pi */ #define FALSE 0 +/* keep this definition equals to GP_STYLE_FOLLOW_FIXED value */ +#define FIXED 2 + /* project 3d point to 2d on screen space */ vec2 toScreenSpace(vec4 vertex) { @@ -70,7 +72,7 @@ float getAngle(vec2 pt0, vec2 pt1) return 0.0; } - if (use_follow_path == FALSE) { + if (alignment_mode == FIXED) { return 0.0; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl index 9cef7601770..ef8b361373f 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl @@ -1,5 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ProjectionMatrix; uniform float pixsize; /* rv3d->pixsize */ uniform int keep_size; @@ -32,8 +30,8 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor); void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - finalprev_pos = ModelViewProjectionMatrix * vec4(prev_pos, 1.0); + gl_Position = point_object_to_ndc(pos); + finalprev_pos = point_object_to_ndc(prev_pos); finalColor = color; if (keep_size == TRUE) { diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl index 6b7cee888ea..a5580e305d6 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl @@ -27,6 +27,27 @@ out vec4 fragColor; bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR); +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) { + return (c < 0.0) ? 0.0 : c * 12.92; + } + else { + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; + } +} + +vec4 texture_read_as_srgb(sampler2D tex, vec2 co) +{ + /* By convention image textures return scene linear colors, but + * grease pencil still works in srgb. */ + vec4 color = texture(tex, co); + color.r = linearrgb_to_srgb(color.r); + color.g = linearrgb_to_srgb(color.g); + color.b = linearrgb_to_srgb(color.b); + return color; +} + void main() { @@ -47,10 +68,10 @@ void main() /* texture for endcaps */ vec4 text_color; if (uvfac[1] == ENDCAP) { - text_color = texture2D(myTexture, vec2(mTexCoord.x, mTexCoord.y)); + text_color = texture_read_as_srgb(myTexture, vec2(mTexCoord.x, mTexCoord.y)); } else { - text_color = texture2D(myTexture, mTexCoord); + text_color = texture_read_as_srgb(myTexture, mTexCoord); } /* texture */ diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl index b90f5b33a57..9ea96806481 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl @@ -1,4 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; uniform vec2 Viewport; uniform int xraymode; uniform int color_type; diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl index 946b39c006a..c7089f357f9 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl @@ -1,5 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ProjectionMatrix; uniform float pixsize; /* rv3d->pixsize */ uniform int keep_size; @@ -30,7 +28,7 @@ float defaultpixsize = pixsize * (1000.0 / pixfactor); void main(void) { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position = point_object_to_ndc(pos); finalColor = color; if (keep_size == TRUE) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index c76ad8c1d7b..96f8f6e4c7a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -140,32 +140,18 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) return matcap_uv * 0.496 + 0.5; } -float srgb_to_linearrgb(float c) -{ - if (c < 0.04045) { - return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); - } - else { - return pow((c + 0.055) * (1.0 / 1.055), 2.4); - } -} - -vec4 srgb_to_linearrgb(vec4 col_from) -{ - vec4 col_to; - col_to.r = srgb_to_linearrgb(col_from.r); - col_to.g = srgb_to_linearrgb(col_from.g); - col_to.b = srgb_to_linearrgb(col_from.b); - col_to.a = col_from.a; - return col_to; -} - -vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool srgb, bool nearest_sampling) +vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) { vec2 tex_size = vec2(textureSize(image, 0).xy); /* TODO(fclem) We could do the same with sampler objects. * But this is a quick workaround instead of messing with the GPUTexture itself. */ vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; vec4 color = texture(image, uv); - return (srgb) ? srgb_to_linearrgb(color) : color; + + /* Unpremultiply, ideally shaders would be added so this is not needed. */ + if (!(color.a == 0.0 || color.a == 1.0)) { + color.rgb = color.rgb / color.a; + } + + return color; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 65196c1a836..a1f80440404 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -1,8 +1,5 @@ out vec4 fragColor; -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrixInverse; - uniform usampler2D objectId; uniform sampler2D materialBuffer; uniform sampler2D normalBuffer; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl index 46b0361245b..092878e43aa 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl @@ -8,6 +8,9 @@ uniform vec2 invertedViewportSize; void main() { + ivec2 texel = ivec2(gl_FragCoord.xy); + float alpha = texelFetch(colorBuffer, texel, 0).a; FragColor = FxaaPixelShader( uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833); + FragColor.a = alpha; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index 5eff0b41e20..51bce639b63 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -1,11 +1,8 @@ uniform float ImageTransparencyCutoff = 0.1; uniform sampler2D image; -uniform bool imageSrgb; uniform bool imageNearest; -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrixInverse; uniform float alpha = 0.5; uniform vec2 invertedViewportSize; uniform vec4 viewvecs[3]; @@ -46,7 +43,7 @@ void main() vec4 diffuse_color; #if defined(V3D_SHADING_TEXTURE_COLOR) - diffuse_color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest); + diffuse_color = workbench_sample_texture(image, uv_interp, imageNearest); if (diffuse_color.a < ImageTransparencyCutoff) { discard; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 2596fc4cf88..af9f1d14f4a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -6,7 +6,6 @@ uniform float materialRoughness; uniform sampler2D image; uniform float ImageTransparencyCutoff = 0.1; -uniform bool imageSrgb; uniform bool imageNearest; #ifdef NORMAL_VIEWPORT_PASS_ENABLED @@ -41,7 +40,7 @@ void main() vec4 color; # if defined(V3D_SHADING_TEXTURE_COLOR) - color = workbench_sample_texture(image, uv_interp, imageSrgb, imageNearest); + color = workbench_sample_texture(image, uv_interp, imageNearest); if (color.a < ImageTransparencyCutoff) { discard; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index f2c684cdb6a..7872c1380ed 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -1,10 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; -uniform mat4 ModelMatrixInverse; -uniform mat4 ProjectionMatrix; -uniform mat4 ViewProjectionMatrix; -uniform mat4 ViewMatrixInverse; -uniform mat3 NormalMatrix; #ifndef HAIR_SHADER in vec3 pos; @@ -50,6 +43,17 @@ vec3 srgb_to_linear_attr(vec3 c) } #endif +vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand) +{ + /* To "simulate" anisotropic shading, randomize hair normal per strand. */ + vec3 nor = cross(tan, binor); + nor = normalize(mix(nor, -tan, rand * 0.1)); + float cos_theta = (rand * 2.0 - 1.0) * 0.2; + float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); + nor = nor * sin_theta + binor * cos_theta; + return nor; +} + void main() { #ifdef HAIR_SHADER @@ -57,29 +61,25 @@ void main() vec2 uv = hair_get_customdata_vec2(u); # endif float time, thick_time, thickness; - vec3 pos, tan, binor; + vec3 world_pos, tan, binor; hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), ModelMatrixInverse, ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, - pos, + world_pos, tan, binor, time, thickness, thick_time); - /* To "simulate" anisotropic shading, randomize hair normal per strand. */ + hair_rand = integer_noise(hair_get_strand_id()); - tan = normalize(tan); - vec3 nor = normalize(cross(binor, tan)); - nor = normalize(mix(nor, -tan, hair_rand * 0.10)); - float cos_theta = (hair_rand * 2.0 - 1.0) * 0.20; - float sin_theta = sqrt(max(0.0, 1.0f - cos_theta * cos_theta)); - nor = nor * sin_theta + binor * cos_theta; - gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand); #else - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); #endif + gl_Position = point_world_to_ndc(world_pos); + #ifdef V3D_SHADING_TEXTURE_COLOR uv_interp = uv; #endif @@ -91,13 +91,13 @@ void main() #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED - normal_viewport = NormalMatrix * nor; + normal_viewport = normal_object_to_view(nor); # ifndef HAIR_SHADER normal_viewport = normalize(normal_viewport); # endif #endif #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl index afd704a7d3a..e07f87525e2 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl @@ -1,7 +1,5 @@ #define INFINITE 1000.0 -uniform mat4 ModelViewProjectionMatrix; - uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57); uniform float lightDistance = 1e4; @@ -18,6 +16,6 @@ vData; void main() { vData.pos = pos; - vData.frontPosition = ModelViewProjectionMatrix * vec4(pos, 1.0); - vData.backPosition = ModelViewProjectionMatrix * vec4(pos + lightDirection * lightDistance, 1.0); + vData.frontPosition = point_object_to_ndc(pos); + vData.backPosition = point_object_to_ndc(pos + lightDirection * lightDistance); } 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 a1c269d5a65..fd06c85747f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -1,8 +1,4 @@ -uniform mat4 ProjectionMatrix; -uniform mat4 ModelMatrixInverse; -uniform mat4 ModelViewMatrixInverse; -uniform mat4 ModelMatrix; uniform vec3 OrcoTexCoFactors[2]; uniform sampler2D depthBuffer; @@ -219,9 +215,11 @@ void main() vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0); vs_ray_dir /= abs(vs_ray_dir.z); - vec3 ls_ray_dir = mat3(ModelViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0; - vec3 ls_ray_ori = (ModelViewMatrixInverse * vec4(vs_ray_ori, 1.0)).xyz; - vec3 ls_ray_end = (ModelViewMatrixInverse * vec4(vs_ray_end, 1.0)).xyz; + /* TODO(fclem) Precompute the matrix/ */ + vec3 ls_ray_dir = mat3(ViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0; + ls_ray_dir = mat3(ModelMatrixInverse) * ls_ray_dir; + vec3 ls_ray_ori = point_view_to_object(vs_ray_ori); + vec3 ls_ray_end = point_view_to_object(vs_ray_end); ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0; ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl index 7a418243fd3..6f0bb56fafd 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl @@ -1,5 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; uniform vec3 OrcoTexCoFactors[2]; uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ @@ -29,5 +28,5 @@ void main() vec3 final_pos = pos; #endif final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1]; - gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 1.0); + gl_Position = point_object_to_ndc(final_pos); } diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c index a01b14f17fb..e1050751830 100644 --- a/source/blender/draw/engines/workbench/solid_mode.c +++ b/source/blender/draw/engines/workbench/solid_mode.c @@ -61,8 +61,12 @@ static void workbench_solid_cache_finish(void *vedata) static void workbench_solid_draw_background(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_deferred_draw_background(data); - workbench_deferred_draw_scene(data); + const int num_samples = workbench_num_viewport_rendering_iterations(data); + + for (int sample = 0; sample < num_samples; sample++) { + workbench_deferred_draw_background(data); + workbench_deferred_draw_scene(data); + } workbench_deferred_draw_finish(data); } diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c index 0f4150ff986..bd2fb24dd85 100644 --- a/source/blender/draw/engines/workbench/transparent_mode.c +++ b/source/blender/draw/engines/workbench/transparent_mode.c @@ -59,8 +59,12 @@ static void workbench_transparent_cache_finish(void *vedata) static void workbench_transparent_draw_background(void *vedata) { WORKBENCH_Data *data = vedata; - workbench_forward_draw_background(data); - workbench_forward_draw_scene(data); + const int num_samples = workbench_num_viewport_rendering_iterations(data); + + for (int sample = 0; sample < num_samples; sample++) { + workbench_forward_draw_background(data); + workbench_forward_draw_scene(data); + } workbench_forward_draw_finish(data); } diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 7728b3f998b..fce1d725133 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -127,7 +127,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) RegionView3D *rv3d = draw_ctx->rv3d; if (rv3d->rflag & RV3D_CLIPPING) { wpd->world_clip_planes = rv3d->clip; - DRW_state_clip_planes_set_from_rv3d(rv3d); UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color); if (wpd->use_color_management) { srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color); @@ -148,7 +147,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) const int ssao_samples = scene->display.matcap_ssao_samples; float invproj[4][4]; - const bool is_persp = DRW_viewport_is_persp_get(); + const bool is_persp = DRW_view_is_persp_get(NULL); /* view vectors for the corners of the view frustum. * Can be used to recreate the world space position easily */ float viewvecs[3][4] = { @@ -171,9 +170,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->shading.cavity_ridge_factor, scene->display.matcap_ssao_attenuation); - /* invert the view matrix */ - DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN); - invert_m4_m4(invproj, wpd->winmat); + DRW_view_winmat_get(NULL, wpd->winmat, false); + DRW_view_winmat_get(NULL, invproj, true); /* convert the view vectors to view space */ for (i = 0; i < 3; i++) { @@ -213,7 +211,7 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, Scene *scene = draw_ctx->scene; WORKBENCH_UBO_World *wd = &wpd->world_data; float view_matrix[4][4]; - DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); + DRW_view_viewmat_get(NULL, view_matrix, false); copy_v3_v3(r_light_direction, scene->display.light_direction); SWAP(float, r_light_direction[2], r_light_direction[1]); diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 5d7bdc72546..eacd319cc4a 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -91,6 +91,7 @@ static struct { /* Shaders */ extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; @@ -119,6 +120,7 @@ static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) { DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl); @@ -159,6 +161,7 @@ static char *workbench_build_prepass_vert(bool is_hair) if (is_hair) { BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); } + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); char *str = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -382,33 +385,60 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; #endif /* TODO only compile on demand */ - e_data.shadow_pass_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_PASS\n" - "#define DOUBLE_MANIFOLD\n"); - e_data.shadow_pass_manifold_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_PASS\n"); - e_data.shadow_fail_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n"); - e_data.shadow_fail_manifold_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_geom_glsl, - shadow_frag, - "#define SHADOW_FAIL\n"); - e_data.shadow_caps_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_caps_geom_glsl, - shadow_frag, - "#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n"); - e_data.shadow_caps_manifold_sh = DRW_shader_create(datatoc_workbench_shadow_vert_glsl, - datatoc_workbench_shadow_caps_geom_glsl, - shadow_frag, - "#define SHADOW_FAIL\n"); + e_data.shadow_pass_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_PASS\n" + "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + e_data.shadow_pass_manifold_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_PASS\n", NULL}, + }); + e_data.shadow_fail_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_FAIL\n" + "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + e_data.shadow_fail_manifold_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, + }); + e_data.shadow_caps_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_FAIL\n" + "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + e_data.shadow_caps_manifold_sh = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, + }); e_data.ghost_resolve_sh = DRW_shader_create_fullscreen( datatoc_workbench_ghost_resolve_frag_glsl, NULL); @@ -549,7 +579,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.ghost_depth_tx); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } { @@ -583,7 +613,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1); } - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -694,13 +724,13 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) if (OBJECT_OUTLINE_ENABLED(wpd)) { DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); } - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); if (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb) { GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND); grp = DRW_shgroup_create(shader, psl->background_pass); wpd->world_clip_planes_batch = DRW_draw_background_clipping_batch_from_rv3d(draw_ctx->rv3d); - DRW_shgroup_call_add(grp, wpd->world_clip_planes_batch, NULL); + DRW_shgroup_call(grp, wpd->world_clip_planes_batch, NULL); DRW_shgroup_uniform_vec4(grp, "color", &wpd->world_clip_planes_color[0], 1); } } @@ -720,7 +750,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); /* Stencil Shadow passes. */ #ifdef DEBUG_SHADOW_VOLUME @@ -765,7 +795,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); #endif } else { @@ -773,7 +803,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER); grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); workbench_composite_uniforms(wpd, grp); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -807,7 +837,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.oit_accum_tx); DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.oit_revealage_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } } } @@ -935,13 +965,13 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) WORKBENCH_MaterialData *material; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { const bool is_active = (ob == draw_ctx->obact); - const bool is_sculpt_mode = (ob->sculpt != NULL); + const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); const bool use_hide = is_active && DRW_object_use_hide_faces(ob); - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); + const int materials_len = MAX2(1, ob->totcol); const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; bool has_transp_mat = false; - if (!is_sculpt_mode && me && me->mloopuv && TEXTURE_DRAWING_ENABLED(wpd)) { + if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { /* Draw textured */ struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); for (int i = 0; i < materials_len; i++) { @@ -961,7 +991,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) material = get_or_create_material_data( vedata, ob, mat, image, iuser, color_type, interp); } - DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); + DRW_shgroup_call_object(material->shgrp, geom_array[i], ob); } } } @@ -983,8 +1013,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) /* Draw solid color */ material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0); } + if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); + DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); } else { struct GPUBatch *geom; @@ -996,18 +1028,31 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) } if (geom) { - DRW_shgroup_call_object_add(material->shgrp, geom, ob); + DRW_shgroup_call_object(material->shgrp, geom, ob); } } } else { /* Draw material color */ if (is_sculpt_mode) { - /* Multiple materials are not supported in sculpt mode yet. */ - Material *mat = give_current_material(ob, 1); - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + + for (int i = 0; i < materials_len; ++i) { + struct Material *mat = give_current_material(ob, i + 1); + if (mat != NULL && mat->a < 1.0f) { + /* Hack */ + wpd->shading.xray_alpha = mat->a; + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); + has_transp_mat = true; + } + else { + material = get_or_create_material_data( + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); + } + shgrps[i] = material->shgrp; + } + DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); } else { struct GPUBatch **geoms; @@ -1030,7 +1075,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) material = get_or_create_material_data( vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); } - DRW_shgroup_call_object_add(material->shgrp, geoms[i], ob); + DRW_shgroup_call_object(material->shgrp, geoms[i], ob); } } } @@ -1044,7 +1089,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) /* Currently unsupported in sculpt mode. We could revert to the slow * method in this case but I'm not sure if it's a good idea given that * sculpted meshes are heavy to begin with. */ - // DRW_shgroup_call_sculpt_add(wpd->shadow_shgrp, ob, ob->obmat); + // DRW_shgroup_call_sculpt(wpd->shadow_shgrp, ob, ob->obmat); } else { WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( @@ -1056,7 +1101,6 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) { - invert_m4_m4(ob->imat, ob->obmat); mul_v3_mat3_m4v3( engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction); @@ -1074,7 +1118,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) } DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); - DRW_shgroup_call_add(grp, geom_shadow, ob->obmat); + DRW_shgroup_call(grp, geom_shadow, ob->obmat); #ifdef DEBUG_SHADOW_VOLUME DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); #endif @@ -1096,7 +1140,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) } DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_add(grp, DRW_cache_object_surface_get(ob), ob->obmat); + DRW_shgroup_call(grp, DRW_cache_object_surface_get(ob), ob->obmat); } if (is_manifold) { @@ -1108,7 +1152,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) } DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_add(grp, geom_shadow, ob->obmat); + DRW_shgroup_call(grp, geom_shadow, ob->obmat); #ifdef DEBUG_SHADOW_VOLUME DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); #endif @@ -1156,7 +1200,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) WORKBENCH_PrivateData *wpd = stl->g_data; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (TAA_ENABLED(wpd)) { + if (workbench_is_taa_enabled(wpd)) { workbench_taa_draw_scene_start(vedata); } diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c index a80f6ce338b..965f5a5ca4f 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c @@ -40,15 +40,16 @@ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) wpd->is_playback = false; } - if (TAA_ENABLED(wpd)) { + if (workbench_is_taa_enabled(wpd)) { psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx); } - else if (FXAA_ENABLED(wpd)) { + else if (workbench_is_fxaa_enabled(wpd)) { psl->effect_aa_pass = workbench_fxaa_create_pass(tx); effect_info->jitter_index = 0; } else { psl->effect_aa_pass = NULL; + effect_info->jitter_index = 0; } } @@ -73,13 +74,13 @@ void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) WORKBENCH_EffectInfo *effect_info = stl->effects; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (FXAA_ENABLED(wpd)) { + if (workbench_is_fxaa_enabled(wpd)) { GPU_framebuffer_bind(fbl->effect_fb); workspace_aa_draw_transform(tx, wpd); GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->effect_aa_pass); } - else if (TAA_ENABLED(wpd)) { + else if (workbench_is_taa_enabled(wpd)) { /* * when drawing the first TAA frame, we transform directly to the * color_only_fb as the TAA shader is just performing a direct copy. diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index 3dea99a76cf..e24536759db 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -136,7 +136,9 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) WORKBENCH_PrivateData *wpd = stl->g_data; WORKBENCH_FramebufferList *fbl = vedata->fbl; - if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (camera == NULL)) { + Camera *cam = camera != NULL ? camera->data : NULL; + if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) || + ((cam->dof.flag & CAM_DOF_ENABLED) == 0)) { wpd->dof_enabled = false; return; } @@ -229,26 +231,17 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) { const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); RegionView3D *rv3d = draw_ctx->rv3d; - Camera *cam = (Camera *)camera->data; /* Parameters */ /* TODO UI Options */ - float fstop = cam->gpu_dof.fstop; + float fstop = cam->dof.aperture_fstop; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); float focus_dist = BKE_camera_object_dof_distance(camera); float focal_len = cam->lens; /* TODO(fclem) deduplicate with eevee */ - - /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm - * unit.scale_length is how many meters per blender unit we have. We want to convert to blender - * units though because the shader reads coordinates in world space, which is in blender units. - * Note however that focus_distance is already in blender units and shall not be scaled here - * (see T48157). */ - float scale = (scene_eval->unit.system) ? scene_eval->unit.scale_length : 1.0f; - float scale_camera = 0.001f / scale; + const float scale_camera = 0.001f; /* we want radius here for the aperture number */ float aperture = 0.5f * scale_camera * focal_len / fstop; float focal_len_scaled = scale_camera * focal_len; @@ -265,9 +258,9 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) wpd->dof_near_far[0] = -cam->clip_start; wpd->dof_near_far[1] = -cam->clip_end; - float blades = cam->gpu_dof.num_blades; - float rotation = cam->gpu_dof.rotation; - float ratio = 1.0f / cam->gpu_dof.ratio; + float blades = cam->dof.aperture_blades; + float rotation = cam->dof.aperture_rotation; + float ratio = 1.0f / cam->dof.aperture_ratio; if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) { @@ -314,37 +307,37 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps); DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } #if 0 { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh, psl->dof_flatten_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh, psl->dof_flatten_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } #endif { @@ -357,14 +350,14 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps); @@ -373,7 +366,7 @@ void workbench_dof_create_pass(WORKBENCH_Data *vedata, DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c index 47355f324a8..6e3bf1658ab 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c @@ -49,7 +49,7 @@ DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx) DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); return pass; } diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c index 0435a804fab..7fd68babc13 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c @@ -90,26 +90,36 @@ int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata) { WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PrivateData *wpd = stl->g_data; - int result = 1; - if (TAA_ENABLED(wpd)) { + const Scene *scene = DRW_context_state_get()->scene; + int result; + if (workbench_is_taa_enabled(wpd)) { if (DRW_state_is_image_render()) { - const Scene *scene = DRW_context_state_get()->scene; - result = (scene->r.mode & R_OSA) ? scene->r.osa : 1; - } - else if (IN_RANGE_INCL(wpd->preferences->gpu_viewport_quality, - GPU_VIEWPORT_QUALITY_TAA8, - GPU_VIEWPORT_QUALITY_TAA16)) { - result = 8; - } - else if (IN_RANGE_INCL(wpd->preferences->gpu_viewport_quality, - GPU_VIEWPORT_QUALITY_TAA16, - GPU_VIEWPORT_QUALITY_TAA32)) { - result = 16; + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (draw_ctx->v3d) { + result = scene->display.viewport_aa; + } + else { + result = scene->display.render_aa; + } } else { - result = 32; + result = wpd->preferences->viewport_aa; } } + else { + /* when no TAA is disabled return 1 to render a single sample + * see `workbench_render.c` */ + result = 1; + } + return result; +} + +int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata)) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1; + result = MAX2(result, 1); return result; } @@ -125,6 +135,8 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata) workbench_taa_jitter_init(); } + effect_info->view = NULL; + /* reset complete drawing when navigating. */ if (effect_info->jitter_index != 0) { if (rv3d && rv3d->rflag & RV3D_NAVIGATING) { @@ -138,12 +150,10 @@ void workbench_taa_engine_init(WORKBENCH_Data *vedata) } { - float view[4][4]; - float win[4][4]; - DRW_viewport_matrix_get(view, DRW_MAT_VIEW); - DRW_viewport_matrix_get(win, DRW_MAT_WIN); - mul_m4_m4m4(effect_info->curr_mat, view, win); - if (!equals_m4m4(effect_info->curr_mat, effect_info->last_mat)) { + float persmat[4][4]; + DRW_view_persmat_get(NULL, persmat, false); + if (!equals_m4m4(persmat, effect_info->last_mat)) { + copy_m4_m4(effect_info->last_mat, persmat); effect_info->jitter_index = 0; } } @@ -191,7 +201,7 @@ DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_bu DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx); DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); /* * Set the offset for the cavity shader so every iteration different @@ -207,9 +217,9 @@ void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata) WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_EffectInfo *effect_info = stl->effects; const float *viewport_size = DRW_viewport_size_get(); + const DRWView *default_view = DRW_view_default_get(); int num_samples = 8; float(*samples)[2]; - float mix_factor; num_samples = workbench_taa_calculate_num_iterations(vedata); switch (num_samples) { @@ -231,41 +241,38 @@ void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata) break; } - mix_factor = 1.0f / (effect_info->jitter_index + 1); - const int jitter_index = effect_info->jitter_index; const float *transform_offset = samples[jitter_index]; + effect_info->taa_mix_factor = 1.0f / (jitter_index + 1); effect_info->jitter_index = (jitter_index + 1) % num_samples; /* construct new matrices from transform delta */ - float viewmat[4][4]; - float persmat[4][4]; - DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_get(effect_info->override_winmat, DRW_MAT_WIN); + float winmat[4][4], viewmat[4][4], persmat[4][4]; + DRW_view_winmat_get(default_view, winmat, false); + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_persmat_get(default_view, persmat, false); - window_translate_m4(effect_info->override_winmat, + window_translate_m4(winmat, persmat, transform_offset[0] / viewport_size[0], transform_offset[1] / viewport_size[1]); - mul_m4_m4m4(effect_info->override_persmat, effect_info->override_winmat, viewmat); - invert_m4_m4(effect_info->override_persinv, effect_info->override_persmat); - invert_m4_m4(effect_info->override_wininv, effect_info->override_winmat); - - DRW_viewport_matrix_override_set(effect_info->override_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(effect_info->override_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(effect_info->override_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(effect_info->override_wininv, DRW_MAT_WININV); - - /* weight the mix factor by the jitter index */ - effect_info->taa_mix_factor = mix_factor; + if (effect_info->view) { + /* When rendering just update the view. This avoids recomputing the culling. */ + DRW_view_update_sub(effect_info->view, viewmat, winmat); + } + else { + /* TAA is not making a big change to the matrices. + * Reuse the main view culling by creating a subview. */ + effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat); + } + DRW_view_set_active(effect_info->view); } void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata) { /* - * If first frame than the offset is 0.0 and its depth is the depth buffer to use + * If first frame then the offset is 0.0 and its depth is the depth buffer to use * for the rest of the draw engines. We store it in a persistent buffer. * * If it is not the first frame we copy the persistent buffer back to the @@ -286,10 +293,9 @@ void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata) GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT); if (!DRW_state_is_image_render()) { - DRW_viewport_matrix_override_unset_all(); + DRW_view_set_active(NULL); } - copy_m4_m4(effect_info->last_mat, effect_info->curr_mat); if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) { DRW_viewport_request_redraw(); } diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 00590940ac3..f12902b6801 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -68,6 +68,7 @@ static struct { /* Shaders */ extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_workbench_forward_composite_frag_glsl[]; extern char datatoc_workbench_forward_depth_frag_glsl[]; @@ -88,6 +89,7 @@ static char *workbench_build_forward_vert(bool is_hair) if (is_hair) { BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); } + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); char *str = BLI_dynstr_get_cstring(ds); @@ -99,6 +101,7 @@ static char *workbench_build_forward_transparent_accum_frag(void) { DynStr *ds = BLI_dynstr_new(); + BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); @@ -199,8 +202,7 @@ WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data(WORKBENCH_ V3D_SHADING_TEXTURE_COLOR) { material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh, psl->object_outline_pass); - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, GL_TEXTURE_2D, false); + GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex); } else { @@ -399,7 +401,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx); DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } /* TODO(campbell): displays but masks geometry, @@ -411,7 +413,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND); grp = DRW_shgroup_create(shader, psl->background_pass); wpd->world_clip_planes_batch = DRW_draw_background_clipping_batch_from_rv3d(draw_ctx->rv3d); - DRW_shgroup_call_add(grp, wpd->world_clip_planes_batch, NULL); + DRW_shgroup_call(grp, wpd->world_clip_planes_batch, NULL); DRW_shgroup_uniform_vec4(grp, "color", &wpd->world_clip_planes_color[0], 1); } @@ -441,7 +443,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS; psl->checker_depth_pass = DRW_pass_create("Checker Depth", state); grp = DRW_shgroup_create(e_data.checker_depth_sh, psl->checker_depth_pass); - DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); DRW_shgroup_uniform_float_copy(grp, "threshold", blend_threshold); DRW_shgroup_uniform_float_copy(grp, "offset", noise_offset); } @@ -565,70 +567,78 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) WORKBENCH_MaterialData *material; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool is_sculpt_mode = (ob->sculpt != NULL); - bool is_drawn = false; - - if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) { - const Mesh *me = ob->data; - if (me->mloopuv) { - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode); - DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob); - DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob); - } - is_drawn = true; + const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); + const int materials_len = MAX2(1, ob->totcol); + const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + + if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { + struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); + for (int i = 0; i < materials_len; i++) { + Material *mat; + Image *image; + ImageUser *iuser; + int interp; + workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); + int color_type = workbench_material_determine_color_type(wpd, image, ob, is_sculpt_mode); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, image, iuser, color_type, interp, is_sculpt_mode); + DRW_shgroup_call_object(material->shgrp_object_outline, geom_array[i], ob); + DRW_shgroup_call_object(material->shgrp, geom_array[i], ob); } } - - /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */ - if (!is_drawn) { - if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - /* No material split needed */ - int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode); - - struct GPUBatch *geom; - if (color_type == V3D_SHADING_VERTEX_COLOR) { - geom = DRW_cache_mesh_surface_vertpaint_get(ob); - } - else { - geom = DRW_cache_object_surface_get(ob); + else if (ELEM(wpd->shading.color_type, + V3D_SHADING_SINGLE_COLOR, + V3D_SHADING_OBJECT_COLOR, + V3D_SHADING_RANDOM_COLOR, + V3D_SHADING_VERTEX_COLOR)) { + /* No material split needed */ + int color_type = workbench_material_determine_color_type(wpd, NULL, ob, is_sculpt_mode); + + if (is_sculpt_mode) { + material = workbench_forward_get_or_create_material_data( + vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode); + bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); + if (!is_wire) { + DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); } + } + else { + struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ? + DRW_cache_mesh_surface_vertpaint_get(ob) : + DRW_cache_object_surface_get(ob); if (geom) { material = workbench_forward_get_or_create_material_data( vedata, ob, NULL, NULL, NULL, color_type, 0, is_sculpt_mode); - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat); - if (!is_wire) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); - } - } - else { - DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob); - if (!is_wire) { - DRW_shgroup_call_object_add(material->shgrp, geom, ob); - } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_object(material->shgrp_object_outline, geom, ob); + if (!is_wire) { + DRW_shgroup_call_object(material->shgrp, geom, ob); } } } + } + else { + /* Draw material color */ + if (is_sculpt_mode) { + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + + for (int i = 0; i < materials_len; ++i) { + struct Material *mat = give_current_material(ob, i + 1); + material = workbench_forward_get_or_create_material_data( + vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); + shgrps[i] = material->shgrp; + } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); + if (!is_wire) { + DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); + } + } else { - const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol)); struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - for (int i = 0; i < materials_len; i++) { - gpumat_array[i] = NULL; - } + memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( ob, gpumat_array, materials_len, NULL, NULL, NULL); @@ -641,17 +651,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) Material *mat = give_current_material(ob, i + 1); material = workbench_forward_get_or_create_material_data( vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0, is_sculpt_mode); - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat); - if (!is_wire) { - DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat); - } - } - else { - DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob); - if (!is_wire) { - DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob); - } + /* TODO(fclem) make this call optional */ + DRW_shgroup_call_object(material->shgrp_object_outline, mat_geom[i], ob); + if (!is_wire) { + DRW_shgroup_call_object(material->shgrp, mat_geom[i], ob); } } } @@ -682,7 +685,7 @@ void workbench_forward_draw_scene(WORKBENCH_Data *vedata) WORKBENCH_PrivateData *wpd = stl->g_data; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (TAA_ENABLED(wpd)) { + if (workbench_is_taa_enabled(wpd)) { workbench_taa_draw_scene_start(vedata); } diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index c403e358d6a..b280b6fd01a 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -294,15 +294,8 @@ void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, if (workbench_material_determine_color_type(wpd, material->ima, ob, false) == V3D_SHADING_TEXTURE_COLOR) { - ImBuf *ibuf = BKE_image_acquire_ibuf(material->ima, material->iuser, NULL); - const bool do_color_correction = wpd->use_color_management && - (ibuf && - (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0); - BKE_image_release_ibuf(material->ima, ibuf, NULL); - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, GL_TEXTURE_2D, false); + GPUTexture *tex = GPU_texture_from_blender(material->ima, material->iuser, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(grp, "image", tex); - DRW_shgroup_uniform_bool_copy(grp, "imageSrgb", do_color_correction); DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); } else { diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 3cfb1283416..240d06c1e79 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -75,18 +75,7 @@ #define IS_NAVIGATING(wpd) \ ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING)) -#define FXAA_ENABLED(wpd) \ - ((!DRW_state_is_opengl_render()) && \ - (IN_RANGE(wpd->preferences->gpu_viewport_quality, \ - GPU_VIEWPORT_QUALITY_FXAA, \ - GPU_VIEWPORT_QUALITY_TAA8) || \ - ((IS_NAVIGATING(wpd) || wpd->is_playback) && \ - (wpd->preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8)))) -#define TAA_ENABLED(wpd) \ - ((DRW_state_is_image_render() && DRW_context_state_get()->scene->r.mode & R_OSA) || \ - (!DRW_state_is_image_render() && \ - wpd->preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8 && !IS_NAVIGATING(wpd) && \ - !wpd->is_playback)) + #define SPECULAR_HIGHLIGHT_ENABLED(wpd) \ (STUDIOLIGHT_ENABLED(wpd) && (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && \ (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd))) @@ -284,12 +273,10 @@ typedef struct WORKBENCH_PrivateData { } WORKBENCH_PrivateData; /* Transient data */ typedef struct WORKBENCH_EffectInfo { - float override_persmat[4][4]; - float override_persinv[4][4]; - float override_winmat[4][4]; - float override_wininv[4][4]; + /** View */ + struct DRWView *view; + /** Last projection matrix to see if view is still valid. */ float last_mat[4][4]; - float curr_mat[4][4]; int jitter_index; float taa_mix_factor; bool view_updated; @@ -326,6 +313,46 @@ typedef struct WORKBENCH_ObjectData { int object_id; } WORKBENCH_ObjectData; +/* inline helper functions */ +BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd) +{ + if (DRW_state_is_image_render()) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (draw_ctx->v3d) { + return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA; + } + else { + return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA; + } + } + else { + return !(IS_NAVIGATING(wpd) || wpd->is_playback) && + wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; + } +} + +BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd) +{ + if (DRW_state_is_image_render()) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + if (draw_ctx->v3d) { + return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA; + } + else { + return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA; + } + } + else { + if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) { + return true; + } + + /* when navigating or animation playback use FXAA if scene uses TAA. */ + return (IS_NAVIGATING(wpd) || wpd->is_playback) && + wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; + } +} + /* workbench_deferred.c */ void workbench_deferred_engine_init(WORKBENCH_Data *vedata); void workbench_deferred_engine_free(void); @@ -375,6 +402,7 @@ void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata); void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata); void workbench_taa_view_updated(WORKBENCH_Data *vedata); int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata); +int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata); /* workbench_effect_dof.c */ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 1497ef493cf..46d78ca0e37 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -63,24 +63,16 @@ static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *deps float frame = BKE_scene_frame_get(scene); /* Set the persective, view and window matrix. */ - float winmat[4][4], wininv[4][4]; - float viewmat[4][4], viewinv[4][4]; - float persmat[4][4], persinv[4][4]; + float winmat[4][4], viewmat[4][4], viewinv[4][4]; RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat); RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv); invert_m4_m4(viewmat, viewinv); - mul_m4_m4m4(persmat, winmat, viewmat); - invert_m4_m4(persinv, persmat); - invert_m4_m4(wininv, winmat); - - DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV); - DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); + + DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); + DRW_view_default_set(view); + DRW_view_set_active(view); } static bool workbench_render_framebuffers_init(void) @@ -159,9 +151,6 @@ void workbench_render(WORKBENCH_Data *data, if (RE_engine_test_break(engine)) { break; } - /* TODO: Save matrices instead of recomputing them for each samples. */ - workbench_render_matrices_init(engine, depsgraph); - workbench_deferred_draw_background(data); workbench_deferred_draw_scene(data); } diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c index 3fc83fea7c6..944bca73993 100644 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ b/source/blender/draw/engines/workbench/workbench_studiolight.c @@ -32,7 +32,7 @@ void studiolight_update_world(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) { float view_matrix[4][4], rot_matrix[4][4]; - DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW); + DRW_view_viewmat_get(NULL, view_matrix, false); if (USE_WORLD_ORIENTATION(wpd)) { axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); @@ -165,12 +165,12 @@ void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_dire } float planes[6][4]; - DRW_culling_frustum_planes_get(planes); + DRW_culling_frustum_planes_get(NULL, planes); /* we only need the far plane. */ copy_v4_v4(wpd->shadow_far_plane, planes[2]); BoundBox frustum_corners; - DRW_culling_frustum_corners_get(&frustum_corners); + DRW_culling_frustum_corners_get(NULL, &frustum_corners); mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]); mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]); @@ -230,7 +230,8 @@ bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, WORKBENCH_ObjectData *oed) { BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed); - return DRW_culling_box_test(shadow_bbox); + const DRWView *default_view = DRW_view_default_get(); + return DRW_culling_box_test(default_view, shadow_bbox); } float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index accc7e91576..2b5fc8c0e47 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -53,6 +53,7 @@ static struct { extern char datatoc_workbench_volume_vert_glsl[]; extern char datatoc_workbench_volume_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) { @@ -77,8 +78,11 @@ static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) char *defines = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); - e_data.volume_sh[id] = DRW_shader_create( - datatoc_workbench_volume_vert_glsl, NULL, datatoc_workbench_volume_frag_glsl, defines); + e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl, + NULL, + datatoc_workbench_volume_frag_glsl, + datatoc_common_view_lib_glsl, + defines); MEM_freeN(defines); } @@ -150,7 +154,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, if (use_slice) { float invviewmat[4][4]; - DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV); + DRW_view_viewmat_get(NULL, invviewmat, true); const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(invviewmat[2]) : @@ -207,10 +211,10 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness); if (use_slice) { - DRW_shgroup_call_object_add(grp, DRW_cache_quad_get(), ob); + DRW_shgroup_call_object(grp, DRW_cache_quad_get(), ob); } else { - DRW_shgroup_call_object_add(grp, DRW_cache_cube_get(), ob); + DRW_shgroup_call_object(grp, DRW_cache_cube_get(), ob); } BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd)); diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 4d8fefbbc06..0f019df9d86 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -44,6 +44,7 @@ #include "DNA_world_types.h" #include "GPU_framebuffer.h" +#include "GPU_primitive.h" #include "GPU_texture.h" #include "GPU_shader.h" @@ -80,9 +81,13 @@ struct rcti; typedef struct DRWInterface DRWInterface; typedef struct DRWPass DRWPass; +typedef struct DRWView DRWView; typedef struct DRWShadingGroup DRWShadingGroup; typedef struct DRWUniform DRWUniform; +/* Opaque type to avoid usage as a DRWCall but it is exactly the same thing. */ +typedef struct DRWCallBuffer DRWCallBuffer; + /* TODO Put it somewhere else? */ typedef struct BoundSphere { float center[3], radius; @@ -105,7 +110,7 @@ typedef char DRWViewportEmptyList; /* Use of multisample framebuffers. */ #define MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl) \ { \ - if (dfbl->multisample_fb != NULL) { \ + if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \ DRW_stats_query_start("Multisample Blit"); \ GPU_framebuffer_bind(dfbl->multisample_fb); \ /* TODO clear only depth but need to do alpha to coverage for transparencies. */ \ @@ -117,7 +122,7 @@ typedef char DRWViewportEmptyList; #define MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl) \ { \ - if (dfbl->multisample_fb != NULL) { \ + if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \ DRW_stats_query_start("Multisample Resolve"); \ GPU_framebuffer_bind(dfbl->default_fb); \ DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, true); \ @@ -128,7 +133,7 @@ typedef char DRWViewportEmptyList; #define MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl) \ { \ - if (dfbl->multisample_fb != NULL) { \ + if (dfbl->multisample_fb != NULL && DRW_state_is_fbo()) { \ DRW_stats_query_start("Multisample Resolve"); \ GPU_framebuffer_bind(dfbl->default_fb); \ DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, false); \ @@ -309,43 +314,47 @@ void DRW_shader_free(struct GPUShader *shader); /* Batches */ typedef enum { + /** Wrtie mask */ DRW_STATE_WRITE_DEPTH = (1 << 0), DRW_STATE_WRITE_COLOR = (1 << 1), - DRW_STATE_DEPTH_ALWAYS = (1 << 2), - DRW_STATE_DEPTH_LESS = (1 << 3), - DRW_STATE_DEPTH_LESS_EQUAL = (1 << 4), - DRW_STATE_DEPTH_EQUAL = (1 << 5), - DRW_STATE_DEPTH_GREATER = (1 << 6), - DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 7), - DRW_STATE_CULL_BACK = (1 << 8), - DRW_STATE_CULL_FRONT = (1 << 9), - DRW_STATE_WIRE = (1 << 10), - DRW_STATE_POINT = (1 << 11), + DRW_STATE_WRITE_STENCIL = (1 << 2), + DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 3), + DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 4), + + /** Depth test */ + DRW_STATE_DEPTH_ALWAYS = (1 << 5), + DRW_STATE_DEPTH_LESS = (1 << 6), + DRW_STATE_DEPTH_LESS_EQUAL = (1 << 7), + DRW_STATE_DEPTH_EQUAL = (1 << 8), + DRW_STATE_DEPTH_GREATER = (1 << 9), + DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 10), + /** Culling test */ + DRW_STATE_CULL_BACK = (1 << 11), + DRW_STATE_CULL_FRONT = (1 << 12), + /** Stencil test */ + DRW_STATE_STENCIL_EQUAL = (1 << 13), + DRW_STATE_STENCIL_NEQUAL = (1 << 14), + + /** Blend state */ + DRW_STATE_ADDITIVE = (1 << 15), + /** Same as additive but let alpha accumulate without premult. */ + DRW_STATE_ADDITIVE_FULL = (1 << 16), + DRW_STATE_BLEND = (1 << 17), + /** Use that if color is already premult by alpha. */ + DRW_STATE_BLEND_PREMUL = (1 << 18), + DRW_STATE_BLEND_PREMUL_UNDER = (1 << 19), + DRW_STATE_BLEND_OIT = (1 << 20), + DRW_STATE_MULTIPLY = (1 << 21), + + DRW_STATE_CLIP_PLANES = (1 << 22), + DRW_STATE_WIRE_SMOOTH = (1 << 23), + DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 24), /** Polygon offset. Does not work with lines and points. */ - DRW_STATE_OFFSET_POSITIVE = (1 << 12), + DRW_STATE_OFFSET_POSITIVE = (1 << 25), /** Polygon offset. Does not work with lines and points. */ - DRW_STATE_OFFSET_NEGATIVE = (1 << 13), - DRW_STATE_WIRE_WIDE = (1 << 14), - DRW_STATE_BLEND = (1 << 15), - DRW_STATE_ADDITIVE = (1 << 16), - DRW_STATE_MULTIPLY = (1 << 17), - DRW_STATE_BLEND_PREMUL_UNDER = (1 << 18), - DRW_STATE_CLIP_PLANES = (1 << 19), - /** Same as DRW_STATE_ADDITIVE but let alpha accumulate without premult. */ - DRW_STATE_ADDITIVE_FULL = (1 << 20), - /** Use that if color is already premult by alpha. */ - DRW_STATE_BLEND_PREMUL = (1 << 21), - DRW_STATE_WIRE_SMOOTH = (1 << 22), - DRW_STATE_TRANS_FEEDBACK = (1 << 23), - DRW_STATE_BLEND_OIT = (1 << 24), - DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 25), - - DRW_STATE_WRITE_STENCIL = (1 << 27), - DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 28), - DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 29), - DRW_STATE_STENCIL_EQUAL = (1 << 30), - DRW_STATE_STENCIL_NEQUAL = (1 << 31), + DRW_STATE_OFFSET_NEGATIVE = (1 << 26), } DRWState; + #define DRW_STATE_DEFAULT \ (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL) #define DRW_STATE_RASTERIZER_ENABLED \ @@ -377,97 +386,64 @@ struct GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFor DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup); DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass); -DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, - DRWPass *pass, - struct GPUBatch *geom, - struct Object *ob, - struct GPUVertFormat *format); -DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(struct GPUMaterial *material, - DRWPass *pass, - int size); -DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, - DRWPass *pass, - struct GPUBatch *geom, - struct GPUVertFormat *format); -DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass); -DRWShadingGroup *DRW_shgroup_line_batch_create_with_format(struct GPUShader *shader, - DRWPass *pass, - struct GPUVertFormat *format); -DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass); -DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, - DRWPass *pass, - int size); DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, struct GPUVertBuf *tf_target); -typedef void(DRWCallGenerateFn)(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, struct GPUBatch *geom), - void *user_data); - /* return final visibility */ typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data); -void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct GPUBatch *batch); - -void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct GPUBatch *geom, float (*obmat)[4]); -void DRW_shgroup_call_range_add( - DRWShadingGroup *shgroup, struct GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_count); -void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, - uint point_len, - float (*obmat)[4]); -void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, - uint line_count, - float (*obmat)[4]); -void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, - uint tria_count, - float (*obmat)[4]); -void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, - uint tria_count, - struct Object *ob); -void DRW_shgroup_call_object_add_ex(DRWShadingGroup *shgroup, - struct GPUBatch *geom, - struct Object *ob, - struct Material *ma, - bool bypass_culling); -#define DRW_shgroup_call_object_add(shgroup, geom, ob) \ - DRW_shgroup_call_object_add_ex(shgroup, geom, ob, NULL, false) -#define DRW_shgroup_call_object_add_no_cull(shgroup, geom, ob) \ - DRW_shgroup_call_object_add_ex(shgroup, geom, ob, NULL, true) -void DRW_shgroup_call_object_add_with_callback(DRWShadingGroup *shgroup, - struct GPUBatch *geom, - struct Object *ob, - struct Material *ma, - DRWCallVisibilityFn *callback, - void *user_data); -/* Used for drawing a batch with instancing without instance attributes. */ -void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, - struct GPUBatch *geom, - float (*obmat)[4], - uint *count); -void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, +void DRW_shgroup_call(DRWShadingGroup *sh, struct GPUBatch *geom, float (*obmat)[4]); +void DRW_shgroup_call_range( + DRWShadingGroup *sh, struct GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_ct); + +void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, uint point_ct, float (*obmat)[4]); +void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, uint line_ct, float (*obmat)[4]); +void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, uint tri_ct, float (*obmat)[4]); + +void DRW_shgroup_call_object_ex(DRWShadingGroup *shgroup, + struct GPUBatch *geom, + struct Object *ob, + bool bypass_culling); +#define DRW_shgroup_call_object(shgroup, geom, ob) \ + DRW_shgroup_call_object_ex(shgroup, geom, ob, false) +#define DRW_shgroup_call_object_no_cull(shgroup, geom, ob) \ + DRW_shgroup_call_object_ex(shgroup, geom, ob, true) + +/* TODO(fclem) remove this when we have DRWView */ +/* user_data is used by DRWCallVisibilityFn defined in DRWView. */ +void DRW_shgroup_call_object_with_callback(DRWShadingGroup *shgroup, struct GPUBatch *geom, struct Object *ob, - uint *count); -void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]); -void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup, - struct Object *ob, - float (*obmat)[4]); -void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup, - DRWCallGenerateFn *geometry_fn, - void *user_data, - float (*obmat)[4]); -void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, - const void *attr[], - uint attr_len); -#define DRW_shgroup_call_dynamic_add(shgroup, ...) \ + void *user_data); + +void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, + struct GPUBatch *geom, + float (*obmat)[4], + uint count); +void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup, + struct GPUBatch *geom, + float (*obmat)[4], + struct GPUBatch *inst_attributes); + +void DRW_shgroup_call_sculpt(DRWShadingGroup *sh, Object *ob, bool wire, bool mask, bool vcol); +void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **sh, Object *ob, bool vcol); + +DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shading_group, + struct GPUVertFormat *format, + GPUPrimType prim_type); +DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shading_group, + struct GPUVertFormat *format, + struct GPUBatch *geom); + +void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint attr_len); + +#define DRW_buffer_add_entry(buffer, ...) \ do { \ const void *array[] = {__VA_ARGS__}; \ - DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \ + DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \ } while (0) -uint DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup); - void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); @@ -503,14 +479,6 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); -void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, - const char *name, - const short *value, - int arraysize); -void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, - const char *name, - const short *value, - int arraysize); /* Boolean are expected to be 4bytes longs for opengl! */ void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, @@ -538,11 +506,13 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value); void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value); void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value); +void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value); bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); +/* TODO Replace with passes inheritance. */ void DRW_pass_state_set(DRWPass *pass, DRWState state); void DRW_pass_state_add(DRWPass *pass, DRWState state); void DRW_pass_state_remove(DRWPass *pass, DRWState state); @@ -553,51 +523,61 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass); bool DRW_pass_is_empty(DRWPass *pass); -/* Viewport */ -typedef enum { - /* keep in sync with the union struct DRWMatrixState. */ - DRW_MAT_PERS = 0, - DRW_MAT_PERSINV, - DRW_MAT_VIEW, - DRW_MAT_VIEWINV, - DRW_MAT_WIN, - DRW_MAT_WININV, - - DRW_MAT_COUNT, // Don't use this. -} DRWViewportMatrixType; - -typedef struct DRWMatrixState { - union { - float mat[DRW_MAT_COUNT][4][4]; - struct { - /* keep in sync with the enum DRWViewportMatrixType. */ - float persmat[4][4]; - float persinv[4][4]; - float viewmat[4][4]; - float viewinv[4][4]; - float winmat[4][4]; - float wininv[4][4]; - }; - }; -} DRWMatrixState; - -void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type); -void DRW_viewport_matrix_get_all(DRWMatrixState *state); -void DRW_viewport_matrix_override_set(const float mat[4][4], DRWViewportMatrixType type); -void DRW_viewport_matrix_override_set_all(DRWMatrixState *state); -void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type); -void DRW_viewport_matrix_override_unset_all(void); - -/* These are in view-space so negative if in perspective. +#define DRW_PASS_CREATE(pass, state) (pass = DRW_pass_create(#pass, state)) + +/* Views */ +DRWView *DRW_view_create(const float viewmat[4][4], + const float winmat[4][4], + const float (*culling_viewmat)[4], + const float (*culling_winmat)[4], + DRWCallVisibilityFn *visibility_fn); +DRWView *DRW_view_create_sub(const DRWView *parent_view, + const float viewmat[4][4], + const float winmat[4][4]); + +void DRW_view_update(DRWView *view, + const float viewmat[4][4], + const float winmat[4][4], + const float (*culling_viewmat)[4], + const float (*culling_winmat)[4]); +void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]); + +const DRWView *DRW_view_default_get(void); +void DRW_view_default_set(DRWView *view); + +void DRW_view_set_active(DRWView *view); + +void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len); +void DRW_view_camtexco_set(DRWView *view, float texco[4]); + +/* For all getters, if view is NULL, default view is assumed. */ +void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse); +void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse); +void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse); + +void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners); +void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]); + +/* These are in view-space, so negative if in perspective. * Extract near and far clip distance from the projection matrix. */ -float DRW_viewport_near_distance_get(void); -float DRW_viewport_far_distance_get(void); +float DRW_view_near_distance_get(const DRWView *view); +float DRW_view_far_distance_get(const DRWView *view); +bool DRW_view_is_persp_get(const DRWView *view); + +/* Culling, return true if object is inside view frustum. */ +bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere); +bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox); +bool DRW_culling_plane_test(const DRWView *view, const float plane[4]); + +void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners); +void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]); + +/* Viewport */ const float *DRW_viewport_size_get(void); const float *DRW_viewport_invert_size_get(void); const float *DRW_viewport_screenvecs_get(void); const float *DRW_viewport_pixelsize_get(void); -bool DRW_viewport_is_persp_get(void); struct DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void); struct DefaultTextureList *DRW_viewport_texture_list_get(void); @@ -635,12 +615,14 @@ DrawData *DRW_drawdata_ensure(ID *id, size_t size, DrawDataInitCb init_cb, DrawDataFreeCb free_cb); +void **DRW_duplidata_get(void *vedata); /* Settings */ bool DRW_object_is_renderable(const struct Object *ob); int DRW_object_visibility_in_active_context(const struct Object *ob); bool DRW_object_is_flat_normal(const struct Object *ob); bool DRW_object_use_hide_faces(const struct Object *ob); +bool DRW_object_use_pbvh_drawing(const struct Object *ob); bool DRW_object_is_visible_psys_in_active_context(const struct Object *object, const struct ParticleSystem *psys); @@ -659,20 +641,6 @@ void DRW_state_reset_ex(DRWState state); void DRW_state_reset(void); void DRW_state_lock(DRWState state); -void DRW_state_invert_facing(void); - -void DRW_state_clip_planes_len_set(uint plane_len); -void DRW_state_clip_planes_reset(void); -void DRW_state_clip_planes_set_from_rv3d(struct RegionView3D *rv3d); - -/* Culling, return true if object is inside view frustum. */ -bool DRW_culling_sphere_test(BoundSphere *bsphere); -bool DRW_culling_box_test(BoundBox *bbox); -bool DRW_culling_plane_test(float plane[4]); - -void DRW_culling_frustum_corners_get(BoundBox *corners); -void DRW_culling_frustum_planes_get(float planes[6][4]); - /* Selection */ void DRW_select_load_id(uint id); diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c index a6026c9da3a..72459309133 100644 --- a/source/blender/draw/intern/draw_anim_viz.c +++ b/source/blender/draw/intern/draw_anim_viz.c @@ -139,7 +139,7 @@ static void MPATH_cache_init(void *vedata) } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_POINT; + DRWState state = DRW_STATE_WRITE_COLOR; psl->points = DRW_pass_create("Motionpath Point Pass", state); } } @@ -215,7 +215,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl, DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1); } /* Only draw the required range. */ - DRW_shgroup_call_range_add(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len); + DRW_shgroup_call_range(shgrp, mpath_batch_line_get(mpath), NULL, start_index, len); } /* Draw points. */ @@ -231,7 +231,7 @@ static void MPATH_cache_motion_path(MPATH_PassList *psl, DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1); } /* Only draw the required range. */ - DRW_shgroup_call_range_add(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len); + DRW_shgroup_call_range(shgrp, mpath_batch_points_get(mpath), NULL, start_index, len); /* Draw frame numbers at each framestep value */ bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0; diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 9b52f282944..3f651b27dd0 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -37,6 +37,8 @@ #include "BKE_armature.h" +#include "DEG_depsgraph_query.h" + #include "ED_armature.h" #include "UI_resources.h" @@ -57,26 +59,26 @@ static struct { /* Current armature object */ Object *ob; /* Reset when changing current_armature */ - DRWShadingGroup *bone_octahedral_solid; - DRWShadingGroup *bone_octahedral_wire; - DRWShadingGroup *bone_octahedral_outline; - DRWShadingGroup *bone_box_solid; - DRWShadingGroup *bone_box_wire; - DRWShadingGroup *bone_box_outline; - DRWShadingGroup *bone_wire; - DRWShadingGroup *bone_stick; - DRWShadingGroup *bone_dof_sphere; - DRWShadingGroup *bone_dof_lines; - DRWShadingGroup *bone_envelope_solid; - DRWShadingGroup *bone_envelope_distance; - DRWShadingGroup *bone_envelope_wire; - DRWShadingGroup *bone_point_solid; - DRWShadingGroup *bone_point_wire; - DRWShadingGroup *bone_axes; - DRWShadingGroup *lines_relationship; - DRWShadingGroup *lines_ik; - DRWShadingGroup *lines_ik_no_target; - DRWShadingGroup *lines_ik_spline; + DRWCallBuffer *bone_octahedral_solid; + DRWCallBuffer *bone_octahedral_wire; + DRWCallBuffer *bone_octahedral_outline; + DRWCallBuffer *bone_box_solid; + DRWCallBuffer *bone_box_wire; + DRWCallBuffer *bone_box_outline; + DRWCallBuffer *bone_wire; + DRWCallBuffer *bone_stick; + DRWCallBuffer *bone_dof_sphere; + DRWCallBuffer *bone_dof_lines; + DRWCallBuffer *bone_envelope_solid; + DRWCallBuffer *bone_envelope_distance; + DRWCallBuffer *bone_envelope_wire; + DRWCallBuffer *bone_point_solid; + DRWCallBuffer *bone_point_wire; + DRWCallBuffer *bone_axes; + DRWCallBuffer *lines_relationship; + DRWCallBuffer *lines_ik; + DRWCallBuffer *lines_ik_no_target; + DRWCallBuffer *lines_ik_spline; DRWArmaturePasses passes; @@ -120,22 +122,21 @@ static void drw_shgroup_bone_octahedral(const float (*bone_mat)[4], { if (g_data.bone_octahedral_outline == NULL) { struct GPUBatch *geom = DRW_cache_bone_octahedral_wire_get(); - g_data.bone_octahedral_outline = shgroup_instance_bone_shape_outline( + g_data.bone_octahedral_outline = buffer_instance_bone_shape_outline( g_data.passes.bone_outline, geom, sh_cfg); } if (g_data.bone_octahedral_solid == NULL && g_data.passes.bone_solid != NULL) { struct GPUBatch *geom = DRW_cache_bone_octahedral_get(); - g_data.bone_octahedral_solid = shgroup_instance_bone_shape_solid( + g_data.bone_octahedral_solid = buffer_instance_bone_shape_solid( g_data.passes.bone_solid, geom, g_data.transparent, sh_cfg); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); if (g_data.bone_octahedral_solid != NULL) { - DRW_shgroup_call_dynamic_add( - g_data.bone_octahedral_solid, final_bonemat, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_octahedral_solid, final_bonemat, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_outline, final_bonemat, outline_color); + DRW_buffer_add_entry(g_data.bone_octahedral_outline, final_bonemat, outline_color); } } @@ -148,21 +149,21 @@ static void drw_shgroup_bone_box(const float (*bone_mat)[4], { if (g_data.bone_box_wire == NULL) { struct GPUBatch *geom = DRW_cache_bone_box_wire_get(); - g_data.bone_box_outline = shgroup_instance_bone_shape_outline( + g_data.bone_box_outline = buffer_instance_bone_shape_outline( g_data.passes.bone_outline, geom, sh_cfg); } if (g_data.bone_box_solid == NULL && g_data.passes.bone_solid != NULL) { struct GPUBatch *geom = DRW_cache_bone_box_get(); - g_data.bone_box_solid = shgroup_instance_bone_shape_solid( + g_data.bone_box_solid = buffer_instance_bone_shape_solid( g_data.passes.bone_solid, geom, g_data.transparent, sh_cfg); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); if (g_data.bone_box_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, final_bonemat, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_box_solid, final_bonemat, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_box_outline, final_bonemat, outline_color); + DRW_buffer_add_entry(g_data.bone_box_outline, final_bonemat, outline_color); } } @@ -172,15 +173,15 @@ static void drw_shgroup_bone_wire(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg) { if (g_data.bone_wire == NULL) { - g_data.bone_wire = shgroup_dynlines_flat_color(g_data.passes.bone_wire, sh_cfg); + g_data.bone_wire = buffer_dynlines_flat_color(g_data.passes.bone_wire, sh_cfg); } float head[3], tail[3]; mul_v3_m4v3(head, g_data.ob->obmat, bone_mat[3]); - DRW_shgroup_call_dynamic_add(g_data.bone_wire, head, color); + DRW_buffer_add_entry(g_data.bone_wire, head, color); add_v3_v3v3(tail, bone_mat[3], bone_mat[1]); mul_m4_v3(g_data.ob->obmat, tail); - DRW_shgroup_call_dynamic_add(g_data.bone_wire, tail, color); + DRW_buffer_add_entry(g_data.bone_wire, tail, color); } /* Stick */ @@ -192,12 +193,12 @@ static void drw_shgroup_bone_stick(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg) { if (g_data.bone_stick == NULL) { - g_data.bone_stick = shgroup_instance_bone_stick(g_data.passes.bone_wire, sh_cfg); + g_data.bone_stick = buffer_instance_bone_stick(g_data.passes.bone_wire, sh_cfg); } float final_bonemat[4][4], tail[4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); add_v3_v3v3(tail, final_bonemat[3], final_bonemat[1]); - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( g_data.bone_stick, final_bonemat[3], tail, col_wire, col_bone, col_head, col_tail); } @@ -210,7 +211,7 @@ static void drw_shgroup_bone_envelope_distance(const float (*bone_mat)[4], { if (g_data.passes.bone_envelope != NULL) { if (g_data.bone_envelope_distance == NULL) { - g_data.bone_envelope_distance = shgroup_instance_bone_envelope_distance( + g_data.bone_envelope_distance = buffer_instance_bone_envelope_distance( g_data.passes.bone_envelope, sh_cfg); /* passes.bone_envelope should have the DRW_STATE_CULL_FRONT state enabled. */ } @@ -225,7 +226,7 @@ static void drw_shgroup_bone_envelope_distance(const float (*bone_mat)[4], head_sphere[3] += *distance; tail_sphere[3] = *radius_tail; tail_sphere[3] += *distance; - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( g_data.bone_envelope_distance, head_sphere, tail_sphere, final_bonemat[0]); } } @@ -239,22 +240,19 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg) { if (g_data.bone_point_wire == NULL) { - g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg); + g_data.bone_point_wire = buffer_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg); } if (g_data.bone_point_solid == NULL && g_data.passes.bone_solid != NULL) { - g_data.bone_point_solid = shgroup_instance_bone_sphere_solid( + g_data.bone_point_solid = buffer_instance_bone_sphere_solid( g_data.passes.bone_solid, g_data.transparent, sh_cfg); } if (g_data.bone_envelope_wire == NULL) { - g_data.bone_envelope_wire = shgroup_instance_bone_envelope_outline(g_data.passes.bone_wire, - sh_cfg); + g_data.bone_envelope_wire = buffer_instance_bone_envelope_outline(g_data.passes.bone_wire, + sh_cfg); } if (g_data.bone_envelope_solid == NULL && g_data.passes.bone_solid != NULL) { - g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid( + g_data.bone_envelope_solid = buffer_instance_bone_envelope_solid( g_data.passes.bone_solid, g_data.transparent, sh_cfg); - /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to - * inverted matrix. */ - DRW_shgroup_state_enable(g_data.bone_envelope_solid, DRW_STATE_CULL_BACK); } float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f}; @@ -272,10 +270,10 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], tmp[3][3] = 1.0f; copy_v3_v3(tmp[3], tail_sphere); if (g_data.bone_point_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color); + DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color); } } else if (tail_sphere[3] < 0.0f) { @@ -285,10 +283,10 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], tmp[3][3] = 1.0f; copy_v3_v3(tmp[3], head_sphere); if (g_data.bone_point_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color); + DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color); } } else { @@ -305,15 +303,15 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], interp_v4_v4v4(head_sphere, tail_sphere, head_sphere, fac_head); interp_v4_v4v4(tail_sphere, tmp_sphere, tail_sphere, fac_tail); if (g_data.bone_envelope_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, - head_sphere, - tail_sphere, - bone_color, - hint_color, - final_bonemat[0]); + DRW_buffer_add_entry(g_data.bone_envelope_solid, + head_sphere, + tail_sphere, + bone_color, + hint_color, + final_bonemat[0]); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( g_data.bone_envelope_wire, head_sphere, tail_sphere, outline_color, final_bonemat[0]); } } @@ -325,10 +323,10 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], tmp[3][3] = 1.0f; copy_v3_v3(tmp[3], tmp_sphere); if (g_data.bone_point_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_point_solid, tmp, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color); + DRW_buffer_add_entry(g_data.bone_point_wire, tmp, outline_color); } } } @@ -336,6 +334,7 @@ static void drw_shgroup_bone_envelope(const float (*bone_mat)[4], /* Custom (geometry) */ +extern void drw_batch_cache_validate(Object *custom); extern void drw_batch_cache_generate_requested(Object *custom); static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], @@ -345,6 +344,10 @@ static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg, Object *custom) { + /* TODO(fclem) arg... less than ideal but we never iter on this object + * to assure batch cache is valid. */ + drw_batch_cache_validate(custom); + struct GPUBatch *surf = DRW_cache_object_surface_get(custom); struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL); struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom); @@ -357,50 +360,50 @@ static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], BLI_assert(g_data.passes.custom_shapes != NULL); if (surf && g_data.passes.bone_solid != NULL) { - DRWShadingGroup *shgrp_geom_solid = BLI_ghash_lookup(g_data.passes.custom_shapes, surf); + DRWCallBuffer *buf_geom_solid = BLI_ghash_lookup(g_data.passes.custom_shapes, surf); - if (shgrp_geom_solid == NULL) { + if (buf_geom_solid == NULL) { /* TODO(fclem) needs to be moved elsewhere. */ drw_batch_cache_generate_requested(custom); /* NOTE! g_data.transparent require a separate shading group if the * object is transparent. This is done by passing a different ghash * for transparent armature in pose mode. */ - shgrp_geom_solid = shgroup_instance_bone_shape_solid( + buf_geom_solid = buffer_instance_bone_shape_solid( g_data.passes.bone_solid, surf, g_data.transparent, sh_cfg); - BLI_ghash_insert(g_data.passes.custom_shapes, surf, shgrp_geom_solid); + BLI_ghash_insert(g_data.passes.custom_shapes, surf, buf_geom_solid); } - DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, bone_color, hint_color); + DRW_buffer_add_entry(buf_geom_solid, final_bonemat, bone_color, hint_color); } if (edges && outline_color[3] > 0.0f) { - DRWShadingGroup *shgrp_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, edges); + DRWCallBuffer *buf_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, edges); - if (shgrp_geom_wire == NULL) { + if (buf_geom_wire == NULL) { /* TODO(fclem) needs to be moved elsewhere. */ drw_batch_cache_generate_requested(custom); - shgrp_geom_wire = shgroup_instance_bone_shape_outline( + buf_geom_wire = buffer_instance_bone_shape_outline( g_data.passes.bone_outline, edges, sh_cfg); - BLI_ghash_insert(g_data.passes.custom_shapes, edges, shgrp_geom_wire); + BLI_ghash_insert(g_data.passes.custom_shapes, edges, buf_geom_wire); } - DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, outline_color); + DRW_buffer_add_entry(buf_geom_wire, final_bonemat, outline_color); } if (ledges) { - DRWShadingGroup *shgrp_geom_ledges = BLI_ghash_lookup(g_data.passes.custom_shapes, ledges); + DRWCallBuffer *buf_geom_ledges = BLI_ghash_lookup(g_data.passes.custom_shapes, ledges); - if (shgrp_geom_ledges == NULL) { + if (buf_geom_ledges == NULL) { /* TODO(fclem) needs to be moved elsewhere. */ drw_batch_cache_generate_requested(custom); - shgrp_geom_ledges = shgroup_instance_wire(g_data.passes.bone_wire, ledges); + buf_geom_ledges = buffer_instance_wire(g_data.passes.bone_wire, ledges); - BLI_ghash_insert(g_data.passes.custom_shapes, ledges, shgrp_geom_ledges); + BLI_ghash_insert(g_data.passes.custom_shapes, ledges, buf_geom_ledges); } float final_color[4] = {outline_color[0], outline_color[1], outline_color[2], 1.0f}; - DRW_shgroup_call_dynamic_add(shgrp_geom_ledges, final_bonemat, final_color); + DRW_buffer_add_entry(buf_geom_ledges, final_bonemat, final_color); } } @@ -408,23 +411,27 @@ static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float color[4], Object *custom) { + /* TODO(fclem) arg... less than ideal but we never iter on this object + * to assure batch cache is valid. */ + drw_batch_cache_validate(custom); + struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom); if (geom) { - DRWShadingGroup *shgrp_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, geom); + DRWCallBuffer *buf_geom_wire = BLI_ghash_lookup(g_data.passes.custom_shapes, geom); - if (shgrp_geom_wire == NULL) { + if (buf_geom_wire == NULL) { /* TODO(fclem) needs to be moved elsewhere. */ drw_batch_cache_generate_requested(custom); - shgrp_geom_wire = shgroup_instance_wire(g_data.passes.bone_wire, geom); + buf_geom_wire = buffer_instance_wire(g_data.passes.bone_wire, geom); - BLI_ghash_insert(g_data.passes.custom_shapes, geom, shgrp_geom_wire); + BLI_ghash_insert(g_data.passes.custom_shapes, geom, buf_geom_wire); } float final_color[4] = {color[0], color[1], color[2], 1.0f}; float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); - DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, final_color); + DRW_buffer_add_entry(buf_geom_wire, final_bonemat, final_color); } } @@ -436,19 +443,19 @@ static void drw_shgroup_bone_point(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg) { if (g_data.bone_point_wire == NULL) { - g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg); + g_data.bone_point_wire = buffer_instance_bone_sphere_outline(g_data.passes.bone_wire, sh_cfg); } if (g_data.bone_point_solid == NULL && g_data.passes.bone_solid != NULL) { - g_data.bone_point_solid = shgroup_instance_bone_sphere_solid( + g_data.bone_point_solid = buffer_instance_bone_sphere_solid( g_data.passes.bone_solid, g_data.transparent, sh_cfg); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); if (g_data.bone_point_solid != NULL) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, final_bonemat, bone_color, hint_color); + DRW_buffer_add_entry(g_data.bone_point_solid, final_bonemat, bone_color, hint_color); } if (outline_color[3] > 0.0f) { - DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, final_bonemat, outline_color); + DRW_buffer_add_entry(g_data.bone_point_wire, final_bonemat, outline_color); } } @@ -458,11 +465,11 @@ static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const eGPUShaderConfig sh_cfg) { if (g_data.bone_axes == NULL) { - g_data.bone_axes = shgroup_instance_bone_axes(g_data.passes.bone_axes, sh_cfg); + g_data.bone_axes = buffer_instance_bone_axes(g_data.passes.bone_axes, sh_cfg); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); - DRW_shgroup_call_dynamic_add(g_data.bone_axes, final_bonemat, color); + DRW_buffer_add_entry(g_data.bone_axes, final_bonemat, color); } /* Relationship lines */ @@ -471,15 +478,15 @@ static void drw_shgroup_bone_relationship_lines(const float start[3], const eGPUShaderConfig sh_cfg) { if (g_data.lines_relationship == NULL) { - g_data.lines_relationship = shgroup_dynlines_dashed_uniform_color( + g_data.lines_relationship = buffer_dynlines_dashed_uniform_color( g_data.passes.relationship_lines, g_theme.wire_color, sh_cfg); } /* reverse order to have less stipple overlap */ float v[3]; mul_v3_m4v3(v, g_data.ob->obmat, end); - DRW_shgroup_call_dynamic_add(g_data.lines_relationship, v); + DRW_buffer_add_entry(g_data.lines_relationship, v); mul_v3_m4v3(v, g_data.ob->obmat, start); - DRW_shgroup_call_dynamic_add(g_data.lines_relationship, v); + DRW_buffer_add_entry(g_data.lines_relationship, v); } static void drw_shgroup_bone_ik_lines(const float start[3], @@ -488,15 +495,15 @@ static void drw_shgroup_bone_ik_lines(const float start[3], { if (g_data.lines_ik == NULL) { static float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */ - g_data.lines_ik = shgroup_dynlines_dashed_uniform_color( + g_data.lines_ik = buffer_dynlines_dashed_uniform_color( g_data.passes.relationship_lines, fcolor, sh_cfg); } /* reverse order to have less stipple overlap */ float v[3]; mul_v3_m4v3(v, g_data.ob->obmat, end); - DRW_shgroup_call_dynamic_add(g_data.lines_ik, v); + DRW_buffer_add_entry(g_data.lines_ik, v); mul_v3_m4v3(v, g_data.ob->obmat, start); - DRW_shgroup_call_dynamic_add(g_data.lines_ik, v); + DRW_buffer_add_entry(g_data.lines_ik, v); } static void drw_shgroup_bone_ik_no_target_lines(const float start[3], @@ -505,15 +512,15 @@ static void drw_shgroup_bone_ik_no_target_lines(const float start[3], { if (g_data.lines_ik_no_target == NULL) { static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */ - g_data.lines_ik_no_target = shgroup_dynlines_dashed_uniform_color( + g_data.lines_ik_no_target = buffer_dynlines_dashed_uniform_color( g_data.passes.relationship_lines, fcolor, sh_cfg); } /* reverse order to have less stipple overlap */ float v[3]; mul_v3_m4v3(v, g_data.ob->obmat, end); - DRW_shgroup_call_dynamic_add(g_data.lines_ik_no_target, v); + DRW_buffer_add_entry(g_data.lines_ik_no_target, v); mul_v3_m4v3(v, g_data.ob->obmat, start); - DRW_shgroup_call_dynamic_add(g_data.lines_ik_no_target, v); + DRW_buffer_add_entry(g_data.lines_ik_no_target, v); } static void drw_shgroup_bone_ik_spline_lines(const float start[3], @@ -522,15 +529,15 @@ static void drw_shgroup_bone_ik_spline_lines(const float start[3], { if (g_data.lines_ik_spline == NULL) { static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */ - g_data.lines_ik_spline = shgroup_dynlines_dashed_uniform_color( + g_data.lines_ik_spline = buffer_dynlines_dashed_uniform_color( g_data.passes.relationship_lines, fcolor, sh_cfg); } /* reverse order to have less stipple overlap */ float v[3]; mul_v3_m4v3(v, g_data.ob->obmat, end); - DRW_shgroup_call_dynamic_add(g_data.lines_ik_spline, v); + DRW_buffer_add_entry(g_data.lines_ik_spline, v); mul_v3_m4v3(v, g_data.ob->obmat, start); - DRW_shgroup_call_dynamic_add(g_data.lines_ik_spline, v); + DRW_buffer_add_entry(g_data.lines_ik_spline, v); } /** \} */ @@ -1634,12 +1641,10 @@ static void draw_bone_dofs(bPoseChannel *pchan) } if (g_data.bone_dof_sphere == NULL) { - g_data.bone_dof_lines = shgroup_instance_bone_dof(g_data.passes.bone_wire, - DRW_cache_bone_dof_lines_get()); - g_data.bone_dof_sphere = shgroup_instance_bone_dof(g_data.passes.bone_envelope, - DRW_cache_bone_dof_sphere_get()); - DRW_shgroup_state_enable(g_data.bone_dof_sphere, DRW_STATE_BLEND); - DRW_shgroup_state_disable(g_data.bone_dof_sphere, DRW_STATE_CULL_FRONT); + g_data.bone_dof_lines = buffer_instance_bone_dof( + g_data.passes.bone_wire, DRW_cache_bone_dof_lines_get(), false); + g_data.bone_dof_sphere = buffer_instance_bone_dof( + g_data.passes.bone_envelope, DRW_cache_bone_dof_sphere_get(), true); } /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ @@ -1672,20 +1677,20 @@ static void draw_bone_dofs(bPoseChannel *pchan) amax[0] = xminmax[1]; amin[1] = zminmax[0]; amax[1] = zminmax[1]; - DRW_shgroup_call_dynamic_add(g_data.bone_dof_sphere, final_bonemat, col_sphere, amin, amax); - DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_lines, amin, amax); + DRW_buffer_add_entry(g_data.bone_dof_sphere, final_bonemat, col_sphere, amin, amax); + DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_lines, amin, amax); } if (pchan->ikflag & BONE_IK_XLIMIT) { amin[0] = xminmax[0]; amax[0] = xminmax[1]; amin[1] = amax[1] = 0.0f; - DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_xaxis, amin, amax); + DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_xaxis, amin, amax); } if (pchan->ikflag & BONE_IK_ZLIMIT) { amin[1] = zminmax[0]; amax[1] = zminmax[1]; amin[0] = amax[0] = 0.0f; - DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_zaxis, amin, amax); + DRW_buffer_add_entry(g_data.bone_dof_lines, final_bonemat, col_zaxis, amin, amax); } } @@ -1839,7 +1844,9 @@ static void draw_armature_edit(Object *ob) const bool show_text = DRW_state_show_text(); const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0); - for (eBone = arm->edbo->first, index = ob->select_id; eBone; + const Object *orig_object = DEG_get_original_object(ob); + + for (eBone = arm->edbo->first, index = orig_object->runtime.select_id; eBone; eBone = eBone->next, index += 0x10000) { if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A) == 0) { @@ -1934,7 +1941,8 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) } if (arm->flag & ARM_POSEMODE) { - index = ob->select_id; + const Object *orig_object = DEG_get_original_object(ob); + index = orig_object->runtime.select_id; } } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 6b4c4cef9c8..c40e9772340 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -46,6 +46,9 @@ /* Batch's only (free'd as an array) */ static struct DRWShapeCache { + GPUBatch *drw_procedural_verts; + GPUBatch *drw_procedural_lines; + GPUBatch *drw_procedural_tris; GPUBatch *drw_single_vertice; GPUBatch *drw_cursor; GPUBatch *drw_cursor_only_circle; @@ -138,6 +141,54 @@ void DRW_shape_cache_reset(void) } /* -------------------------------------------------------------------- */ +/** \name Procedural Batches + * \{ */ + +GPUBatch *drw_cache_procedural_points_get(void) +{ + if (!SHC.drw_procedural_verts) { + /* TODO(fclem) get rid of this dummy VBO. */ + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, 1); + + SHC.drw_procedural_verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); + } + return SHC.drw_procedural_verts; +} + +GPUBatch *drw_cache_procedural_lines_get(void) +{ + if (!SHC.drw_procedural_lines) { + /* TODO(fclem) get rid of this dummy VBO. */ + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, 1); + + SHC.drw_procedural_lines = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO); + } + return SHC.drw_procedural_lines; +} + +GPUBatch *drw_cache_procedural_triangles_get(void) +{ + if (!SHC.drw_procedural_tris) { + /* TODO(fclem) get rid of this dummy VBO. */ + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, 1); + + SHC.drw_procedural_tris = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); + } + return SHC.drw_procedural_tris; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Helper functions * \{ */ @@ -3290,14 +3341,6 @@ GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(Object *ob) return DRW_mesh_batch_cache_get_edit_mesh_analysis(ob->data); } -void DRW_cache_mesh_sculpt_coords_ensure(Object *ob) -{ - BLI_assert(ob->type == OB_MESH); - - Mesh *me = ob->data; - DRW_mesh_cache_sculpt_coords_ensure(me); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -3961,68 +4004,32 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines) /** \name Batch Cache Impl. common * \{ */ -GPUBatch *DRW_batch_request(GPUBatch **batch) -{ - /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ - if (*batch == NULL) { - *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); - } - return *batch; -} - -bool DRW_batch_requested(GPUBatch *batch, int prim_type) +void drw_batch_cache_validate(Object *ob) { - /* Batch has been requested if it has been created but not initialized. */ - if (batch != NULL && batch->verts[0] == NULL) { - /* HACK. We init without a valid VBO and let the first vbo binding - * fill verts[0]. */ - GPU_batch_init_ex(batch, prim_type, (GPUVertBuf *)1, NULL, 0); - batch->verts[0] = NULL; - return true; - } - return false; -} - -void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo) -{ - if (*ibo == NULL) { - *ibo = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); - } - GPU_batch_vao_cache_clear(batch); - batch->elem = *ibo; -} - -bool DRW_ibo_requested(GPUIndexBuf *ibo) -{ - /* TODO do not rely on data uploaded. This prevents multithreading. - * (need access to a gl context) */ - return (ibo != NULL && ibo->ibo_id == 0 && ibo->data == NULL); -} - -void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) -{ - if (*vbo == NULL) { - *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); - } - /* HACK set first vbo if not init. */ - if (batch->verts[0] == NULL) { - GPU_batch_vao_cache_clear(batch); - batch->verts[0] = *vbo; - } - else { - /* HACK: bypass assert */ - int vbo_vert_len = (*vbo)->vertex_len; - (*vbo)->vertex_len = batch->verts[0]->vertex_len; - GPU_batch_vertbuf_add(batch, *vbo); - (*vbo)->vertex_len = vbo_vert_len; + struct Mesh *mesh_eval = ob->runtime.mesh_eval; + switch (ob->type) { + case OB_MESH: + DRW_mesh_batch_cache_validate((Mesh *)ob->data); + break; + case OB_CURVE: + case OB_FONT: + case OB_SURF: + if (mesh_eval != NULL) { + DRW_mesh_batch_cache_validate(mesh_eval); + } + DRW_curve_batch_cache_validate((Curve *)ob->data); + break; + case OB_MBALL: + DRW_mball_batch_cache_validate((MetaBall *)ob->data); + break; + case OB_LATTICE: + DRW_lattice_batch_cache_validate((Lattice *)ob->data); + break; + default: + break; } } -bool DRW_vbo_requested(GPUVertBuf *vbo) -{ - return (vbo != NULL && vbo->format.attr_len == 0); -} - void drw_batch_cache_generate_requested(Object *ob) { const DRWContextState *draw_ctx = DRW_context_state_get(); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 4ef8f5a9326..4dc58972ce6 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -44,15 +44,19 @@ struct bGPdata; /* Expose via BKE callbacks */ void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); +void DRW_mball_batch_cache_validate(struct MetaBall *mb); void DRW_mball_batch_cache_free(struct MetaBall *mb); void DRW_curve_batch_cache_dirty_tag(struct Curve *cu, int mode); +void DRW_curve_batch_cache_validate(struct Curve *cu); void DRW_curve_batch_cache_free(struct Curve *cu); void DRW_mesh_batch_cache_dirty_tag(struct Mesh *me, int mode); +void DRW_mesh_batch_cache_validate(struct Mesh *me); void DRW_mesh_batch_cache_free(struct Mesh *me); void DRW_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode); +void DRW_lattice_batch_cache_validate(struct Lattice *lt); void DRW_lattice_batch_cache_free(struct Lattice *lt); void DRW_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode); @@ -159,8 +163,6 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me); -void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me); - /* Edit mesh bitflags (is this the right place?) */ enum { VFLAG_VERT_ACTIVE = 1 << 0, @@ -204,30 +206,4 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *ob struct ParticleSystem *psys, struct PTCacheEdit *edit); -/* Common */ -// #define DRW_DEBUG_MESH_CACHE_REQUEST - -#ifdef DRW_DEBUG_MESH_CACHE_REQUEST -# define DRW_ADD_FLAG_FROM_VBO_REQUEST(flag, vbo, value) \ - (flag |= DRW_vbo_requested(vbo) ? (printf(" VBO requested " #vbo "\n") ? value : value) : 0) -# define DRW_ADD_FLAG_FROM_IBO_REQUEST(flag, ibo, value) \ - (flag |= DRW_ibo_requested(ibo) ? (printf(" IBO requested " #ibo "\n") ? value : value) : 0) -#else -# define DRW_ADD_FLAG_FROM_VBO_REQUEST(flag, vbo, value) \ - (flag |= DRW_vbo_requested(vbo) ? (value) : 0) -# define DRW_ADD_FLAG_FROM_IBO_REQUEST(flag, ibo, value) \ - (flag |= DRW_ibo_requested(ibo) ? (value) : 0) -#endif - -/* Test and assign NULL if test fails */ -#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL)) -#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL)) - -struct GPUBatch *DRW_batch_request(struct GPUBatch **batch); -bool DRW_batch_requested(struct GPUBatch *batch, int prim_type); -void DRW_ibo_request(struct GPUBatch *batch, struct GPUIndexBuf **ibo); -bool DRW_ibo_requested(struct GPUIndexBuf *ibo); -void DRW_vbo_request(struct GPUBatch *batch, struct GPUVertBuf **vbo); -bool DRW_vbo_requested(struct GPUVertBuf *vbo); - #endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 33b872109a5..663fbf647a6 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -42,6 +42,8 @@ #include "DRW_render.h" +#include "draw_cache_inline.h" + #include "draw_cache_impl.h" /* own include */ #define SELECT 1 @@ -472,12 +474,16 @@ static void curve_batch_cache_init(Curve *cu) cache->is_dirty = false; } -static CurveBatchCache *curve_batch_cache_get(Curve *cu) +void DRW_curve_batch_cache_validate(Curve *cu) { if (!curve_batch_cache_valid(cu)) { curve_batch_cache_clear(cu); curve_batch_cache_init(cu); } +} + +static CurveBatchCache *curve_batch_cache_get(Curve *cu) +{ return cu->batch_cache; } diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c index ea394359b05..d1c214c2aa6 100644 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -37,6 +37,8 @@ #include "GPU_batch.h" #include "GPU_extensions.h" +#include "draw_cache_inline.h" + #include "draw_cache_impl.h" /* own include */ static int dl_vert_len(const DispList *dl) @@ -402,7 +404,6 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb, &format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); attr_id.nor = GPU_vertformat_attr_add( &format_pos_nor, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_triple_load(&format_pos_nor); /* UVs are in [0..1] range. We can compress them. */ attr_id.uv = GPU_vertformat_attr_add( &format_uv, "u", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c index b5223bc047c..8b3864684b5 100644 --- a/source/blender/draw/intern/draw_cache_impl_lattice.c +++ b/source/blender/draw/intern/draw_cache_impl_lattice.c @@ -340,12 +340,16 @@ static void lattice_batch_cache_init(Lattice *lt) cache->is_dirty = false; } -static LatticeBatchCache *lattice_batch_cache_get(Lattice *lt) +void DRW_lattice_batch_cache_validate(Lattice *lt) { if (!lattice_batch_cache_valid(lt)) { lattice_batch_cache_clear(lt); lattice_batch_cache_init(lt); } +} + +static LatticeBatchCache *lattice_batch_cache_get(Lattice *lt) +{ return lt->batch_cache; } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 1d8c7f0e5a7..9fb9f9713d1 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -61,6 +61,8 @@ #include "ED_mesh.h" #include "ED_uvedit.h" +#include "draw_cache_inline.h" + #include "draw_cache_impl.h" /* own include */ static void mesh_batch_cache_clear(Mesh *me); @@ -421,13 +423,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata; /* See: DM_vertex_attributes_from_gpu for similar logic */ - GPUVertAttrLayers gpu_attrs = {{{0}}}; DRW_MeshCDMask cd_used; mesh_cd_layers_type_clear(&cd_used); for (int i = 0; i < gpumat_array_len; i++) { GPUMaterial *gpumat = gpumat_array[i]; if (gpumat) { + GPUVertAttrLayers gpu_attrs; GPU_material_vertex_attrs(gpumat, &gpu_attrs); for (int j = 0; j < gpu_attrs.totlayer; j++) { const char *name = gpu_attrs.layer[j].name; @@ -1140,11 +1142,12 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, rdata->cd.layers.tangent_len); int i_dst = 0; + int act_tan = rdata->cd.layers.tangent_active; for (int i_src = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) { if ((cd_used->tan & (1 << i_src)) == 0) { i_dst--; if (rdata->cd.layers.tangent_active >= i_src) { - rdata->cd.layers.tangent_active--; + act_tan--; } } else { @@ -1168,6 +1171,11 @@ static MeshRenderData *mesh_render_data_create_ex(Mesh *me, } } } + if (rdata->cd.layers.tangent_active != -1) { + /* Actual active UV slot inside uv layers used for shading. */ + rdata->cd.layers.tangent_active = act_tan; + } + if (cd_used->tan_orco != 0) { const char *name = CustomData_get_layer_name(&rdata->cd.output.ldata, CD_TANGENT, i_dst); uint hash = BLI_ghashutil_strhash_p(name); @@ -1892,6 +1900,39 @@ static void drw_mesh_weight_state_extract(Object *ob, /** \name Mesh GPUBatch Cache * \{ */ +typedef enum DRWBatchFlag { + MBC_SURFACE = (1 << 0), + MBC_SURFACE_WEIGHTS = (1 << 1), + MBC_EDIT_TRIANGLES = (1 << 2), + MBC_EDIT_VERTICES = (1 << 3), + MBC_EDIT_EDGES = (1 << 4), + MBC_EDIT_LNOR = (1 << 5), + MBC_EDIT_FACEDOTS = (1 << 6), + MBC_EDIT_MESH_ANALYSIS = (1 << 7), + MBC_EDITUV_FACES_STRECH_AREA = (1 << 8), + MBC_EDITUV_FACES_STRECH_ANGLE = (1 << 9), + MBC_EDITUV_FACES = (1 << 10), + MBC_EDITUV_EDGES = (1 << 11), + MBC_EDITUV_VERTS = (1 << 12), + MBC_EDITUV_FACEDOTS = (1 << 13), + MBC_EDIT_SELECTION_VERTS = (1 << 14), + MBC_EDIT_SELECTION_EDGES = (1 << 15), + MBC_EDIT_SELECTION_FACES = (1 << 16), + MBC_EDIT_SELECTION_FACEDOTS = (1 << 17), + MBC_ALL_VERTS = (1 << 18), + MBC_ALL_EDGES = (1 << 19), + MBC_LOOSE_EDGES = (1 << 20), + MBC_EDGE_DETECTION = (1 << 21), + MBC_WIRE_EDGES = (1 << 22), + MBC_WIRE_LOOPS = (1 << 23), + MBC_WIRE_LOOPS_UVS = (1 << 24), + MBC_SURF_PER_MAT = (1 << 25), +} DRWBatchFlag; + +#define MBC_EDITUV \ + (MBC_EDITUV_FACES_STRECH_AREA | MBC_EDITUV_FACES_STRECH_ANGLE | MBC_EDITUV_FACES | \ + MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS) + typedef struct MeshBatchCache { /* In order buffers: All verts only specified once * or once per loop. To be used with a GPUIndexBuf. */ @@ -1997,14 +2038,16 @@ typedef struct MeshBatchCache { int *auto_layer_is_srgb; int auto_layer_len; + DRWBatchFlag batch_requested; + DRWBatchFlag batch_ready; + /* settings to determine if cache is invalid */ - bool is_maybe_dirty; - bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ int edge_len; int tri_len; int poly_len; int vert_len; int mat_len; + bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ bool is_editmode; bool is_uvsyncsel; @@ -2014,13 +2057,15 @@ typedef struct MeshBatchCache { int lastmatch; - /* XXX, only keep for as long as sculpt mode uses shaded drawing. */ - bool is_sculpt_points_tag; - /* Valid only if edge_detection is up to date. */ bool is_manifold; } MeshBatchCache; +BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag new_flag) +{ + atomic_fetch_and_or_uint32((uint32_t *)(&cache->batch_requested), *(uint32_t *)&new_flag); +} + /* GPUBatch cache management. */ static bool mesh_batch_cache_valid(Mesh *me) @@ -2031,10 +2076,6 @@ static bool mesh_batch_cache_valid(Mesh *me) return false; } - if (cache->mat_len != mesh_render_mat_len_get(me)) { - return false; - } - if (cache->is_editmode != (me->edit_mesh != NULL)) { return false; } @@ -2043,20 +2084,8 @@ static bool mesh_batch_cache_valid(Mesh *me) return false; } - if (cache->is_maybe_dirty == false) { - return true; - } - else { - if (cache->is_editmode) { - return false; - } - else if ((cache->vert_len != mesh_render_verts_len_get(me)) || - (cache->edge_len != mesh_render_edges_len_get(me)) || - (cache->tri_len != mesh_render_looptri_len_get(me)) || - (cache->poly_len != mesh_render_polys_len_get(me)) || - (cache->mat_len != mesh_render_mat_len_get(me))) { - return false; - } + if (cache->mat_len != mesh_render_mat_len_get(me)) { + return false; } return true; @@ -2087,18 +2116,23 @@ static void mesh_batch_cache_init(Mesh *me) __func__); cache->surf_per_mat = MEM_callocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__); - cache->is_maybe_dirty = false; cache->is_dirty = false; + cache->batch_ready = 0; + cache->batch_requested = 0; drw_mesh_weight_state_clear(&cache->weight_state); } -static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +void DRW_mesh_batch_cache_validate(Mesh *me) { if (!mesh_batch_cache_valid(me)) { mesh_batch_cache_clear(me); mesh_batch_cache_init(me); } +} + +static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +{ return me->runtime.batch_cache; } @@ -2109,6 +2143,8 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights); GPU_VERTBUF_DISCARD_SAFE(cache->ordered.weights); + cache->batch_ready &= ~MBC_SURFACE_WEIGHTS; + drw_mesh_weight_state_clear(&cache->weight_state); } } @@ -2133,6 +2169,8 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) } MEM_SAFE_FREE(cache->surf_per_mat); + cache->batch_ready &= ~MBC_SURF_PER_MAT; + MEM_SAFE_FREE(cache->auto_layer_names); MEM_SAFE_FREE(cache->auto_layer_is_srgb); @@ -2158,6 +2196,8 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges); GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts); GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots); + + cache->batch_ready &= ~MBC_EDITUV; } void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) @@ -2167,9 +2207,6 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) return; } switch (mode) { - case BKE_MESH_BATCH_DIRTY_MAYBE_ALL: - cache->is_maybe_dirty = true; - break; case BKE_MESH_BATCH_DIRTY_SELECT: GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_data); GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_pos_nor_data); @@ -2177,7 +2214,11 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->batch.edit_vertices); GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges); GPU_BATCH_DISCARD_SAFE(cache->batch.edit_facedots); + GPU_BATCH_DISCARD_SAFE(cache->batch.edit_selection_facedots); GPU_BATCH_DISCARD_SAFE(cache->batch.edit_mesh_analysis); + cache->batch_ready &= ~(MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES | MBC_EDIT_EDGES | + MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS | + MBC_EDIT_MESH_ANALYSIS); /* Because visible UVs depends on edit mode selection, discard everything. */ mesh_batch_cache_discard_uvedit(cache); break; @@ -2192,6 +2233,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]); } } + cache->batch_ready &= ~(MBC_SURFACE | MBC_WIRE_LOOPS | MBC_SURF_PER_MAT); break; case BKE_MESH_BATCH_DIRTY_ALL: cache->is_dirty = true; @@ -2200,9 +2242,6 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) mesh_batch_cache_discard_shaded_tri(cache); mesh_batch_cache_discard_uvedit(cache); break; - case BKE_MESH_BATCH_DIRTY_SCULPT_COORDS: - cache->is_sculpt_points_tag = true; - break; case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL: mesh_batch_cache_discard_uvedit(cache); break; @@ -2215,6 +2254,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_edges); GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_verts); GPU_BATCH_DISCARD_SAFE(cache->batch.edituv_facedots); + cache->batch_ready &= ~MBC_EDITUV; break; default: BLI_assert(0); @@ -2249,6 +2289,8 @@ static void mesh_batch_cache_clear(Mesh *me) mesh_batch_cache_discard_uvedit(cache); + cache->batch_ready = 0; + drw_mesh_weight_state_clear(&cache->weight_state); } @@ -4227,36 +4269,42 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_ALL_VERTS); return DRW_batch_request(&cache->batch.all_verts); } GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_ALL_EDGES); return DRW_batch_request(&cache->batch.all_edges); } GPUBatch *DRW_mesh_batch_cache_get_surface(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SURFACE); return DRW_batch_request(&cache->batch.surface); } GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES); return DRW_batch_request(&cache->batch.loose_edges); } GPUBatch *DRW_mesh_batch_cache_get_surface_weights(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SURFACE_WEIGHTS); return DRW_batch_request(&cache->batch.surface_weights); } GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDGE_DETECTION); /* Even if is_manifold is not correct (not updated), * the default (not manifold) is just the worst case. */ if (r_is_manifold) { @@ -4268,12 +4316,14 @@ GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold) GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_WIRE_EDGES); return DRW_batch_request(&cache->batch.wire_edges); } GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_MESH_ANALYSIS); return DRW_batch_request(&cache->batch.edit_mesh_analysis); } @@ -4299,6 +4349,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, &cache->auto_layer_len); } + mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); + if (auto_layer_names) { *auto_layer_names = cache->auto_layer_names; *auto_layer_is_srgb = cache->auto_layer_is_srgb; @@ -4313,6 +4365,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me, GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_SURF_PER_MAT); texpaint_request_active_uv(cache, me); for (int i = 0; i < cache->mat_len; ++i) { DRW_batch_request(&cache->surf_per_mat[i]); @@ -4324,6 +4377,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_uv(cache, me); + mesh_batch_cache_add_request(cache, MBC_SURFACE); return DRW_batch_request(&cache->batch.surface); } @@ -4331,6 +4385,7 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_vcol(cache, me); + mesh_batch_cache_add_request(cache, MBC_SURFACE); return DRW_batch_request(&cache->batch.surface); } @@ -4343,30 +4398,35 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edit_triangles(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_TRIANGLES); return DRW_batch_request(&cache->batch.edit_triangles); } GPUBatch *DRW_mesh_batch_cache_get_edit_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_EDGES); return DRW_batch_request(&cache->batch.edit_edges); } GPUBatch *DRW_mesh_batch_cache_get_edit_vertices(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_VERTICES); return DRW_batch_request(&cache->batch.edit_vertices); } GPUBatch *DRW_mesh_batch_cache_get_edit_lnors(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_LNOR); return DRW_batch_request(&cache->batch.edit_lnor); } GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_FACEDOTS); return DRW_batch_request(&cache->batch.edit_facedots); } @@ -4379,24 +4439,28 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_facedots(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACES); return DRW_batch_request(&cache->batch.edit_selection_faces); } GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_FACEDOTS); return DRW_batch_request(&cache->batch.edit_selection_facedots); } GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_EDGES); return DRW_batch_request(&cache->batch.edit_selection_edges); } GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDIT_SELECTION_VERTS); return DRW_batch_request(&cache->batch.edit_selection_verts); } @@ -4409,36 +4473,42 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me) GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_area(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_AREA); return DRW_batch_request(&cache->batch.edituv_faces_strech_area); } GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_strech_angle(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRECH_ANGLE); return DRW_batch_request(&cache->batch.edituv_faces_strech_angle); } GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES); return DRW_batch_request(&cache->batch.edituv_faces); } GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES); return DRW_batch_request(&cache->batch.edituv_edges); } GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS); return DRW_batch_request(&cache->batch.edituv_verts); } GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS); return DRW_batch_request(&cache->batch.edituv_facedots); } @@ -4446,34 +4516,17 @@ GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); texpaint_request_active_uv(cache, me); + mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS); return DRW_batch_request(&cache->batch.wire_loops_uvs); } GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); + mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS); return DRW_batch_request(&cache->batch.wire_loops); } -/** - * Needed for when we draw with shaded data. - */ -void DRW_mesh_cache_sculpt_coords_ensure(Mesh *UNUSED(me)) -{ -#if 0 /* Unused for now */ - if (me->runtime.batch_cache) { - MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) { - /* XXX Force update of all the batches that contains the pos_with_normals buffer. - * TODO(fclem): Ideally, Gawain should provide a way to update a buffer without destroying it. */ - mesh_batch_cache_clear_selective(me, cache->pos_with_normals); - GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals); - } - cache->is_sculpt_points_tag = false; - } -#endif -} - /* Compute 3D & 2D areas and their sum. */ BLI_INLINE void edit_uv_preprocess_stretch_area(BMFace *efa, const int cd_loop_uv_offset, @@ -4688,14 +4741,18 @@ static void uvedit_fill_buffer_data(MeshRenderData *rdata, GPU_indexbuf_add_generic_vert(elb_face, vidx); GPU_indexbuf_add_primitive_restart(elb_face); } - if (elb_edge && e_origindex[l[i].e] != ORIGINDEX_NONE) { + if (elb_edge) { for (i = 0; i < mpoly->totloop; ++i) { - GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % mpoly->totloop); + if (e_origindex[l[i].e] != ORIGINDEX_NONE) { + GPU_indexbuf_add_line_verts(elb_edge, vidx + i, vidx + (i + 1) % mpoly->totloop); + } } } - if (elb_vert && v_origindex[l[i].v] != ORIGINDEX_NONE) { + if (elb_vert) { for (i = 0; i < mpoly->totloop; ++i) { - GPU_indexbuf_add_generic_vert(elb_vert, vidx + i); + if (v_origindex[l[i].v] != ORIGINDEX_NONE) { + GPU_indexbuf_add_generic_vert(elb_vert, vidx + i); + } } } } @@ -4850,82 +4907,113 @@ void DRW_mesh_batch_cache_create_requested( { MeshBatchCache *cache = mesh_batch_cache_get(me); - /* Check vertex weights. */ - if ((cache->batch.surface_weights != 0) && (ts != NULL)) { - struct DRW_MeshWeightState wstate; - BLI_assert(ob->type == OB_MESH); - drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate); - mesh_batch_cache_check_vertex_group(cache, &wstate); - drw_mesh_weight_state_copy(&cache->weight_state, &wstate); - drw_mesh_weight_state_clear(&wstate); + /* Early out */ + if (cache->batch_requested == 0) { +#ifdef DEBUG + goto check; +#endif + return; } - /* Optimization : Only create orco layer if mesh is deformed. */ - if (cache->cd_needed.orco != 0) { - CustomData *cd_vdata = (me->edit_mesh) ? &me->edit_mesh->bm->vdata : &me->vdata; - if (CustomData_get_layer(cd_vdata, CD_ORCO) != NULL && ob->modifiers.first != NULL) { - /* Orco layer is needed. */ - } - else if (cache->cd_needed.tan_orco == 0) { - /* Skip orco calculation if not needed by tangent generation. */ - cache->cd_needed.orco = 0; + DRWBatchFlag batch_requested = cache->batch_requested; + cache->batch_requested = 0; + + if (batch_requested & MBC_SURFACE_WEIGHTS) { + /* Check vertex weights. */ + if ((cache->batch.surface_weights != NULL) && (ts != NULL)) { + struct DRW_MeshWeightState wstate; + BLI_assert(ob->type == OB_MESH); + drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate); + mesh_batch_cache_check_vertex_group(cache, &wstate); + drw_mesh_weight_state_copy(&cache->weight_state, &wstate); + drw_mesh_weight_state_clear(&wstate); } } - /* Verify that all surface batches have needed attribute layers. */ - /* TODO(fclem): We could be a bit smarter here and only do it per material. */ - bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed); - if (cd_overlap == false) { - if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv || - (cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan || - cache->cd_used.tan_orco != cache->cd_needed.tan_orco) { - GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan); - } - if (cache->cd_used.orco != cache->cd_needed.orco) { - GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco); + if (batch_requested & (MBC_SURFACE | MBC_SURF_PER_MAT | MBC_WIRE_LOOPS_UVS)) { + /* Optimization : Only create orco layer if mesh is deformed. */ + if (cache->cd_needed.orco != 0) { + CustomData *cd_vdata = (me->edit_mesh) ? &me->edit_mesh->bm->vdata : &me->vdata; + if (CustomData_get_layer(cd_vdata, CD_ORCO) != NULL && ob->modifiers.first != NULL) { + /* Orco layer is needed. */ + } + else if (cache->cd_needed.tan_orco == 0) { + /* Skip orco calculation if not needed by tangent generation. + */ + cache->cd_needed.orco = 0; + } } - if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { - GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol); + + /* Verify that all surface batches have needed attribute layers. + */ + /* TODO(fclem): We could be a bit smarter here and only do it per + * material. */ + bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed); + if (cd_overlap == false) { + if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv || + (cache->cd_used.tan & cache->cd_needed.tan) != cache->cd_needed.tan || + cache->cd_used.tan_orco != cache->cd_needed.tan_orco) { + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_uv_tan); + } + if (cache->cd_used.orco != cache->cd_needed.orco) { + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_orco); + } + if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) { + GPU_VERTBUF_DISCARD_SAFE(cache->ordered.loop_vcol); + } + /* We can't discard batches at this point as they have been + * referenced for drawing. Just clear them in place. */ + for (int i = 0; i < cache->mat_len; ++i) { + GPU_BATCH_CLEAR_SAFE(cache->surf_per_mat[i]); + } + GPU_BATCH_CLEAR_SAFE(cache->batch.surface); + cache->batch_ready &= ~(MBC_SURFACE | MBC_SURF_PER_MAT); + + mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); } - /* We can't discard batches at this point as they have been - * referenced for drawing. Just clear them in place. */ - for (int i = 0; i < cache->mat_len; ++i) { - GPU_BATCH_CLEAR_SAFE(cache->surf_per_mat[i]); + mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); + mesh_cd_layers_type_clear(&cache->cd_needed); + } + + if (batch_requested & MBC_EDITUV) { + /* Discard UV batches if sync_selection changes */ + if (ts != NULL) { + const bool is_uvsyncsel = (ts->uv_flag & UV_SYNC_SELECTION); + if (cache->is_uvsyncsel != is_uvsyncsel) { + cache->is_uvsyncsel = is_uvsyncsel; + GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv); + GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv); + GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans); + GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips); + GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points); + /* We only clear the batches as they may already have been + * referenced. */ + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts); + GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_facedots); + cache->batch_ready &= ~MBC_EDITUV; + } } - GPU_BATCH_CLEAR_SAFE(cache->batch.surface); + } - mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed); + /* Second chance to early out */ + if ((batch_requested & ~cache->batch_ready) == 0) { +#ifdef DEBUG + goto check; +#endif + return; } - mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed); - mesh_cd_layers_type_clear(&cache->cd_needed); - /* Discard UV batches if sync_selection changes */ - if (ts != NULL) { - const bool is_uvsyncsel = (ts->uv_flag & UV_SYNC_SELECTION); - if (cache->is_uvsyncsel != is_uvsyncsel) { - cache->is_uvsyncsel = is_uvsyncsel; - GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv_data); - GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_angle); - GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_stretch_area); - GPU_VERTBUF_DISCARD_SAFE(cache->edit.loop_uv); - GPU_VERTBUF_DISCARD_SAFE(cache->edit.facedots_uv); - GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_tri_fans); - GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_line_strips); - GPU_INDEXBUF_DISCARD_SAFE(cache->ibo.edituv_loops_points); - /* We only clear the batches as they may already have been referenced. */ - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_area); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces_strech_angle); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_faces); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_edges); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_verts); - GPU_BATCH_CLEAR_SAFE(cache->batch.edituv_facedots); - } - } - - bool has_request = false; + cache->batch_ready |= batch_requested; + /* Init batches and request VBOs & IBOs */ if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) { - has_request = true; DRW_ibo_request(cache->batch.surface, &cache->ibo.loops_tris); DRW_vbo_request(cache->batch.surface, &cache->ordered.loop_pos_nor); /* For paint overlay. Active layer should have been queried. */ @@ -4937,43 +5025,35 @@ void DRW_mesh_batch_cache_create_requested( } } if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) { - has_request = true; DRW_vbo_request(cache->batch.all_verts, &cache->ordered.pos_nor); } if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.all_edges, &cache->ibo.edges_lines); DRW_vbo_request(cache->batch.all_edges, &cache->ordered.pos_nor); } if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.loose_edges, &cache->ibo.loose_edges_lines); DRW_vbo_request(cache->batch.loose_edges, &cache->ordered.pos_nor); } if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) { - has_request = true; DRW_ibo_request(cache->batch.edge_detection, &cache->ibo.edges_adj_lines); DRW_vbo_request(cache->batch.edge_detection, &cache->ordered.pos_nor); } if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) { - has_request = true; DRW_ibo_request(cache->batch.surface_weights, &cache->ibo.surf_tris); DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.pos_nor); DRW_vbo_request(cache->batch.surface_weights, &cache->ordered.weights); } if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINE_STRIP)) { - has_request = true; DRW_ibo_request(cache->batch.wire_loops, &cache->ibo.loops_line_strips); DRW_vbo_request(cache->batch.wire_loops, &cache->ordered.loop_pos_nor); } if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.wire_edges, &cache->ibo.loops_lines); DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_pos_nor); DRW_vbo_request(cache->batch.wire_edges, &cache->ordered.loop_edge_fac); } if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINE_STRIP)) { - has_request = true; DRW_ibo_request(cache->batch.wire_loops_uvs, &cache->ibo.loops_line_strips); /* For paint overlay. Active layer should have been queried. */ if (cache->cd_used.uv != 0) { @@ -4983,37 +5063,31 @@ void DRW_mesh_batch_cache_create_requested( /* Edit Mesh */ if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_triangles, &cache->ibo.edit_loops_tris); DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_triangles, &cache->edit.loop_data); } if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_vertices, &cache->ibo.edit_loops_points); DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_vertices, &cache->edit.loop_data); } if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_loops_lines); DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_edges, &cache->edit.loop_data); } if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_lnor, &cache->ibo.edit_loops_tris); DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_lnor, &cache->edit.loop_lnor); } if (DRW_batch_requested(cache->batch.edit_facedots, GPU_PRIM_POINTS)) { - has_request = true; DRW_vbo_request(cache->batch.edit_facedots, &cache->edit.facedots_pos_nor_data); } /* Mesh Analysis */ if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_mesh_analysis, &cache->ibo.edit_loops_tris); DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_mesh_analysis, &cache->edit.loop_mesh_analysis); @@ -5021,39 +5095,33 @@ void DRW_mesh_batch_cache_create_requested( /* Edit UV */ if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRI_FAN)) { - has_request = true; DRW_ibo_request(cache->batch.edituv_faces, &cache->ibo.edituv_loops_tri_fans); DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv); DRW_vbo_request(cache->batch.edituv_faces, &cache->edit.loop_uv_data); } if (DRW_batch_requested(cache->batch.edituv_faces_strech_area, GPU_PRIM_TRI_FAN)) { - has_request = true; DRW_ibo_request(cache->batch.edituv_faces_strech_area, &cache->ibo.edituv_loops_tri_fans); DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv); DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_uv_data); DRW_vbo_request(cache->batch.edituv_faces_strech_area, &cache->edit.loop_stretch_area); } if (DRW_batch_requested(cache->batch.edituv_faces_strech_angle, GPU_PRIM_TRI_FAN)) { - has_request = true; DRW_ibo_request(cache->batch.edituv_faces_strech_angle, &cache->ibo.edituv_loops_tri_fans); DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv); DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_uv_data); DRW_vbo_request(cache->batch.edituv_faces_strech_angle, &cache->edit.loop_stretch_angle); } if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.edituv_edges, &cache->ibo.edituv_loops_line_strips); DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv); DRW_vbo_request(cache->batch.edituv_edges, &cache->edit.loop_uv_data); } if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) { - has_request = true; DRW_ibo_request(cache->batch.edituv_verts, &cache->ibo.edituv_loops_points); DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv); DRW_vbo_request(cache->batch.edituv_verts, &cache->edit.loop_uv_data); } if (DRW_batch_requested(cache->batch.edituv_facedots, GPU_PRIM_POINTS)) { - has_request = true; DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv); DRW_vbo_request(cache->batch.edituv_facedots, &cache->edit.facedots_uv_data); } @@ -5061,25 +5129,21 @@ void DRW_mesh_batch_cache_create_requested( /* Selection */ /* TODO reuse ordered.loop_pos_nor if possible. */ if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_selection_verts, &cache->ibo.edit_loops_points); DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_selection_verts, &cache->edit.loop_vert_idx); } if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) { - has_request = true; DRW_ibo_request(cache->batch.edit_selection_edges, &cache->ibo.edit_loops_lines); DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_selection_edges, &cache->edit.loop_edge_idx); } if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) { - has_request = true; DRW_ibo_request(cache->batch.edit_selection_faces, &cache->ibo.edit_loops_tris); DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_pos_nor); DRW_vbo_request(cache->batch.edit_selection_faces, &cache->edit.loop_face_idx); } if (DRW_batch_requested(cache->batch.edit_selection_facedots, GPU_PRIM_POINTS)) { - has_request = true; DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_pos_nor_data); DRW_vbo_request(cache->batch.edit_selection_facedots, &cache->edit.facedots_idx); } @@ -5087,7 +5151,6 @@ void DRW_mesh_batch_cache_create_requested( /* Per Material */ for (int i = 0; i < cache->mat_len; ++i) { if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) { - has_request = true; if (cache->mat_len > 1) { DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]); } @@ -5108,11 +5171,6 @@ void DRW_mesh_batch_cache_create_requested( } } - /* Early out if no request. */ - if (!has_request) { - return; - } - #ifdef DRW_DEBUG_MESH_CACHE_REQUEST printf("-- %s %s --\n", __func__, ob->id.name + 2); #endif @@ -5344,6 +5402,7 @@ void DRW_mesh_batch_cache_create_requested( } #ifdef DEBUG +check: /* Make sure all requested batches have been setup. */ for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) { BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0)); diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index 432c5092274..60f15338412 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -98,12 +98,16 @@ static void metaball_batch_cache_init(MetaBall *mb) cache->is_manifold = false; } -static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb) +void DRW_mball_batch_cache_validate(MetaBall *mb) { if (!metaball_batch_cache_valid(mb)) { metaball_batch_cache_clear(mb); metaball_batch_cache_init(mb); } +} + +static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb) +{ return mb->batch_cache; } diff --git a/source/blender/draw/intern/draw_cache_inline.h b/source/blender/draw/intern/draw_cache_inline.h new file mode 100644 index 00000000000..d94ef5b90d3 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_inline.h @@ -0,0 +1,110 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2016, Blender Foundation. + */ + +/** \file + * \ingroup draw + */ + +#ifndef __DRAW_CACHE_INLINE_H__ +#define __DRAW_CACHE_INLINE_H__ + +#include "MEM_guardedalloc.h" +#include "GPU_batch.h" + +/* Common */ +// #define DRW_DEBUG_MESH_CACHE_REQUEST + +#ifdef DRW_DEBUG_MESH_CACHE_REQUEST +# define DRW_ADD_FLAG_FROM_VBO_REQUEST(flag, vbo, value) \ + (flag |= DRW_vbo_requested(vbo) ? (printf(" VBO requested " #vbo "\n") ? value : value) : 0) +# define DRW_ADD_FLAG_FROM_IBO_REQUEST(flag, ibo, value) \ + (flag |= DRW_ibo_requested(ibo) ? (printf(" IBO requested " #ibo "\n") ? value : value) : 0) +#else +# define DRW_ADD_FLAG_FROM_VBO_REQUEST(flag, vbo, value) \ + (flag |= DRW_vbo_requested(vbo) ? (value) : 0) +# define DRW_ADD_FLAG_FROM_IBO_REQUEST(flag, ibo, value) \ + (flag |= DRW_ibo_requested(ibo) ? (value) : 0) +#endif + +/* Test and assign NULL if test fails */ +#define DRW_TEST_ASSIGN_VBO(v) (v = (DRW_vbo_requested(v) ? (v) : NULL)) +#define DRW_TEST_ASSIGN_IBO(v) (v = (DRW_ibo_requested(v) ? (v) : NULL)) + +BLI_INLINE GPUBatch *DRW_batch_request(GPUBatch **batch) +{ + /* XXX TODO(fclem): We are writting to batch cache here. Need to make this thread safe. */ + if (*batch == NULL) { + *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); + } + return *batch; +} + +BLI_INLINE bool DRW_batch_requested(GPUBatch *batch, int prim_type) +{ + /* Batch has been requested if it has been created but not initialized. */ + if (batch != NULL && batch->verts[0] == NULL) { + /* HACK. We init without a valid VBO and let the first vbo binding + * fill verts[0]. */ + GPU_batch_init_ex(batch, prim_type, (GPUVertBuf *)1, NULL, 0); + batch->verts[0] = NULL; + return true; + } + return false; +} + +BLI_INLINE void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo) +{ + if (*ibo == NULL) { + *ibo = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); + } + GPU_batch_vao_cache_clear(batch); + batch->elem = *ibo; +} + +BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo) +{ + /* TODO do not rely on data uploaded. This prevents multithreading. + * (need access to a gl context) */ + return (ibo != NULL && ibo->ibo_id == 0 && ibo->data == NULL); +} + +BLI_INLINE void DRW_vbo_request(GPUBatch *batch, GPUVertBuf **vbo) +{ + if (*vbo == NULL) { + *vbo = MEM_callocN(sizeof(GPUVertBuf), "GPUVertBuf"); + } + /* HACK set first vbo if not init. */ + if (batch->verts[0] == NULL) { + GPU_batch_vao_cache_clear(batch); + batch->verts[0] = *vbo; + } + else { + /* HACK: bypass assert */ + int vbo_vert_len = (*vbo)->vertex_len; + (*vbo)->vertex_len = batch->verts[0]->vertex_len; + GPU_batch_vertbuf_add(batch, *vbo); + (*vbo)->vertex_len = vbo_vert_len; + } +} + +BLI_INLINE bool DRW_vbo_requested(GPUVertBuf *vbo) +{ + return (vbo != NULL && vbo->format.attr_len == 0); +} + +#endif /* __DRAW_CACHE_INLINE_H__ */ diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index b4eb354ec59..378324b4871 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -233,6 +233,7 @@ extern char datatoc_armature_stick_frag_glsl[]; extern char datatoc_armature_dof_vert_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; @@ -284,7 +285,8 @@ static struct { struct GPUVertFormat *instance_bone_envelope_distance; struct GPUVertFormat *instance_bone_envelope_outline; struct GPUVertFormat *instance_mball_handles; - struct GPUVertFormat *dynlines_color; + struct GPUVertFormat *pos_color; + struct GPUVertFormat *pos; } g_formats = {NULL}; void DRW_globals_free(void) @@ -309,34 +311,36 @@ void DRW_shgroup_world_clip_planes_from_rv3d(DRWShadingGroup *shgrp, const Regio DRW_shgroup_state_enable(shgrp, DRW_STATE_CLIP_PLANES); } -DRWShadingGroup *shgroup_dynlines_flat_color(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_dynlines_flat_color(DRWPass *pass, eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_FLAT_COLOR, sh_cfg); - DRW_shgroup_instance_format(g_formats.dynlines_color, + DRW_shgroup_instance_format(g_formats.pos_color, { {"pos", DRW_ATTR_FLOAT, 3}, {"color", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_line_batch_create_with_format( - sh, pass, g_formats.dynlines_color); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer(grp, g_formats.pos_color, GPU_PRIM_LINES); } -DRWShadingGroup *shgroup_dynlines_dashed_uniform_color(DRWPass *pass, - const float color[4], - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_dynlines_dashed_uniform_color(DRWPass *pass, + const float color[4], + eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config( GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR, sh_cfg); static float dash_width = 6.0f; static float dash_factor = 0.5f; - DRWShadingGroup *grp = DRW_shgroup_line_batch_create(sh, pass); + + DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}}); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", color, 1); DRW_shgroup_uniform_vec2(grp, "viewport_size", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float(grp, "dash_width", &dash_width, 1); @@ -345,60 +349,52 @@ DRWShadingGroup *shgroup_dynlines_dashed_uniform_color(DRWPass *pass, if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_LINES); } -DRWShadingGroup *shgroup_dynpoints_uniform_color(DRWPass *pass, - const float color[4], - const float *size, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_dynpoints_uniform_color(DRWShadingGroup *grp) { - GPUShader *sh = GPU_shader_get_builtin_shader_with_config( - GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, sh_cfg); + DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}}); - DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass); - DRW_shgroup_uniform_vec4(grp, "color", color, 1); - DRW_shgroup_uniform_float(grp, "size", size, 1); - DRW_shgroup_state_enable(grp, DRW_STATE_POINT); - if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); - } - return grp; + return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS); } -DRWShadingGroup *shgroup_groundlines_uniform_color(DRWPass *pass, - const float color[4], - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_groundlines_uniform_color(DRWPass *pass, + const float color[4], + eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_GROUNDLINE, sh_cfg); - DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass); + DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}}); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", color, 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS); } -DRWShadingGroup *shgroup_groundpoints_uniform_color(DRWPass *pass, - const float color[4], - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_groundpoints_uniform_color(DRWPass *pass, + const float color[4], + eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_GROUNDPOINT, sh_cfg); - DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass); + DRW_shgroup_instance_format(g_formats.pos, {{"pos", DRW_ATTR_FLOAT, 3}}); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", color, 1); - DRW_shgroup_state_enable(grp, DRW_STATE_POINT); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer(grp, g_formats.pos, GPU_PRIM_POINTS); } -DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, - struct GPUBatch *geom, - const float *size, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_screenspace(DRWPass *pass, + struct GPUBatch *geom, + const float *size, + eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config( GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR, sh_cfg); @@ -409,18 +405,17 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, {"color", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh, pass, geom, g_formats.instance_screenspace); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_float(grp, "size", size, 1); DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_screenspace, geom); } -DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct GPUBatch *geom) +struct DRWCallBuffer *buffer_instance_solid(DRWPass *pass, struct GPUBatch *geom) { static float light[3] = {0.0f, 0.0f, 1.0f}; GPUShader *sh = GPU_shader_get_builtin_shader( @@ -432,13 +427,13 @@ DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct GPUBatch *geom) {"color", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec3(grp, "light", light, 1); - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_color, geom); } -DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct GPUBatch *geom) +struct DRWCallBuffer *buffer_instance_wire(DRWPass *pass, struct GPUBatch *geom) { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR); @@ -448,14 +443,14 @@ DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct GPUBatch *geom) {"color", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_color, geom); } -DRWShadingGroup *shgroup_instance_screen_aligned(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_screen_aligned(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED, sh_cfg); @@ -467,18 +462,17 @@ DRWShadingGroup *shgroup_instance_screen_aligned(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh, pass, geom, g_formats.instance_screen_aligned); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_screen_aligned, geom); } -DRWShadingGroup *shgroup_instance_scaled(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_scaled(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config( GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, sh_cfg); @@ -490,15 +484,16 @@ DRWShadingGroup *shgroup_instance_scaled(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_scaled); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_scaled, geom); } -DRWShadingGroup *shgroup_instance(DRWPass *pass, struct GPUBatch *geom, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config( GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, sh_cfg); @@ -510,22 +505,16 @@ DRWShadingGroup *shgroup_instance(DRWPass *pass, struct GPUBatch *geom, eGPUShad {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_sized); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); DRW_shgroup_state_disable(grp, DRW_STATE_BLEND); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom); } -DRWShadingGroup *shgroup_instance_alpha(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_alpha(DRWShadingGroup *grp, struct GPUBatch *geom) { - GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config( - GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, sh_cfg); - DRW_shgroup_instance_format(g_formats.instance_sized, { {"color", DRW_ATTR_FLOAT, 4}, @@ -533,17 +522,12 @@ DRWShadingGroup *shgroup_instance_alpha(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_sized); - if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); - } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom); } -DRWShadingGroup *shgroup_instance_empty_axes(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_empty_axes(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->empty_axes_sh == NULL) { @@ -562,16 +546,15 @@ DRWShadingGroup *shgroup_instance_empty_axes(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->empty_axes_sh, pass, geom, g_formats.instance_sized); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->empty_axes_sh, pass); DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_sized, geom); } -DRWShadingGroup *shgroup_instance_outline(DRWPass *pass, struct GPUBatch *geom, int *baseid) +struct DRWCallBuffer *buffer_instance_outline(DRWPass *pass, struct GPUBatch *geom, int *baseid) { GPUShader *sh_inst = GPU_shader_get_builtin_shader( GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE); @@ -583,16 +566,15 @@ DRWShadingGroup *shgroup_instance_outline(DRWPass *pass, struct GPUBatch *geom, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_outline); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); DRW_shgroup_uniform_int(grp, "baseId", baseid, 1); - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_outline, geom); } -DRWShadingGroup *shgroup_camera_instance(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_camera_instance(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_CAMERA, sh_cfg); @@ -605,17 +587,16 @@ DRWShadingGroup *shgroup_camera_instance(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_camera); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_camera, geom); } -DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_distance_lines_instance(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_DISTANCE_LINES, sh_cfg); @@ -629,18 +610,17 @@ DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_inst, pass, geom, g_formats.instance_distance_lines); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); DRW_shgroup_uniform_float(grp, "size", &point_size, 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_distance_lines, geom); } -DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_spot_instance(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { GPUShader *sh_inst = GPU_shader_get_builtin_shader_with_config( GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, sh_cfg); @@ -653,17 +633,17 @@ DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, {"InstanceModelMatrix", DRW_ATTR_FLOAT, 16}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_spot); + DRWShadingGroup *grp = DRW_shgroup_create(sh_inst, pass); DRW_shgroup_uniform_bool(grp, "drawFront", &False, 1); DRW_shgroup_uniform_bool(grp, "drawBack", &False, 1); DRW_shgroup_uniform_bool(grp, "drawSilhouette", &True, 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_spot, geom); } -DRWShadingGroup *shgroup_instance_bone_axes(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_axes(DRWPass *pass, eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_axes == NULL) { @@ -681,16 +661,16 @@ DRWShadingGroup *shgroup_instance_bone_axes(DRWPass *pass, eGPUShaderConfig sh_c {"color", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->bone_axes, pass, DRW_cache_bone_arrows_get(), g_formats.instance_color); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_axes, pass); DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_color, DRW_cache_bone_arrows_get()); } -DRWShadingGroup *shgroup_instance_bone_envelope_outline(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_envelope_outline(DRWPass *pass, eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_envelope_outline == NULL) { @@ -711,18 +691,17 @@ DRWShadingGroup *shgroup_instance_bone_envelope_outline(DRWPass *pass, eGPUShade {"xAxis", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_data->bone_envelope_outline, - pass, - DRW_cache_bone_envelope_outline_get(), - g_formats.instance_bone_envelope_outline); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope_outline, pass); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone_envelope_outline, DRW_cache_bone_envelope_outline_get()); } -DRWShadingGroup *shgroup_instance_bone_envelope_distance(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_envelope_distance(DRWPass *pass, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_envelope_distance == NULL) { @@ -742,19 +721,17 @@ DRWShadingGroup *shgroup_instance_bone_envelope_distance(DRWPass *pass, eGPUShad {"xAxis", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_data->bone_envelope_distance, - pass, - DRW_cache_bone_envelope_solid_get(), - g_formats.instance_bone_envelope_distance); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope_distance, pass); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone_envelope_distance, DRW_cache_bone_envelope_solid_get()); } -DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, - bool transp, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_envelope_solid(DRWPass *pass, + bool transp, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_envelope == NULL) { @@ -776,18 +753,19 @@ DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, {"xAxis", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_data->bone_envelope, - pass, - DRW_cache_bone_envelope_solid_get(), - g_formats.instance_bone_envelope); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_envelope, pass); + /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to + * inverted matrix. */ + DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK); DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone_envelope, DRW_cache_bone_envelope_solid_get()); } -DRWShadingGroup *shgroup_instance_mball_handles(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_mball_handles(DRWPass *pass, eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->mball_handles == NULL) { @@ -806,28 +784,32 @@ DRWShadingGroup *shgroup_instance_mball_handles(DRWPass *pass, eGPUShaderConfig {"color", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_data->mball_handles, - pass, - DRW_cache_screenspace_circle_get(), - g_formats.instance_mball_handles); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->mball_handles, pass); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_mball_handles, DRW_cache_screenspace_circle_get()); } /* Only works with batches with adjacency infos. */ -DRWShadingGroup *shgroup_instance_bone_shape_outline(DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_shape_outline(DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->shape_outline == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; sh_data->shape_outline = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_armature_shape_outline_vert_glsl, NULL}, - .geom = (const char *[]){sh_cfg_data->lib, datatoc_armature_shape_outline_geom_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_armature_shape_outline_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_armature_shape_outline_geom_glsl, + NULL}, .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -839,25 +821,27 @@ DRWShadingGroup *shgroup_instance_bone_shape_outline(DRWPass *pass, {"outlineColorSize", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->shape_outline, pass, geom, g_formats.instance_bone_outline); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->shape_outline, pass); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone_outline, geom); } -DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, - struct GPUBatch *geom, - bool transp, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_shape_solid(DRWPass *pass, + struct GPUBatch *geom, + bool transp, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->shape_solid == NULL) { const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; sh_data->shape_solid = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_armature_shape_solid_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_armature_shape_solid_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_armature_shape_solid_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -870,18 +854,17 @@ DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, {"stateColor", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->shape_solid, pass, geom, g_formats.instance_bone); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->shape_solid, pass); DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone, geom); } -DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass, - bool transp, - eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_sphere_solid(DRWPass *pass, + bool transp, + eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_sphere == NULL) { @@ -900,17 +883,17 @@ DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass, {"stateColor", DRW_ATTR_FLOAT, 3}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->bone_sphere, pass, DRW_cache_bone_point_get(), g_formats.instance_bone); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_sphere, pass); /* More transparent than the shape to be less distractive. */ DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.4f : 1.0f); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone, DRW_cache_bone_point_get()); } -DRWShadingGroup *shgroup_instance_bone_sphere_outline(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_sphere_outline(DRWPass *pass, eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_sphere_outline == NULL) { @@ -929,18 +912,16 @@ DRWShadingGroup *shgroup_instance_bone_sphere_outline(DRWPass *pass, eGPUShaderC {"outlineColorSize", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_data->bone_sphere_outline, - pass, - DRW_cache_bone_point_wire_outline_get(), - g_formats.instance_bone_outline); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_sphere_outline, pass); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone_outline, DRW_cache_bone_point_wire_outline_get()); } -DRWShadingGroup *shgroup_instance_bone_stick(DRWPass *pass, eGPUShaderConfig sh_cfg) +struct DRWCallBuffer *buffer_instance_bone_stick(DRWPass *pass, eGPUShaderConfig sh_cfg) { COMMON_Shaders *sh_data = &g_shaders[sh_cfg]; if (sh_data->bone_stick == NULL) { @@ -963,17 +944,19 @@ DRWShadingGroup *shgroup_instance_bone_stick(DRWPass *pass, eGPUShaderConfig sh_ {"tailColor", DRW_ATTR_FLOAT, 4}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->bone_stick, pass, DRW_cache_bone_stick_get(), g_formats.instance_bone_stick); + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_stick, pass); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float_copy(grp, "stickSize", 5.0f * U.pixelsize); if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - return grp; + return DRW_shgroup_call_buffer_instance( + grp, g_formats.instance_bone_stick, DRW_cache_bone_stick_get()); } -struct DRWShadingGroup *shgroup_instance_bone_dof(struct DRWPass *pass, struct GPUBatch *geom) +struct DRWCallBuffer *buffer_instance_bone_dof(struct DRWPass *pass, + struct GPUBatch *geom, + bool blend) { COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT]; if (sh_data->bone_dofs == NULL) { @@ -989,10 +972,12 @@ struct DRWShadingGroup *shgroup_instance_bone_dof(struct DRWPass *pass, struct G {"amax", DRW_ATTR_FLOAT, 2}, }); - DRWShadingGroup *grp = DRW_shgroup_instance_create( - sh_data->bone_dofs, pass, geom, g_formats.instance_bone_dof); - - return grp; + DRWShadingGroup *grp = DRW_shgroup_create(sh_data->bone_dofs, pass); + if (blend) { + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND); + DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT); + } + return DRW_shgroup_call_buffer_instance(grp, g_formats.instance_bone_dof, geom); } struct GPUShader *mpath_line_shader_get(void) @@ -1028,18 +1013,23 @@ struct GPUShader *volume_velocity_shader_get(bool use_needle) COMMON_Shaders *sh_data = &g_shaders[GPU_SHADER_CFG_DEFAULT]; if (use_needle) { if (sh_data->volume_velocity_needle_sh == NULL) { - sh_data->volume_velocity_needle_sh = DRW_shader_create( + sh_data->volume_velocity_needle_sh = DRW_shader_create_with_lib( datatoc_volume_velocity_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_common_view_lib_glsl, "#define USE_NEEDLE"); } return sh_data->volume_velocity_needle_sh; } else { if (sh_data->volume_velocity_sh == NULL) { - sh_data->volume_velocity_sh = DRW_shader_create( - datatoc_volume_velocity_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL); + sh_data->volume_velocity_sh = DRW_shader_create_with_lib( + datatoc_volume_velocity_vert_glsl, + NULL, + datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } return sh_data->volume_velocity_sh; } @@ -1075,22 +1065,27 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color theme_id = (active) ? TH_ACTIVE : TH_SELECT; } else { - if (ob->type == OB_LAMP) { - theme_id = TH_LIGHT; - } - else if (ob->type == OB_SPEAKER) { - theme_id = TH_SPEAKER; - } - else if (ob->type == OB_CAMERA) { - theme_id = TH_CAMERA; - } - else if (ob->type == OB_EMPTY) { - theme_id = TH_EMPTY; + switch (ob->type) { + case OB_LAMP: + theme_id = TH_LIGHT; + break; + case OB_SPEAKER: + theme_id = TH_SPEAKER; + break; + case OB_CAMERA: + theme_id = TH_CAMERA; + break; + case OB_EMPTY: + theme_id = TH_EMPTY; + break; + case OB_LIGHTPROBE: + /* TODO add lightprobe color */ + theme_id = TH_EMPTY; + break; + default: + /* fallback to TH_WIRE */ + break; } - else if (ob->type == OB_LIGHTPROBE) { - theme_id = TH_EMPTY; - } /* TODO add lightprobe color */ - /* fallback to TH_WIRE */ } } @@ -1217,7 +1212,7 @@ bool DRW_object_is_flat(Object *ob, int *axis) bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis) { float ob_rot[3][3], invviewmat[4][4]; - DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV); + DRW_view_viewmat_get(NULL, invviewmat, true); BKE_object_rot_to_mat3(ob, ob_rot, true); float dot = dot_v3v3(ob_rot[axis], invviewmat[2]); if (fabsf(dot) < 1e-3) { diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 489bc7459df..df7220c0d2a 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -23,6 +23,7 @@ #ifndef __DRAW_COMMON_H__ #define __DRAW_COMMON_H__ +struct DRWCallBuffer; struct DRWPass; struct DRWShadingGroup; struct GPUBatch; @@ -125,77 +126,74 @@ void DRW_globals_free(void); void DRW_shgroup_world_clip_planes_from_rv3d(struct DRWShadingGroup *shgrp, const RegionView3D *rv3d); -struct DRWShadingGroup *shgroup_dynlines_flat_color(struct DRWPass *pass, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_dynlines_dashed_uniform_color(struct DRWPass *pass, - const float color[4], - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_dynpoints_uniform_color(struct DRWPass *pass, - const float color[4], - const float *size, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_groundlines_uniform_color(struct DRWPass *pass, - const float color[4], - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_groundpoints_uniform_color(struct DRWPass *pass, +/* TODO(fclem) ideally, most of the DRWCallBuffer functions shouldn't create a shgroup. */ +struct DRWCallBuffer *buffer_dynlines_flat_color(struct DRWPass *pass, eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_dynlines_dashed_uniform_color(struct DRWPass *pass, const float color[4], eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_screenspace(struct DRWPass *pass, +struct DRWCallBuffer *buffer_dynpoints_uniform_color(struct DRWShadingGroup *grp); +struct DRWCallBuffer *buffer_groundlines_uniform_color(struct DRWPass *pass, + const float color[4], + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_groundpoints_uniform_color(struct DRWPass *pass, + const float color[4], + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_screenspace(struct DRWPass *pass, + struct GPUBatch *geom, + const float *size, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_solid(struct DRWPass *pass, struct GPUBatch *geom); +struct DRWCallBuffer *buffer_instance_wire(struct DRWPass *pass, struct GPUBatch *geom); +struct DRWCallBuffer *buffer_instance_screen_aligned(struct DRWPass *pass, struct GPUBatch *geom, - const float *size, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_solid(struct DRWPass *pass, struct GPUBatch *geom); -struct DRWShadingGroup *shgroup_instance_wire(struct DRWPass *pass, struct GPUBatch *geom); -struct DRWShadingGroup *shgroup_instance_screen_aligned(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_empty_axes(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_scaled(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_alpha(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_outline(struct DRWPass *pass, +struct DRWCallBuffer *buffer_instance_empty_axes(struct DRWPass *pass, struct GPUBatch *geom, - int *baseid); -struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, - struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_scaled(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_alpha(struct DRWShadingGroup *grp, struct GPUBatch *geom); +struct DRWCallBuffer *buffer_instance_outline(struct DRWPass *pass, struct GPUBatch *geom, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_axes(struct DRWPass *pass, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_envelope_distance(struct DRWPass *pass, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_envelope_outline(struct DRWPass *pass, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, - bool transp, + int *baseid); +struct DRWCallBuffer *buffer_camera_instance(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_distance_lines_instance(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_spot_instance(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_mball_handles(struct DRWPass *pass, eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_axes(struct DRWPass *pass, eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_envelope_distance(struct DRWPass *pass, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_shape_outline(struct DRWPass *pass, - struct GPUBatch *geom, +struct DRWCallBuffer *buffer_instance_bone_envelope_outline(struct DRWPass *pass, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_shape_solid(struct DRWPass *pass, - struct GPUBatch *geom, +struct DRWCallBuffer *buffer_instance_bone_envelope_solid(struct DRWPass *pass, bool transp, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_sphere_outline(struct DRWPass *pass, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_sphere_solid(struct DRWPass *pass, - bool transp, - eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_stick(struct DRWPass *pass, eGPUShaderConfig sh_cfg); -struct DRWShadingGroup *shgroup_instance_bone_dof(struct DRWPass *pass, struct GPUBatch *geom); +struct DRWCallBuffer *buffer_instance_bone_shape_outline(struct DRWPass *pass, + struct GPUBatch *geom, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_shape_solid(struct DRWPass *pass, + struct GPUBatch *geom, + bool transp, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_sphere_outline(struct DRWPass *pass, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_sphere_solid(struct DRWPass *pass, + bool transp, + eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_stick(struct DRWPass *pass, eGPUShaderConfig sh_cfg); +struct DRWCallBuffer *buffer_instance_bone_dof(struct DRWPass *pass, + struct GPUBatch *geom, + bool blend); struct GPUShader *mpath_line_shader_get(void); struct GPUShader *mpath_points_shader_get(void); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index cb83265195a..50819f6a522 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -98,9 +98,9 @@ static GPUShader *hair_refine_shader_get(ParticleRefineShader sh) void DRW_hair_init(void) { #ifdef USE_TRANSFORM_FEEDBACK - g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_TRANS_FEEDBACK); + g_tf_pass = DRW_pass_create("Update Hair Pass", 0); #else - g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_POINT); + g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR); #endif } @@ -195,7 +195,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, shgrp, "hairCloseTip", (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0); /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass culling * test. */ - DRW_shgroup_call_object_add_no_cull( + DRW_shgroup_call_object_no_cull( shgrp, hair_cache->final[subdiv].proc_hairs[thickness_res - 1], object); /* Transform Feedback subdiv. */ @@ -224,7 +224,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", hair_cache->strand_seg_tex); DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); - DRW_shgroup_call_procedural_points_add(tf_shgrp, final_points_len, NULL); + DRW_shgroup_call_procedural_points(tf_shgrp, final_points_len, NULL); } return shgrp; diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index e8d91309e06..e7a41ee3e43 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -36,33 +36,9 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" #include "BLI_mempool.h" +#include "BLI_memblock.h" -#define BUFFER_CHUNK_SIZE 32 -#define BUFFER_VERTS_CHUNK 32 - -typedef struct DRWBatchingBuffer { - struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */ - GPUVertFormat *format; /* Identifier. */ - GPUVertBuf *vert; /* GPUVertBuf contained in the GPUBatch. */ - GPUBatch *batch; /* GPUBatch containing the GPUVertBuf. */ -} DRWBatchingBuffer; - -typedef struct DRWInstancingBuffer { - struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */ - GPUVertFormat *format; /* Identifier. */ - GPUBatch *instance; /* Identifier. */ - GPUVertBuf *vert; /* GPUVertBuf contained in the GPUBatch. */ - GPUBatch *batch; /* GPUBatch containing the GPUVertBuf. */ -} DRWInstancingBuffer; - -typedef struct DRWInstanceChunk { - size_t cursor; /* Offset to the next instance data. */ - size_t alloc_size; /* Number of DRWBatchingBuffer/Batches alloc'd in ibufs/btchs. */ - union { - DRWBatchingBuffer *bbufs; - DRWInstancingBuffer *ibufs; - }; -} DRWInstanceChunk; +#include "intern/gpu_primitive_private.h" struct DRWInstanceData { struct DRWInstanceData *next; @@ -77,212 +53,167 @@ struct DRWInstanceDataList { DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE]; DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE]; - DRWInstanceChunk instancing; - DRWInstanceChunk batching; + BLI_memblock *pool_instancing; + BLI_memblock *pool_batching; + BLI_memblock *pool_buffers; }; +typedef struct DRWTempBufferHandle { + /** Must be first for casting. */ + GPUVertBuf buf; + /** Format pointer for reuse. */ + GPUVertFormat *format; + /** Touched vertex length for resize. */ + uint *vert_len; +} DRWTempBufferHandle; + static ListBase g_idatalists = {NULL, NULL}; /* -------------------------------------------------------------------- */ /** \name Instance Buffer Management * \{ */ -/** - * This manager allows to distribute existing batches for instancing - * attributes. This reduce the number of batches creation. - * Querying a batch is done with a vertex format. This format should - * be static so that it's pointer never changes (because we are using - * this pointer as identifier [we don't want to check the full format - * that would be too slow]). - */ -static void instance_batch_free(GPUBatch *batch, void *UNUSED(user_data)) +static void instance_batch_free(GPUBatch *geom, void *UNUSED(user_data)) { - if (batch->verts[0] == NULL) { + if (geom->verts[0] == NULL) { /** XXX This is a false positive case. * The batch has been requested but not init yet * and there is a chance that it might become init. */ return; } - /* Free all batches that have the same key before they are reused. */ + + /* Free all batches that use the same vbos before they are reused. */ /* TODO: Make it thread safe! Batch freeing can happen from another thread. */ - /* XXX we need to iterate over all idatalists unless we make some smart - * data structure to store the locations to update. */ - for (DRWInstanceDataList *idatalist = g_idatalists.first; idatalist; - idatalist = idatalist->next) { - DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; - for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { - if (ibuf->instance == batch) { - BLI_assert(ibuf->shgroup == NULL); /* Make sure it has no other users. */ - GPU_VERTBUF_DISCARD_SAFE(ibuf->vert); - GPU_BATCH_DISCARD_SAFE(ibuf->batch); - /* Tag as non alloced. */ - ibuf->format = NULL; + /* FIXME: This is not really correct. The correct way would be to check based on + * the vertex buffers. We assume the batch containing the VBO is being when it should. */ + /* PERF: This is doing a linear search. This can be very costly. */ + LISTBASE_FOREACH (DRWInstanceDataList *, data_list, &g_idatalists) { + BLI_memblock *memblock = data_list->pool_instancing; + BLI_memblock_iter iter; + BLI_memblock_iternew(memblock, &iter); + GPUBatch *batch; + while ((batch = (GPUBatch *)BLI_memblock_iterstep(&iter))) { + /* Only check verts[0] that's enough. */ + if (batch->verts[0] == geom->verts[0]) { + GPU_batch_clear(batch); } } } } -void DRW_batching_buffer_request(DRWInstanceDataList *idatalist, - GPUVertFormat *format, - GPUPrimType type, - struct DRWShadingGroup *shgroup, - GPUBatch **r_batch, - GPUVertBuf **r_vert) +/** + * This manager allows to distribute existing batches for instancing + * attributes. This reduce the number of batches creation. + * Querying a batch is done with a vertex format. This format should + * be static so that it's pointer never changes (because we are using + * this pointer as identifier [we don't want to check the full format + * that would be too slow]). + */ +GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist, + GPUVertFormat *format, + uint *vert_len) { - DRWInstanceChunk *chunk = &idatalist->batching; - DRWBatchingBuffer *bbuf = idatalist->batching.bbufs; - BLI_assert(format); - /* Search for an unused batch. */ - for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) { - if (bbuf->shgroup == NULL) { - if (bbuf->format == format) { - bbuf->shgroup = shgroup; - *r_batch = bbuf->batch; - *r_vert = bbuf->vert; - return; - } - } - } - int new_id = 0; /* Find insertion point. */ - for (; new_id < chunk->alloc_size; ++new_id) { - if (chunk->bbufs[new_id].format == NULL) { - break; - } + BLI_assert(format != NULL); + BLI_assert(vert_len != NULL); + + DRWTempBufferHandle *handle = BLI_memblock_alloc(idatalist->pool_buffers); + GPUVertBuf *vert = &handle->buf; + handle->vert_len = vert_len; + + if (handle->format != format) { + handle->format = format; + /* TODO/PERF: Save the allocated data from freeing to avoid reallocation. */ + GPU_vertbuf_clear(vert); + GPU_vertbuf_init_with_format_ex(vert, format, GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(vert, DRW_BUFFER_VERTS_CHUNK); } - /* If there is no batch left. Allocate more. */ - if (new_id == chunk->alloc_size) { - new_id = chunk->alloc_size; - chunk->alloc_size += BUFFER_CHUNK_SIZE; - chunk->bbufs = MEM_reallocN(chunk->bbufs, chunk->alloc_size * sizeof(DRWBatchingBuffer)); - memset(chunk->bbufs + new_id, 0, sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE); - } - /* Create the batch. */ - bbuf = chunk->bbufs + new_id; - bbuf->vert = *r_vert = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_DYNAMIC); - bbuf->batch = *r_batch = GPU_batch_create_ex(type, bbuf->vert, NULL, 0); - bbuf->format = format; - bbuf->shgroup = shgroup; - GPU_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK); + return vert; } -void DRW_instancing_buffer_request(DRWInstanceDataList *idatalist, - GPUVertFormat *format, - GPUBatch *instance, - struct DRWShadingGroup *shgroup, - GPUBatch **r_batch, - GPUVertBuf **r_vert) +/* NOTE: Does not return a valid drawable batch until DRW_instance_buffer_finish has run. */ +GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, + GPUVertBuf *buf, + GPUBatch *geom) { - DRWInstanceChunk *chunk = &idatalist->instancing; - DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; - BLI_assert(format); - /* Search for an unused batch. */ - for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { - if (ibuf->shgroup == NULL) { - if (ibuf->format == format) { - if (ibuf->instance == instance) { - ibuf->shgroup = shgroup; - *r_batch = ibuf->batch; - *r_vert = ibuf->vert; - return; - } - } + /* Do not call this with a batch that is already an instancing batch. */ + BLI_assert(geom->inst == NULL); + + GPUBatch *batch = BLI_memblock_alloc(idatalist->pool_instancing); + bool is_compatible = (batch->gl_prim_type == geom->gl_prim_type) && (batch->inst == buf) && + (batch->phase == GPU_BATCH_READY_TO_DRAW); + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN && is_compatible; i++) { + if (batch->verts[i] != geom->verts[i]) { + is_compatible = false; } } - int new_id = 0; /* Find insertion point. */ - for (; new_id < chunk->alloc_size; ++new_id) { - if (chunk->ibufs[new_id].format == NULL) { - break; - } + + if (!is_compatible) { + GPU_batch_clear(batch); + /* Save args and init later */ + batch->inst = buf; + batch->phase = GPU_BATCH_READY_TO_BUILD; + batch->verts[0] = (void *)geom; /* HACK to save the pointer without other alloc. */ + + /* Make sure to free this batch if the instance geom gets free. */ + GPU_batch_callback_free_set(geom, &instance_batch_free, NULL); } - /* If there is no batch left. Allocate more. */ - if (new_id == chunk->alloc_size) { - new_id = chunk->alloc_size; - chunk->alloc_size += BUFFER_CHUNK_SIZE; - chunk->ibufs = MEM_reallocN(chunk->ibufs, chunk->alloc_size * sizeof(DRWInstancingBuffer)); - memset(chunk->ibufs + new_id, 0, sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE); + return batch; +} + +/* NOTE: Use only with buf allocated via DRW_temp_buffer_request. */ +GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist, + GPUVertBuf *buf, + GPUPrimType prim_type) +{ + GPUBatch *batch = BLI_memblock_alloc(idatalist->pool_batching); + bool is_compatible = (batch->verts[0] == buf) && + (batch->gl_prim_type == convert_prim_type_to_gl(prim_type)); + if (!is_compatible) { + GPU_batch_clear(batch); + GPU_batch_init(batch, prim_type, buf, NULL); } - /* Create the batch. */ - ibuf = chunk->ibufs + new_id; - ibuf->vert = *r_vert = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_DYNAMIC); - ibuf->batch = *r_batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); - ibuf->format = format; - ibuf->shgroup = shgroup; - ibuf->instance = instance; - GPU_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK); - /* Make sure to free this ibuf if the instance batch gets free. */ - GPU_batch_callback_free_set(instance, &instance_batch_free, NULL); + return batch; +} + +static void temp_buffer_handle_free(DRWTempBufferHandle *handle) +{ + handle->format = NULL; + GPU_vertbuf_clear(&handle->buf); } void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist) { - size_t realloc_size = 1; /* Avoid 0 size realloc. */ - /* Resize down buffers in use and send data to GPU & free unused buffers. */ - DRWInstanceChunk *batching = &idatalist->batching; - DRWBatchingBuffer *bbuf = batching->bbufs; - for (int i = 0; i < batching->alloc_size; i++, bbuf++) { - if (bbuf->shgroup != NULL) { - realloc_size = i + 1; - uint vert_len = DRW_shgroup_get_instance_count(bbuf->shgroup); - vert_len += (vert_len == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */ - if (vert_len + BUFFER_VERTS_CHUNK <= bbuf->vert->vertex_len) { - uint size = vert_len + BUFFER_VERTS_CHUNK - 1; - size = size - size % BUFFER_VERTS_CHUNK; - GPU_vertbuf_data_resize(bbuf->vert, size); + /* Resize down buffers in use and send data to GPU. */ + BLI_memblock_iter iter; + DRWTempBufferHandle *handle; + BLI_memblock_iternew(idatalist->pool_buffers, &iter); + while ((handle = BLI_memblock_iterstep(&iter))) { + if (handle->vert_len != NULL) { + uint vert_len = *(handle->vert_len); + uint target_buf_size = ((vert_len / DRW_BUFFER_VERTS_CHUNK) + 1) * DRW_BUFFER_VERTS_CHUNK; + if (target_buf_size < handle->buf.vertex_alloc) { + GPU_vertbuf_data_resize(&handle->buf, target_buf_size); } - GPU_vertbuf_use(bbuf->vert); /* Send data. */ - bbuf->shgroup = NULL; /* Set as non used for the next round. */ - } - else { - GPU_VERTBUF_DISCARD_SAFE(bbuf->vert); - GPU_BATCH_DISCARD_SAFE(bbuf->batch); - bbuf->format = NULL; /* Tag as non alloced. */ + GPU_vertbuf_data_len_set(&handle->buf, vert_len); + GPU_vertbuf_use(&handle->buf); /* Send data. */ } } - /* Rounding up to nearest chunk size. */ - realloc_size += BUFFER_CHUNK_SIZE - 1; - realloc_size -= realloc_size % BUFFER_CHUNK_SIZE; - /* Resize down if necessary. */ - if (realloc_size < batching->alloc_size) { - batching->alloc_size = realloc_size; - batching->ibufs = MEM_reallocN(batching->ibufs, realloc_size * sizeof(DRWBatchingBuffer)); - } - - realloc_size = 1; - /* Resize down buffers in use and send data to GPU & free unused buffers. */ - DRWInstanceChunk *instancing = &idatalist->instancing; - DRWInstancingBuffer *ibuf = instancing->ibufs; - for (int i = 0; i < instancing->alloc_size; i++, ibuf++) { - if (ibuf->shgroup != NULL) { - realloc_size = i + 1; - uint vert_len = DRW_shgroup_get_instance_count(ibuf->shgroup); - vert_len += (vert_len == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */ - if (vert_len + BUFFER_VERTS_CHUNK <= ibuf->vert->vertex_len) { - uint size = vert_len + BUFFER_VERTS_CHUNK - 1; - size = size - size % BUFFER_VERTS_CHUNK; - GPU_vertbuf_data_resize(ibuf->vert, size); - } - GPU_vertbuf_use(ibuf->vert); /* Send data. */ - /* Setup batch now that we are sure ibuf->instance is setup. */ - GPU_batch_copy(ibuf->batch, ibuf->instance); - GPU_batch_instbuf_set(ibuf->batch, ibuf->vert, false); - ibuf->shgroup = NULL; /* Set as non used for the next round. */ - } - else { - GPU_VERTBUF_DISCARD_SAFE(ibuf->vert); - GPU_BATCH_DISCARD_SAFE(ibuf->batch); - ibuf->format = NULL; /* Tag as non alloced. */ + /* Finish pending instancing batches. */ + GPUBatch *batch; + BLI_memblock_iternew(idatalist->pool_instancing, &iter); + while ((batch = BLI_memblock_iterstep(&iter))) { + if (batch->phase == GPU_BATCH_READY_TO_BUILD) { + GPUVertBuf *inst = batch->inst; + GPUBatch *geom = (void *)batch->verts[0]; /* HACK see DRW_temp_batch_instance_request. */ + GPU_batch_copy(batch, geom); + GPU_batch_instbuf_set(batch, inst, false); } } - /* Rounding up to nearest chunk size. */ - realloc_size += BUFFER_CHUNK_SIZE - 1; - realloc_size -= realloc_size % BUFFER_CHUNK_SIZE; - /* Resize down if necessary. */ - if (realloc_size < instancing->alloc_size) { - instancing->alloc_size = realloc_size; - instancing->ibufs = MEM_reallocN(instancing->ibufs, - realloc_size * sizeof(DRWInstancingBuffer)); - } + /* Resize pools and free unused. */ + BLI_memblock_clear(idatalist->pool_buffers, (MemblockValFreeFP)temp_buffer_handle_free); + BLI_memblock_clear(idatalist->pool_instancing, (MemblockValFreeFP)GPU_batch_clear); + BLI_memblock_clear(idatalist->pool_batching, (MemblockValFreeFP)GPU_batch_clear); } /** \} */ @@ -352,12 +283,10 @@ DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint DRWInstanceDataList *DRW_instance_data_list_create(void) { DRWInstanceDataList *idatalist = MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); - idatalist->batching.bbufs = MEM_callocN(sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE, - "DRWBatchingBuffers"); - idatalist->batching.alloc_size = BUFFER_CHUNK_SIZE; - idatalist->instancing.ibufs = MEM_callocN(sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE, - "DRWInstancingBuffers"); - idatalist->instancing.alloc_size = BUFFER_CHUNK_SIZE; + + idatalist->pool_batching = BLI_memblock_create(sizeof(GPUBatch)); + idatalist->pool_instancing = BLI_memblock_create(sizeof(GPUBatch)); + idatalist->pool_buffers = BLI_memblock_create(sizeof(DRWTempBufferHandle)); BLI_addtail(&g_idatalists, idatalist); @@ -378,19 +307,9 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) idatalist->idata_tail[i] = NULL; } - DRWBatchingBuffer *bbuf = idatalist->batching.bbufs; - for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) { - GPU_VERTBUF_DISCARD_SAFE(bbuf->vert); - GPU_BATCH_DISCARD_SAFE(bbuf->batch); - } - MEM_freeN(idatalist->batching.bbufs); - - DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; - for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { - GPU_VERTBUF_DISCARD_SAFE(ibuf->vert); - GPU_BATCH_DISCARD_SAFE(ibuf->batch); - } - MEM_freeN(idatalist->instancing.ibufs); + BLI_memblock_destroy(idatalist->pool_buffers, (MemblockValFreeFP)temp_buffer_handle_free); + BLI_memblock_destroy(idatalist->pool_instancing, (MemblockValFreeFP)GPU_batch_clear); + BLI_memblock_destroy(idatalist->pool_batching, (MemblockValFreeFP)GPU_batch_clear); BLI_remlink(&g_idatalists, idatalist); } diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h index ea5c6ac7bb2..d88de1a58e2 100644 --- a/source/blender/draw/intern/draw_instance_data.h +++ b/source/blender/draw/intern/draw_instance_data.h @@ -30,6 +30,8 @@ #define MAX_INSTANCE_DATA_SIZE 64 /* Can be adjusted for more */ +#define DRW_BUFFER_VERTS_CHUNK 128 + typedef struct DRWInstanceData DRWInstanceData; typedef struct DRWInstanceDataList DRWInstanceDataList; @@ -38,18 +40,15 @@ struct DRWShadingGroup; void *DRW_instance_data_next(DRWInstanceData *idata); DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attr_size); -void DRW_batching_buffer_request(DRWInstanceDataList *idatalist, - GPUVertFormat *format, - GPUPrimType type, - struct DRWShadingGroup *shgroup, - GPUBatch **r_batch, - GPUVertBuf **r_vert); -void DRW_instancing_buffer_request(DRWInstanceDataList *idatalist, - GPUVertFormat *format, - GPUBatch *instance, - struct DRWShadingGroup *shgroup, - GPUBatch **r_batch, - GPUVertBuf **r_vert); +GPUVertBuf *DRW_temp_buffer_request(DRWInstanceDataList *idatalist, + GPUVertFormat *format, + uint *vert_len); +GPUBatch *DRW_temp_batch_instance_request(DRWInstanceDataList *idatalist, + GPUVertBuf *buf, + GPUBatch *geom); +GPUBatch *DRW_temp_batch_request(DRWInstanceDataList *idatalist, + GPUVertBuf *buf, + GPUPrimType type); /* Upload all instance data to the GPU as soon as possible. */ void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 5c88c1f93db..be046abfc8c 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -22,16 +22,19 @@ #include <stdio.h> +#include "BLI_alloca.h" #include "BLI_listbase.h" -#include "BLI_mempool.h" +#include "BLI_memblock.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_threads.h" #include "BLF_api.h" +#include "BKE_anim.h" #include "BKE_colortools.h" #include "BKE_curve.h" +#include "BKE_editmesh.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_lattice.h" @@ -40,6 +43,7 @@ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_pointcache.h" #include "draw_manager.h" @@ -212,6 +216,11 @@ bool DRW_object_use_hide_faces(const struct Object *ob) return false; } +bool DRW_object_use_pbvh_drawing(const struct Object *ob) +{ + return ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT); +} + bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys) { const bool for_render = DRW_state_is_image_render(); @@ -356,7 +365,8 @@ void DRW_transform_none(GPUTexture *tex) GPU_batch_uniform_mat4(geom, "ModelViewProjectionMatrix", mat); GPU_batch_program_use_begin(geom); - GPU_batch_draw_range_ex(geom, 0, 0, false); + GPU_batch_bind(geom); + GPU_batch_draw_advanced(geom, 0, 0, 0, 0); GPU_batch_program_use_end(geom); GPU_texture_unbind(tex); @@ -447,7 +457,8 @@ void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color, bool /* avoid gpuMatrix calls */ GPU_batch_program_use_begin(geom); - GPU_batch_draw_range_ex(geom, 0, 0, false); + GPU_batch_bind(geom); + GPU_batch_draw_advanced(geom, 0, 0, 0, 0); GPU_batch_program_use_end(geom); } @@ -520,19 +531,21 @@ static void drw_viewport_cache_resize(void) if (DST.vmempool != NULL) { /* Release Image textures. */ - BLI_mempool_iter iter; + BLI_memblock_iter iter; GPUTexture **tex; - BLI_mempool_iternew(DST.vmempool->images, &iter); - while ((tex = BLI_mempool_iterstep(&iter))) { + BLI_memblock_iternew(DST.vmempool->images, &iter); + while ((tex = BLI_memblock_iterstep(&iter))) { GPU_texture_free(*tex); } - BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_len(DST.vmempool->calls)); - BLI_mempool_clear_ex(DST.vmempool->states, BLI_mempool_len(DST.vmempool->states)); - BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_len(DST.vmempool->shgroups)); - BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_len(DST.vmempool->uniforms)); - BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_len(DST.vmempool->passes)); - BLI_mempool_clear_ex(DST.vmempool->images, BLI_mempool_len(DST.vmempool->images)); + BLI_memblock_clear(DST.vmempool->calls, NULL); + BLI_memblock_clear(DST.vmempool->states, NULL); + BLI_memblock_clear(DST.vmempool->cullstates, NULL); + BLI_memblock_clear(DST.vmempool->shgroups, NULL); + BLI_memblock_clear(DST.vmempool->uniforms, NULL); + BLI_memblock_clear(DST.vmempool->passes, NULL); + BLI_memblock_clear(DST.vmempool->views, NULL); + BLI_memblock_clear(DST.vmempool->images, NULL); } DRW_instance_data_list_free_unused(DST.idatalist); @@ -597,24 +610,28 @@ static void drw_viewport_var_init(void) DST.vmempool = GPU_viewport_mempool_get(DST.viewport); if (DST.vmempool->calls == NULL) { - DST.vmempool->calls = BLI_mempool_create(sizeof(DRWCall), 0, 512, 0); + DST.vmempool->calls = BLI_memblock_create(sizeof(DRWCall)); } if (DST.vmempool->states == NULL) { - DST.vmempool->states = BLI_mempool_create( - sizeof(DRWCallState), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + DST.vmempool->states = BLI_memblock_create(sizeof(DRWCallState)); + } + if (DST.vmempool->cullstates == NULL) { + DST.vmempool->cullstates = BLI_memblock_create(sizeof(DRWCullingState)); } if (DST.vmempool->shgroups == NULL) { - DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0); + DST.vmempool->shgroups = BLI_memblock_create(sizeof(DRWShadingGroup)); } if (DST.vmempool->uniforms == NULL) { - DST.vmempool->uniforms = BLI_mempool_create(sizeof(DRWUniform), 0, 512, 0); + DST.vmempool->uniforms = BLI_memblock_create(sizeof(DRWUniform)); + } + if (DST.vmempool->views == NULL) { + DST.vmempool->views = BLI_memblock_create(sizeof(DRWView)); } if (DST.vmempool->passes == NULL) { - DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0); + DST.vmempool->passes = BLI_memblock_create(sizeof(DRWPass)); } if (DST.vmempool->images == NULL) { - DST.vmempool->images = BLI_mempool_create( - sizeof(GPUTexture *), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + DST.vmempool->images = BLI_memblock_create(sizeof(GPUTexture *)); } DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport); @@ -631,36 +648,35 @@ static void drw_viewport_var_init(void) DST.vmempool = NULL; } + DST.primary_view_ct = 0; + if (rv3d != NULL) { - /* Refresh DST.screenvecs */ - copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); - copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); - normalize_v3(DST.screenvecs[0]); - normalize_v3(DST.screenvecs[1]); + normalize_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); + normalize_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); - /* Refresh DST.pixelsize */ DST.pixsize = rv3d->pixsize; + DST.view_default = DRW_view_create(rv3d->viewmat, rv3d->winmat, NULL, NULL, NULL); + DRW_view_camtexco_set(DST.view_default, rv3d->viewcamtexcofac); - copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERS], rv3d->persmat); - copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERSINV], rv3d->persinv); - copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEW], rv3d->viewmat); - copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEWINV], rv3d->viewinv); - copy_m4_m4(DST.original_mat.mat[DRW_MAT_WIN], rv3d->winmat); - invert_m4_m4(DST.original_mat.mat[DRW_MAT_WININV], rv3d->winmat); - - memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DST.original_mat.mat)); + if (DST.draw_ctx.sh_cfg == GPU_SHADER_CFG_CLIPPED) { + int plane_len = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; + DRW_view_clip_planes_set(DST.view_default, rv3d->clip, plane_len); + } - copy_v4_v4(DST.view_data.viewcamtexcofac, rv3d->viewcamtexcofac); + DST.view_active = DST.view_default; + DST.view_previous = NULL; } else { - copy_v4_fl4(DST.view_data.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); - } + zero_v3(DST.screenvecs[0]); + zero_v3(DST.screenvecs[1]); - /* Reset facing */ - DST.frontface = GL_CCW; - DST.backface = GL_CW; - glFrontFace(DST.frontface); + DST.pixsize = 1.0f; + DST.view_default = NULL; + DST.view_active = NULL; + DST.view_previous = NULL; + } + /* fclem: Is this still needed ? */ if (DST.draw_ctx.object_edit) { ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d); } @@ -669,116 +685,94 @@ static void drw_viewport_var_init(void) memset(&DST.RST, 0x0, sizeof(DST.RST)); if (G_draw.view_ubo == NULL) { - G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(ViewUboStorage), NULL); + G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL); } - DST.override_mat = 0; - DST.dirty_mat = true; - DST.state_cache_id = 1; - - DST.clipping.updated = false; - memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data)); } -void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) +DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) { - BLI_assert(type >= 0 && type < DRW_MAT_COUNT); - /* Can't use this in render mode. */ - BLI_assert(((DST.override_mat & (1 << type)) != 0) || DST.draw_ctx.rv3d != NULL); - - copy_m4_m4(mat, DST.view_data.matstate.mat[type]); + return GPU_viewport_framebuffer_list_get(DST.viewport); } -void DRW_viewport_matrix_get_all(DRWMatrixState *state) +DefaultTextureList *DRW_viewport_texture_list_get(void) { - memcpy(state, DST.view_data.matstate.mat, sizeof(DRWMatrixState)); + return GPU_viewport_texture_list_get(DST.viewport); } -void DRW_viewport_matrix_override_set(const float mat[4][4], DRWViewportMatrixType type) +void DRW_viewport_request_redraw(void) { - BLI_assert(type < DRW_MAT_COUNT); - copy_m4_m4(DST.view_data.matstate.mat[type], mat); - DST.override_mat |= (1 << type); - DST.dirty_mat = true; - DST.clipping.updated = false; + GPU_viewport_tag_update(DST.viewport); } -void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type) -{ - BLI_assert(type < DRW_MAT_COUNT); - copy_m4_m4(DST.view_data.matstate.mat[type], DST.original_mat.mat[type]); - DST.override_mat &= ~(1 << type); - DST.dirty_mat = true; - DST.clipping.updated = false; -} +/** \} */ -void DRW_viewport_matrix_override_set_all(DRWMatrixState *state) -{ - memcpy(DST.view_data.matstate.mat, state, sizeof(DRWMatrixState)); - DST.override_mat = 0xFFFFFF; - DST.dirty_mat = true; - DST.clipping.updated = false; -} +/* -------------------------------------------------------------------- */ +/** \name Duplis + * \{ */ -void DRW_viewport_matrix_override_unset_all(void) +static void drw_duplidata_load(DupliObject *dupli) { - memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DRWMatrixState)); - DST.override_mat = 0; - DST.dirty_mat = true; - DST.clipping.updated = false; -} + if (dupli == NULL) { + return; + } -bool DRW_viewport_is_persp_get(void) -{ - RegionView3D *rv3d = DST.draw_ctx.rv3d; - if (rv3d) { - return rv3d->is_persp; + if (DST.dupli_origin != dupli->ob) { + DST.dupli_origin = dupli->ob; } else { - return DST.view_data.matstate.mat[DRW_MAT_WIN][3][3] == 0.0f; + /* Same data as previous iter. No need to poll ghash for this. */ + return; } -} - -float DRW_viewport_near_distance_get(void) -{ - float projmat[4][4]; - DRW_viewport_matrix_get(projmat, DRW_MAT_WIN); - if (DRW_viewport_is_persp_get()) { - return -projmat[3][2] / (projmat[2][2] - 1.0f); - } - else { - return -(projmat[3][2] + 1.0f) / projmat[2][2]; + if (DST.dupli_ghash == NULL) { + DST.dupli_ghash = BLI_ghash_ptr_new(__func__); } -} -float DRW_viewport_far_distance_get(void) -{ - float projmat[4][4]; - DRW_viewport_matrix_get(projmat, DRW_MAT_WIN); + void **value; + if (!BLI_ghash_ensure_p(DST.dupli_ghash, DST.dupli_origin, &value)) { + *value = MEM_callocN(sizeof(void *) * DST.enabled_engine_count, __func__); - if (DRW_viewport_is_persp_get()) { - return -projmat[3][2] / (projmat[2][2] + 1.0f); - } - else { - return -(projmat[3][2] - 1.0f) / projmat[2][2]; + /* TODO: Meh a bit out of place but this is nice as it is + * only done once per "original" object. */ + drw_batch_cache_validate(DST.dupli_origin); } + DST.dupli_datas = *(void ***)value; } -DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) +static void duplidata_value_free(void *val) { - return GPU_viewport_framebuffer_list_get(DST.viewport); + void **dupli_datas = val; + for (int i = 0; i < DST.enabled_engine_count; i++) { + MEM_SAFE_FREE(dupli_datas[i]); + } + MEM_freeN(val); } -DefaultTextureList *DRW_viewport_texture_list_get(void) +static void drw_duplidata_free(void) { - return GPU_viewport_texture_list_get(DST.viewport); + if (DST.dupli_ghash != NULL) { + BLI_ghash_free(DST.dupli_ghash, + (void (*)(void *key))drw_batch_cache_generate_requested, + duplidata_value_free); + DST.dupli_ghash = NULL; + } } -void DRW_viewport_request_redraw(void) +/* Return NULL if not a dupli or a pointer of pointer to the engine data */ +void **DRW_duplidata_get(void *vedata) { - GPU_viewport_tag_update(DST.viewport); + if (DST.dupli_source == NULL) { + return NULL; + } + /* XXX Search engine index by using vedata array */ + for (int i = 0; i < DST.enabled_engine_count; i++) { + if (DST.vedata_array[i] == vedata) { + return &DST.dupli_datas[i]; + } + } + return NULL; } /** \} */ @@ -1039,9 +1033,14 @@ static void drw_engines_init(void) static void drw_engines_cache_init(void) { - for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DST.enabled_engine_count = BLI_listbase_count(&DST.enabled_engines); + DST.vedata_array = MEM_mallocN(sizeof(void *) * DST.enabled_engine_count, __func__); + + int i = 0; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { DrawEngineType *engine = link->data; ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + DST.vedata_array[i] = data; if (data->text_draw_cache) { DRW_text_cache_destroy(data->text_draw_cache); @@ -1083,9 +1082,15 @@ static void drw_engines_cache_populate(Object *ob) * ourselves here. */ drw_drawdata_unlink_dupli((ID *)ob); - for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + /* Validation for dupli objects happen elsewhere. */ + if (!DST.dupli_source) { + drw_batch_cache_validate(ob); + } + + int i = 0; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + ViewportEngineData *data = DST.vedata_array[i]; if (engine->id_update) { engine->id_update(data, &ob->id); @@ -1098,7 +1103,9 @@ static void drw_engines_cache_populate(Object *ob) /* TODO: in the future it would be nice to generate once for all viewports. * But we need threaded DRW manager first. */ - drw_batch_cache_generate_requested(ob); + if (!DST.dupli_source) { + drw_batch_cache_generate_requested(ob); + } /* ... and clearing it here too because theses draw data are * from a mempool and must not be free individually by depsgraph. */ @@ -1107,14 +1114,16 @@ static void drw_engines_cache_populate(Object *ob) static void drw_engines_cache_finish(void) { - for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + int i = 0; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) { DrawEngineType *engine = link->data; - ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + ViewportEngineData *data = DST.vedata_array[i]; if (engine->cache_finish) { engine->cache_finish(data); } } + MEM_freeN(DST.vedata_array); } static void drw_engines_draw_background(void) @@ -1390,17 +1399,19 @@ static void drw_engines_disable(void) BLI_freelistN(&DST.enabled_engines); } -static uint DRW_engines_get_hash(void) +static void drw_engines_data_validate(void) { - uint hash = 0; - /* The cache depends on enabled engines */ - /* FIXME : if collision occurs ... segfault */ + int enabled_engines = BLI_listbase_count(&DST.enabled_engines); + void **engine_handle_array = BLI_array_alloca(engine_handle_array, enabled_engines + 1); + int i = 0; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - hash += BLI_ghashutil_strhash_p(engine->idname); + engine_handle_array[i++] = engine; } + engine_handle_array[i] = NULL; - return hash; + GPU_viewport_engines_data_validate(DST.viewport, engine_handle_array); } /* -------------------------------------------------------------------- */ @@ -1513,8 +1524,6 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DST.viewport = viewport; /* Setup viewport */ - GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash()); - DST.draw_ctx = (DRWContextState){ .ar = ar, .rv3d = rv3d, @@ -1534,6 +1543,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* Get list of enabled engines */ drw_engines_enable(view_layer, engine_type); + drw_engines_data_validate(); + /* Update ubos */ DRW_globals_update(); @@ -1552,23 +1563,31 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_engines_cache_init(); drw_engines_world_update(scene); - const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; - const int iter_flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | - DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | - DEG_ITER_OBJECT_FLAG_DUPLI; - DEG_OBJECT_ITER_BEGIN (depsgraph, ob, iter_flag) { - if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { - continue; - } - if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { - continue; + /* Only iterate over objects for internal engines or when overlays are enabled */ + const bool internal_engine = (engine_type->flag & RE_INTERNAL) != 0; + const bool draw_type_render = v3d->shading.type == OB_RENDER; + const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + if (internal_engine || overlays_on || !draw_type_render) { + const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; + const int iter_flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI; + DEG_OBJECT_ITER_BEGIN (depsgraph, ob, iter_flag) { + if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { + continue; + } + if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) { + continue; + } + DST.dupli_parent = data_.dupli_parent; + DST.dupli_source = data_.dupli_object_current; + drw_duplidata_load(DST.dupli_source); + drw_engines_cache_populate(ob); } - DST.dupli_parent = data_.dupli_parent; - DST.dupli_source = data_.dupli_object_current; - drw_engines_cache_populate(ob); + DEG_OBJECT_ITER_END; } - DEG_OBJECT_ITER_END; + drw_duplidata_free(); drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); @@ -1615,10 +1634,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, drw_engines_draw_scene(); -#ifdef __APPLE__ - /* Fix 3D view being "laggy" on macos. (See T56996) */ + /* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */ GPU_flush(); -#endif /* annotations - temporary drawing buffer (3d space) */ /* XXX: Or should we use a proper draw/overlay engine for this case? */ @@ -1630,16 +1647,15 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, } DRW_draw_callbacks_post_scene(); + DRW_state_reset(); + if (DST.draw_ctx.evil_C) { - DRW_state_reset(); ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_POST_VIEW); /* Callback can be nasty and do whatever they want with the state. * Don't trust them! */ DRW_state_reset(); } - DRW_state_reset(); - drw_debug_draw(); GPU_depth_test(false); @@ -1785,9 +1801,9 @@ static void DRW_render_gpencil_to_image(RenderEngine *engine, void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph) { - /* This function is only valid for Cycles - * Eevee done all work in the Eevee render directly. - * Maybe it can be done equal for both engines? + /* This function is only valid for Cycles & Workbench + * Eevee does all work in the Eevee render directly. + * Maybe it can be done equal for all engines? */ if (STREQ(engine->type->name, "Eevee")) { return; @@ -1854,7 +1870,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph } RenderResult *render_result = RE_engine_get_result(engine); - RenderLayer *render_layer = render_result->layers.first; + RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name); DRW_render_gpencil_to_image(engine, render_layer, &render_rect); @@ -2011,12 +2027,20 @@ void DRW_render_object_iter( DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; DST.ob_state = NULL; - callback(vedata, ob, engine, depsgraph); + drw_duplidata_load(DST.dupli_source); - drw_batch_cache_generate_requested(ob); + if (!DST.dupli_source) { + drw_batch_cache_validate(ob); + } + callback(vedata, ob, engine, depsgraph); + if (!DST.dupli_source) { + drw_batch_cache_generate_requested(ob); + } } } DEG_OBJECT_ITER_END; + + drw_duplidata_free(); } /* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired). @@ -2246,14 +2270,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, drw_engines_world_update(scene); if (use_obedit) { -# if 0 - drw_engines_cache_populate(obact); -# else FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) { drw_engines_cache_populate(ob_iter); } FOREACH_OBJECT_IN_MODE_END; -# endif } else { const int iter_flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | @@ -2284,16 +2304,18 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /* This relies on dupli instances being after their instancing object. */ if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { Object *ob_orig = DEG_get_original_object(ob); - DRW_select_load_id(ob_orig->select_id); + DRW_select_load_id(ob_orig->runtime.select_id); } DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; + drw_duplidata_load(DST.dupli_source); drw_engines_cache_populate(ob); } } DEG_OBJECT_ITER_END; } + drw_duplidata_free(); drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); @@ -2349,8 +2371,6 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, */ static void drw_draw_depth_loop_imp(void) { - DRW_opengl_context_enable(); - /* Setup framebuffer */ DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get( DST.viewport); @@ -2388,10 +2408,12 @@ static void drw_draw_depth_loop_imp(void) DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; + drw_duplidata_load(DST.dupli_source); drw_engines_cache_populate(ob); } DEG_OBJECT_ITER_END; + drw_duplidata_free(); drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); @@ -2411,9 +2433,6 @@ static void drw_draw_depth_loop_imp(void) /* TODO: Reading depth for operators should be done here. */ GPU_framebuffer_restore(); - - /* Changin context */ - DRW_opengl_context_disable(); } /** @@ -2429,6 +2448,8 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; + DRW_opengl_context_enable(); + /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); @@ -2463,6 +2484,9 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, /* Avoid accidental reuse. */ drw_state_ensure_not_reused(&DST); #endif + + /* Changin context */ + DRW_opengl_context_disable(); } /** @@ -2477,6 +2501,8 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; + DRW_opengl_context_enable(); + /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); @@ -2502,6 +2528,15 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, /* Avoid accidental reuse. */ drw_state_ensure_not_reused(&DST); #endif + + /* Changin context */ + DRW_opengl_context_disable(); +} + +/** See #DRW_shgroup_world_clip_planes_from_rv3d. */ +static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_clip_planes[6][4]) +{ + GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); } /** @@ -2547,7 +2582,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) GPU_SHADER_CFG_DEFAULT; GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_DEPTH_ONLY, sh_cfg); if (world_clip_planes != NULL) { - GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); } GPU_batch_draw(batch); @@ -2567,6 +2602,204 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) DRW_opengl_context_disable(); } +static void draw_mesh_verts(GPUBatch *batch, uint offset, const float world_clip_planes[6][4]) +{ + GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); + GPU_batch_uniform_1ui(batch, "offset", offset); + if (world_clip_planes != NULL) { + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + } + GPU_batch_draw(batch); +} + +static void draw_mesh_edges(GPUBatch *batch, uint offset, const float world_clip_planes[6][4]) +{ + GPU_line_width(1.0f); + glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); + + const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); + GPU_batch_uniform_1ui(batch, "offset", offset); + if (world_clip_planes != NULL) { + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + } + GPU_batch_draw(batch); + + glProvokingVertex(GL_LAST_VERTEX_CONVENTION); +} + +/* two options, facecolors or black */ +static void draw_mesh_face(GPUBatch *batch, + uint offset, + const bool use_select, + const float world_clip_planes[6][4]) +{ + if (use_select) { + const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); + GPU_batch_uniform_1ui(batch, "offset", offset); + if (world_clip_planes != NULL) { + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + } + GPU_batch_draw(batch); + } + else { + const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_UNIFORM_SELECT_ID, sh_cfg); + GPU_batch_uniform_1ui(batch, "id", 0); + if (world_clip_planes != NULL) { + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + } + GPU_batch_draw(batch); + } +} + +static void draw_mesh_face_dot(GPUBatch *batch, uint offset, const float world_clip_planes[6][4]) +{ + const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); + GPU_batch_uniform_1ui(batch, "offset", offset); + if (world_clip_planes != NULL) { + draw_world_clip_planes_from_rv3d(batch, world_clip_planes); + } + GPU_batch_draw(batch); +} + +void DRW_draw_select_id_object(Scene *scene, + RegionView3D *rv3d, + Object *ob, + short select_mode, + bool draw_facedot, + uint initial_offset, + uint *r_vert_offset, + uint *r_edge_offset, + uint *r_face_offset) +{ + ToolSettings *ts = scene->toolsettings; + if (select_mode == -1) { + select_mode = ts->selectmode; + } + + GPU_matrix_mul(ob->obmat); + + const float(*world_clip_planes)[4] = NULL; + if (rv3d->rflag & RV3D_CLIPPING) { + ED_view3d_clipping_local(rv3d, ob->obmat); + world_clip_planes = rv3d->clip_local; + } + + BLI_assert(initial_offset > 0); + + switch (ob->type) { + case OB_MESH: + if (ob->mode & OB_MODE_EDIT) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_mesh; + const bool use_faceselect = (select_mode & SCE_SELECT_FACE) != 0; + + DRW_mesh_batch_cache_validate(me); + + BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); + + GPUBatch *geom_faces, *geom_edges, *geom_verts, *geom_facedots; + geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); + if (select_mode & SCE_SELECT_EDGE) { + geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me); + } + if (select_mode & SCE_SELECT_VERTEX) { + geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); + } + if (use_faceselect && draw_facedot) { + geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(me); + } + DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true); + + draw_mesh_face(geom_faces, initial_offset, use_faceselect, world_clip_planes); + + if (use_faceselect && draw_facedot) { + draw_mesh_face_dot(geom_facedots, initial_offset, world_clip_planes); + } + + if (select_mode & SCE_SELECT_FACE) { + *r_face_offset = initial_offset + em->bm->totface; + } + else { + *r_face_offset = initial_offset; + } + + ED_view3d_polygon_offset(rv3d, 1.0); + + /* Unlike faces, only draw edges if edge select mode. */ + if (select_mode & SCE_SELECT_EDGE) { + draw_mesh_edges(geom_edges, *r_face_offset, world_clip_planes); + *r_edge_offset = *r_face_offset + em->bm->totedge; + } + else { + /* Note that `r_vert_offset` is calculated from `r_edge_offset`. + * Otherwise the first vertex is never selected, see: T53512. */ + *r_edge_offset = *r_face_offset; + } + + ED_view3d_polygon_offset(rv3d, 1.1); + + /* Unlike faces, only verts if vert select mode. */ + if (select_mode & SCE_SELECT_VERTEX) { + draw_mesh_verts(geom_verts, *r_edge_offset, world_clip_planes); + *r_vert_offset = *r_edge_offset + em->bm->totvert; + } + else { + *r_vert_offset = *r_edge_offset; + } + + ED_view3d_polygon_offset(rv3d, 0.0); + } + else { + Mesh *me_orig = DEG_get_original_object(ob)->data; + Mesh *me_eval = ob->data; + + DRW_mesh_batch_cache_validate(me_eval); + GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me_eval); + if ((me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) && + /* Currently vertex select supports weight paint and vertex paint. */ + ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { + + GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me_eval); + DRW_mesh_batch_cache_create_requested(ob, me_eval, NULL, false, true); + + /* Only draw faces to mask out verts, we don't want their selection ID's. */ + draw_mesh_face(geom_faces, 0, false, world_clip_planes); + draw_mesh_verts(geom_verts, 1, world_clip_planes); + + *r_face_offset = *r_edge_offset = initial_offset; + *r_vert_offset = me_eval->totvert + 1; + } + else { + const bool use_hide = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL); + DRW_mesh_batch_cache_create_requested(ob, me_eval, NULL, false, use_hide); + + draw_mesh_face(geom_faces, initial_offset, true, world_clip_planes); + + *r_face_offset = initial_offset + me_eval->totpoly; + *r_edge_offset = *r_vert_offset = *r_face_offset; + } + } + break; + case OB_CURVE: + case OB_SURF: + break; + } + + GPU_matrix_set(rv3d->viewmat); +} + /* Set an opengl context to be used with shaders that draw on U32 colors. */ void DRW_framebuffer_select_id_setup(ARegion *ar, const bool clear) { @@ -2583,7 +2816,7 @@ void DRW_framebuffer_select_id_setup(ARegion *ar, const bool clear) glDisable(GL_DITHER); GPU_depth_test(true); - glDisable(GL_SCISSOR_TEST); + GPU_disable_program_point_size(); if (clear) { GPU_framebuffer_clear_color_depth( @@ -2654,7 +2887,8 @@ void DRW_state_dfdy_factors_get(float dfdyfac[2]) */ bool DRW_state_is_fbo(void) { - return ((DST.default_framebuffer != NULL) || DST.options.is_image_render); + return ((DST.default_framebuffer != NULL) || DST.options.is_image_render) && + !DRW_state_is_depth() && !DRW_state_is_select(); } /** @@ -2841,7 +3075,6 @@ void DRW_engines_free(void) DRW_UBO_FREE_SAFE(G_draw.view_ubo); DRW_TEXTURE_FREE_SAFE(G_draw.ramp); DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp); - MEM_SAFE_FREE(g_pos_format); MEM_SAFE_FREE(DST.uniform_names.buffer); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index a70438a2d37..6cf70f555eb 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -43,9 +43,9 @@ /* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ #define USE_GPU_SELECT +// #define DRW_DEBUG_CULLING #define DRW_DEBUG_USE_UNIFORM_NAME 0 #define DRW_UNIFORM_BUFFER_NAME 64 -#define DRW_UNIFORM_BUFFER_NAME_INC 1024 /* ------------ Profiling --------------- */ @@ -92,102 +92,56 @@ /* Used by DRWCallState.flag */ enum { - DRW_CALL_CULLED = (1 << 0), DRW_CALL_NEGSCALE = (1 << 1), - DRW_CALL_BYPASS_CULLING = (1 << 2), }; /* Used by DRWCallState.matflag */ enum { DRW_CALL_MODELINVERSE = (1 << 0), - DRW_CALL_MODELVIEW = (1 << 1), - DRW_CALL_MODELVIEWINVERSE = (1 << 2), - DRW_CALL_MODELVIEWPROJECTION = (1 << 3), - DRW_CALL_NORMALVIEW = (1 << 4), - DRW_CALL_NORMALVIEWINVERSE = (1 << 5), - DRW_CALL_NORMALWORLD = (1 << 6), - DRW_CALL_ORCOTEXFAC = (1 << 7), - DRW_CALL_EYEVEC = (1 << 8), - DRW_CALL_OBJECTINFO = (1 << 9), + DRW_CALL_MODELVIEWPROJECTION = (1 << 1), + DRW_CALL_ORCOTEXFAC = (1 << 2), + DRW_CALL_OBJECTINFO = (1 << 3), }; -typedef struct DRWCallState { - DRWCallVisibilityFn *visibility_cb; +typedef struct DRWCullingState { + uint32_t mask; + /* Culling: Using Bounding Sphere for now for faster culling. + * Not ideal for planes. Could be extended. */ + BoundSphere bsphere; + /* Grrr only used by EEVEE. */ void *user_data; +} DRWCullingState; +typedef struct DRWCallState { + DRWCullingState *culling; uchar flag; - uchar cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */ - uint16_t matflag; /* Which matrices to compute. */ - /* Culling: Using Bounding Sphere for now for faster culling. - * Not ideal for planes. */ - BoundSphere bsphere; + uchar matflag; /* Which matrices to compute. */ + short ob_index; /* Matrices */ float model[4][4]; float modelinverse[4][4]; - float modelview[4][4]; - float modelviewinverse[4][4]; - float modelviewprojection[4][4]; - float normalview[3][3]; - float normalviewinverse[3][3]; - float normalworld[3][3]; /* Not view dependent */ - float orcotexfac[2][3]; /* Not view dependent */ - float objectinfo[2]; - float eyevec[3]; + float orcotexfac[2][3]; + float ob_random; } DRWCallState; -typedef enum { - /** A single batch. */ - DRW_CALL_SINGLE, - /** Like single but only draw a range of vertices/indices. */ - DRW_CALL_RANGE, - /** Draw instances without any instancing attributes. */ - DRW_CALL_INSTANCES, - /** Uses a callback to draw with any number of batches. */ - DRW_CALL_GENERATE, - /** Generate a drawcall without any #GPUBatch. */ - DRW_CALL_PROCEDURAL, -} DRWCallType; - typedef struct DRWCall { struct DRWCall *next; DRWCallState *state; - union { - struct { /* type == DRW_CALL_SINGLE */ - GPUBatch *geometry; - short ma_index; - } single; - struct { /* type == DRW_CALL_RANGE */ - GPUBatch *geometry; - uint start, count; - } range; - struct { /* type == DRW_CALL_INSTANCES */ - GPUBatch *geometry; - /* Count can be adjusted between redraw. If needed, we can add fixed count. */ - uint *count; - } instances; - struct { /* type == DRW_CALL_GENERATE */ - DRWCallGenerateFn *geometry_fn; - void *user_data; - } generate; - struct { /* type == DRW_CALL_PROCEDURAL */ - uint vert_count; - GPUPrimType prim_type; - } procedural; - }; + GPUBatch *batch; + uint vert_first; + uint vert_count; + uint inst_count; - DRWCallType type; #ifdef USE_GPU_SELECT + /* TODO(fclem) remove once we have a dedicated selection engine. */ int select_id; + GPUVertBuf *inst_selectid; #endif } DRWCall; /* Used by DRWUniform.type */ typedef enum { - DRW_UNIFORM_BOOL, - DRW_UNIFORM_BOOL_COPY, - DRW_UNIFORM_SHORT_TO_INT, - DRW_UNIFORM_SHORT_TO_FLOAT, DRW_UNIFORM_INT, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT, @@ -205,8 +159,8 @@ struct DRWUniform { /* For reference or array/vector types. */ const void *pvalue; /* Single values. */ - float fvalue; - int ivalue; + float fvalue[2]; + int ivalue[2]; }; int name_ofs; /* name offset in name buffer. */ int location; @@ -215,43 +169,18 @@ struct DRWUniform { char arraysize; /* cannot be more than 16 too */ }; -typedef enum { - DRW_SHG_NORMAL, - DRW_SHG_POINT_BATCH, - DRW_SHG_LINE_BATCH, - DRW_SHG_TRIANGLE_BATCH, - DRW_SHG_INSTANCE, - DRW_SHG_INSTANCE_EXTERNAL, - DRW_SHG_FEEDBACK_TRANSFORM, -} DRWShadingGroupType; - struct DRWShadingGroup { DRWShadingGroup *next; GPUShader *shader; /* Shader to bind */ DRWUniform *uniforms; /* Uniforms pointers */ - /* Watch this! Can be nasty for debugging. */ - union { - struct { /* DRW_SHG_NORMAL */ - DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */ - } calls; - struct { /* DRW_SHG_FEEDBACK_TRANSFORM */ - DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */ - struct GPUVertBuf *tfeedback_target; /* Transform Feedback target. */ - }; - struct { /* DRW_SHG_***_BATCH */ - struct GPUBatch *batch_geom; /* Result of call batching */ - struct GPUVertBuf *batch_vbo; - uint primitive_count; - }; - struct { /* DRW_SHG_INSTANCE[_EXTERNAL] */ - struct GPUBatch *instance_geom; - struct GPUVertBuf *instance_vbo; - uint instance_count; - float instance_orcofac[2][3]; /* TODO find a better place. */ - }; - }; + struct { + DRWCall *first, *last; /* Linked list of DRWCall */ + } calls; + + /** TODO Maybe remove from here */ + struct GPUVertBuf *tfeedback_target; /** State changes for this batch only (or'd with the pass's state) */ DRWState state_extra; @@ -259,31 +188,17 @@ struct DRWShadingGroup { DRWState state_extra_disable; /** Stencil mask to use for stencil test / write operations */ uint stencil_mask; - DRWShadingGroupType type; /* Builtin matrices locations */ int model; int modelinverse; - int modelview; - int modelviewinverse; int modelviewprojection; - int normalview; - int normalviewinverse; - int normalworld; int orcotexfac; - int eye; int callid; int objectinfo; - uint16_t matflag; /* Matrices needed, same as DRWCall.flag */ + uchar matflag; /* Matrices needed, same as DRWCall.flag */ DRWPass *pass_parent; /* backlink to pass we're in */ -#ifndef NDEBUG - char attrs_count; -#endif -#ifdef USE_GPU_SELECT - GPUVertBuf *inst_selectid; - int override_selectid; /* Override for single object instances. */ -#endif }; #define MAX_PASS_NAME 32 @@ -299,11 +214,49 @@ struct DRWPass { char name[MAX_PASS_NAME]; }; -typedef struct ViewUboStorage { - DRWMatrixState matstate; +/* keep in sync with viewBlock */ +typedef struct DRWViewUboStorage { + /* View matrices */ + float persmat[4][4]; + float persinv[4][4]; + float viewmat[4][4]; + float viewinv[4][4]; + float winmat[4][4]; + float wininv[4][4]; + + float clipplanes[6][4]; + /* Should not be here. Not view dependant (only main view). */ float viewcamtexcofac[4]; - float clipplanes[2][4]; -} ViewUboStorage; +} DRWViewUboStorage; + +#define MAX_CULLED_VIEWS 32 + +struct DRWView { + /** Parent view if this is a sub view. NULL otherwise. */ + struct DRWView *parent; + + DRWViewUboStorage storage; + /** Number of active clipplanes. */ + int clip_planes_len; + /** Does culling result needs to be updated. */ + bool is_dirty; + /** Culling */ + uint32_t culling_mask; + BoundBox frustum_corners; + BoundSphere frustum_bsphere; + float frustum_planes[6][4]; + /** Custom visibility function. */ + DRWCallVisibilityFn *visibility_fn; + void *user_data; +}; + +/* TODO(fclem): Future awaits */ +#if 0 +typedef struct ModelUboStorage { + float model[4][4]; + float modelinverse[4][4]; +} ModelUboStorage; +#endif /* ------------- DRAW DEBUG ------------ */ @@ -332,12 +285,15 @@ typedef struct DRWManager { DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE]; /* State of the object being evaluated if already allocated. */ DRWCallState *ob_state; - uchar state_cache_id; /* Could be larger but 254 view changes is already a lot! */ struct DupliObject *dupli_source; struct Object *dupli_parent; + struct Object *dupli_origin; + struct GHash *dupli_ghash; + void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */ /* Rendering state */ GPUShader *shader; + GPUBatch *batch; /* Managed by `DRW_state_set`, `DRW_state_reset` */ DRWState state; @@ -352,8 +308,6 @@ typedef struct DRWManager { float screenvecs[2][3]; float pixsize; - GLenum backface, frontface; - struct { uint is_select : 1; uint is_depth : 1; @@ -370,24 +324,18 @@ typedef struct DRWManager { struct DRWTextStore **text_store_p; ListBase enabled_engines; /* RenderEngineType */ + void **vedata_array; /* ViewportEngineData */ + int enabled_engine_count; /* Length of enabled_engines list. */ bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */ - /* View dependent uniforms. */ - DRWMatrixState original_mat; /* Original rv3d matrices. */ - int override_mat; /* Bitflag of which matrices are overridden. */ - int clip_planes_len; /* Number of active clipplanes. */ - bool dirty_mat; - - /* keep in sync with viewBlock */ - ViewUboStorage view_data; - - struct { - float frustum_planes[6][4]; - BoundBox frustum_corners; - BoundSphere frustum_bsphere; - bool updated; - } clipping; + DRWView *view_default; + DRWView *view_active; + DRWView *view_previous; + uint primary_view_ct; + /** TODO(fclem) Remove this. Only here to support + * shaders without common_view_lib.glsl */ + DRWViewUboStorage view_storage_cpy; #ifdef USE_GPU_SELECT uint select_id; @@ -443,8 +391,12 @@ void drw_state_set(DRWState state); void drw_debug_draw(void); void drw_debug_init(void); +void drw_batch_cache_validate(Object *ob); void drw_batch_cache_generate_requested(struct Object *ob); -extern struct GPUVertFormat *g_pos_format; +/* Procedural Drawing */ +GPUBatch *drw_cache_procedural_points_get(void); +GPUBatch *drw_cache_procedural_lines_get(void); +GPUBatch *drw_cache_procedural_triangles_get(void); #endif /* __DRAW_MANAGER_H__ */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 65ef2fa66fa..70f7d28d551 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -37,10 +37,15 @@ #include "BLI_hash.h" #include "BLI_link_utils.h" #include "BLI_mempool.h" +#include "BLI_memblock.h" -#include "intern/gpu_codegen.h" +#ifdef DRW_DEBUG_CULLING +# include "BLI_math_bits.h" +#endif -struct GPUVertFormat *g_pos_format = NULL; +#include "GPU_buffers.h" + +#include "intern/gpu_codegen.h" /* -------------------------------------------------------------------- */ /** \name Uniform Buffer Object (DRW_uniformbuffer) @@ -74,7 +79,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int length, int arraysize) { - DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms); + DRWUniform *uni = BLI_memblock_alloc(DST.vmempool->uniforms); uni->location = loc; uni->type = type; uni->length = length; @@ -82,16 +87,15 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, switch (type) { case DRW_UNIFORM_INT_COPY: - uni->ivalue = *((int *)value); - break; - case DRW_UNIFORM_BOOL_COPY: - uni->ivalue = (int)*((bool *)value); + BLI_assert(length <= 2); + memcpy(uni->ivalue, value, sizeof(int) * length); break; case DRW_UNIFORM_FLOAT_COPY: - uni->fvalue = *((float *)value); + BLI_assert(length <= 2); + memcpy(uni->fvalue, value, sizeof(float) * length); break; default: - uni->pvalue = value; + uni->pvalue = (const float *)value; break; } @@ -142,7 +146,7 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, size_t len = strlen(name) + 1; if (len >= max_len) { - DST.uniform_names.buffer_len += DRW_UNIFORM_BUFFER_NAME_INC; + DST.uniform_names.buffer_len += MAX2(DST.uniform_names.buffer_len, len); DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, DST.uniform_names.buffer_len); } @@ -199,7 +203,7 @@ void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const int *value, int arraysize) { - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize); } void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, @@ -234,22 +238,6 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize); } -void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, - const char *name, - const short *value, - int arraysize) -{ - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize); -} - -void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, - const char *name, - const short *value, - int arraysize) -{ - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize); -} - void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, @@ -300,7 +288,8 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value) { - drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL_COPY, &value, 1, 1); + int ival = value; + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &ival, 1, 1); } void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value) @@ -308,6 +297,11 @@ void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, &value, 1, 1); } +void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 2, 1); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -361,20 +355,29 @@ static void drw_call_state_update_matflag(DRWCallState *state, DRWShadingGroup *shgroup, Object *ob) { - uint16_t new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag); + uchar new_flags = ((state->matflag ^ shgroup->matflag) & shgroup->matflag); /* HACK: Here we set the matflags bit to 1 when computing the value * so that it's not recomputed for other drawcalls. * This is the opposite of what draw_matrices_model_prepare() does. */ state->matflag |= shgroup->matflag; + if (new_flags & DRW_CALL_MODELINVERSE) { + if (ob) { + copy_m4_m4(state->modelinverse, ob->imat); + } + else { + invert_m4_m4(state->modelinverse, state->model); + } + } + /* Orco factors: We compute this at creation to not have to save the *ob_data */ - if ((new_flags & DRW_CALL_ORCOTEXFAC) != 0) { + if (new_flags & DRW_CALL_ORCOTEXFAC) { drw_call_calc_orco(ob, state->orcotexfac); } - if ((new_flags & DRW_CALL_OBJECTINFO) != 0) { - state->objectinfo[0] = ob ? ob->index : 0; + if (new_flags & DRW_CALL_OBJECTINFO) { + state->ob_index = ob ? ob->index : 0; uint random; if (DST.dupli_source) { random = DST.dupli_source->random_id; @@ -382,23 +385,21 @@ static void drw_call_state_update_matflag(DRWCallState *state, else { random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0); } - state->objectinfo[1] = random * (1.0f / (float)0xFFFFFFFF); + state->ob_random = random * (1.0f / (float)0xFFFFFFFF); } } static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) { - DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states); + DRWCallState *state = BLI_memblock_alloc(DST.vmempool->states); state->flag = 0; - state->cache_id = 0; - state->visibility_cb = NULL; state->matflag = 0; /* Matrices */ if (obmat != NULL) { copy_m4_m4(state->model, obmat); - if (is_negative_m4(state->model)) { + if (ob && (ob->transflag & OB_NEG_SCALE)) { state->flag |= DRW_CALL_NEGSCALE; } } @@ -406,22 +407,27 @@ static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obm unit_m4(state->model); } + drw_call_state_update_matflag(state, shgroup, ob); + + DRWCullingState *cull = BLI_memblock_alloc(DST.vmempool->cullstates); + state->culling = cull; + if (ob != NULL) { float corner[3]; BoundBox *bbox = BKE_object_boundbox_get(ob); /* Get BoundSphere center and radius from the BoundBox. */ - mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]); + mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]); mul_v3_m4v3(corner, obmat, bbox->vec[0]); - mul_m4_v3(obmat, state->bsphere.center); - state->bsphere.radius = len_v3v3(state->bsphere.center, corner); + mul_m4_v3(obmat, cull->bsphere.center); + cull->bsphere.radius = len_v3v3(cull->bsphere.center, corner); } else { + /* TODO(fclem) Bypass alloc if we can (see if eevee's + * probe visibility collection still works). */ /* Bypass test. */ - state->bsphere.radius = -1.0f; + cull->bsphere.radius = -1.0f; } - drw_call_state_update_matflag(state, shgroup, ob); - return state; } @@ -438,314 +444,408 @@ static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obm return DST.ob_state; } -void DRW_shgroup_call_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4]) +void DRW_shgroup_call(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4]) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + call->state = drw_call_state_create(shgroup, obmat, NULL); - call->type = DRW_CALL_SINGLE; - call->single.geometry = geom; + call->batch = geom; + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = 0; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); } -void DRW_shgroup_call_range_add( +void DRW_shgroup_call_range( DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_count) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); BLI_assert(v_count); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + call->state = drw_call_state_create(shgroup, obmat, NULL); - call->type = DRW_CALL_RANGE; - call->range.geometry = geom; - call->range.start = v_sta; - call->range.count = v_count; + call->batch = geom; + call->vert_first = v_sta; + call->vert_count = v_count; + call->inst_count = 0; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); } static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, - GPUPrimType prim_type, + GPUBatch *geom, uint vert_count, - float (*obmat)[4], - Object *ob) + float (*obmat)[4]) { - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - if (ob) { - call->state = drw_call_state_object(shgroup, ob->obmat, ob); - } - else { - call->state = drw_call_state_create(shgroup, obmat, NULL); - } - call->type = DRW_CALL_PROCEDURAL; - call->procedural.prim_type = prim_type; - call->procedural.vert_count = vert_count; + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + + call->state = drw_call_state_object(shgroup, obmat, NULL); + call->batch = geom; + call->vert_first = 0; + call->vert_count = vert_count; + call->inst_count = 0; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); -} - -void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, - uint point_len, - float (*obmat)[4]) -{ - drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_POINTS, point_len, obmat, NULL); } -void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, - uint line_count, - float (*obmat)[4]) +void DRW_shgroup_call_procedural_points(DRWShadingGroup *shgroup, + uint point_len, + float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_LINES, line_count * 2, obmat, NULL); + struct GPUBatch *geom = drw_cache_procedural_points_get(); + drw_shgroup_call_procedural_add_ex(shgroup, geom, point_len, obmat); } -void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, - uint tria_count, - float (*obmat)[4]) +void DRW_shgroup_call_procedural_lines(DRWShadingGroup *shgroup, + uint line_count, + float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, obmat, NULL); + struct GPUBatch *geom = drw_cache_procedural_lines_get(); + drw_shgroup_call_procedural_add_ex(shgroup, geom, line_count * 2, obmat); } -/* TODO (fclem): this is a sign that the api is starting to be limiting. - * Maybe add special function that general purpose for special cases. */ -void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, - uint tria_count, - Object *ob) +void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *shgroup, + uint tria_count, + float (*obmat)[4]) { - drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, NULL, ob); + struct GPUBatch *geom = drw_cache_procedural_triangles_get(); + drw_shgroup_call_procedural_add_ex(shgroup, geom, tria_count * 3, obmat); } /* These calls can be culled and are optimized for redraw */ -void DRW_shgroup_call_object_add_ex( - DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, Material *ma, bool bypass_culling) +void DRW_shgroup_call_object_ex(DRWShadingGroup *shgroup, + GPUBatch *geom, + Object *ob, + bool bypass_culling) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + call->state = drw_call_state_object(shgroup, ob->obmat, ob); - call->type = DRW_CALL_SINGLE; - call->single.geometry = geom; - call->single.ma_index = ma ? ma->index : 0; + call->batch = geom; + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = 0; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - /* NOTE this will disable culling for the whole object. */ - call->state->flag |= (bypass_culling) ? DRW_CALL_BYPASS_CULLING : 0; - - BLI_LINKS_APPEND(&shgroup->calls, call); + if (bypass_culling) { + /* NOTE this will disable culling for the whole object. */ + call->state->culling->bsphere.radius = -1.0f; + } } -void DRW_shgroup_call_object_add_with_callback(DRWShadingGroup *shgroup, - GPUBatch *geom, - Object *ob, - Material *ma, - DRWCallVisibilityFn *callback, - void *user_data) +void DRW_shgroup_call_object_with_callback(DRWShadingGroup *shgroup, + GPUBatch *geom, + Object *ob, + void *user_data) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + call->state = drw_call_state_object(shgroup, ob->obmat, ob); - call->state->visibility_cb = callback; - call->state->user_data = user_data; - call->type = DRW_CALL_SINGLE; - call->single.geometry = geom; - call->single.ma_index = ma ? ma->index : 0; + call->state->culling->user_data = user_data; + call->batch = geom; + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = 0; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); } -void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, - GPUBatch *geom, - float (*obmat)[4], - uint *count) +void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, + GPUBatch *geom, + float (*obmat)[4], + uint count) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + call->state = drw_call_state_create(shgroup, obmat, NULL); - call->type = DRW_CALL_INSTANCES; - call->instances.geometry = geom; - call->instances.count = count; + call->batch = geom; + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = count; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); } -/* These calls can be culled and are optimized for redraw */ -void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, - GPUBatch *geom, - Object *ob, - uint *count) +void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup, + struct GPUBatch *geom, + float (*obmat)[4], + struct GPUBatch *inst_attributes) { BLI_assert(geom != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); + BLI_assert(inst_attributes->verts[0] != NULL); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - call->state = drw_call_state_object(shgroup, ob->obmat, ob); - call->type = DRW_CALL_INSTANCES; - call->instances.geometry = geom; - call->instances.count = count; -#ifdef USE_GPU_SELECT - call->select_id = DST.select_id; -#endif + GPUVertBuf *buf_inst = inst_attributes->verts[0]; + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); BLI_LINKS_APPEND(&shgroup->calls, call); -} - -void DRW_shgroup_call_generate_add(DRWShadingGroup *shgroup, - DRWCallGenerateFn *geometry_fn, - void *user_data, - float (*obmat)[4]) -{ - BLI_assert(geometry_fn != NULL); - BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)); - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); call->state = drw_call_state_create(shgroup, obmat, NULL); - call->type = DRW_CALL_GENERATE; - call->generate.geometry_fn = geometry_fn; - call->generate.user_data = user_data; + call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf_inst, geom); + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = buf_inst->vertex_len; #ifdef USE_GPU_SELECT call->select_id = DST.select_id; + call->inst_selectid = NULL; #endif - - BLI_LINKS_APPEND(&shgroup->calls, call); } -/* This function tests if the current draw engine draws the vertex colors - * It is used when drawing sculpts - * - * XXX: should we use a callback to a the draw engine to retrieve this - * setting, this makes the draw manager more clean? */ -static bool DRW_draw_vertex_color_active(const DRWContextState *draw_ctx) -{ - View3D *v3d = draw_ctx->v3d; - return v3d->shading.type == OB_SOLID && v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR; -} +// #define SCULPT_DEBUG_BUFFERS -static void sculpt_draw_cb(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom), - void *user_data) -{ - Object *ob = user_data; +typedef struct DRWSculptCallbackData { + Object *ob; + DRWShadingGroup **shading_groups; + bool use_wire; + bool use_mats; + bool use_mask; + bool fast_mode; /* Set by draw manager. Do not init. */ +#ifdef SCULPT_DEBUG_BUFFERS + int node_nr; +#endif +} DRWSculptCallbackData; + +#ifdef SCULPT_DEBUG_BUFFERS +# define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9]) +static float sculpt_debug_colors[9][4] = { + {1.0f, 0.2f, 0.2f, 1.0f}, + {0.2f, 1.0f, 0.2f, 1.0f}, + {0.2f, 0.2f, 1.0f, 1.0f}, + {1.0f, 1.0f, 0.2f, 1.0f}, + {0.2f, 1.0f, 1.0f, 1.0f}, + {1.0f, 0.2f, 1.0f, 1.0f}, + {1.0f, 0.7f, 0.2f, 1.0f}, + {0.2f, 1.0f, 0.7f, 1.0f}, + {0.7f, 0.2f, 1.0f, 1.0f}, +}; +#endif - /* XXX should be ensured before but sometime it's not... go figure (see T57040). */ - PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob); +static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers) +{ + GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); + short index = 0; - const DRWContextState *drwctx = DRW_context_state_get(); - int fast_mode = 0; + /* Meh... use_mask is a bit misleading here. */ + if (scd->use_mask && !GPU_pbvh_buffers_has_mask(buffers)) { + return; + } - if (drwctx->evil_C != NULL) { - Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); - if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING; - } + if (scd->use_mats) { + index = GPU_pbvh_buffers_material_index_get(buffers); } - if (pbvh) { - const bool show_vcol = DRW_draw_vertex_color_active(drwctx); - BKE_pbvh_draw_cb(pbvh, - NULL, - NULL, - fast_mode, - false, - false, - show_vcol, - (void (*)(void *, GPUBatch *))draw_fn, - shgroup); + DRWShadingGroup *shgrp = scd->shading_groups[index]; + if (geom != NULL && shgrp != NULL) { +#ifdef SCULPT_DEBUG_BUFFERS + /* Color each buffers in different colors. Only work in solid/Xray mode. */ + shgrp = DRW_shgroup_create_sub(shgrp); + DRW_shgroup_uniform_vec3(shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->node_nr++), 1); +#endif + /* DRW_shgroup_call_object_ex reuses matrices calculations for all the drawcalls of this + * object. */ + DRW_shgroup_call_object_ex(shgrp, geom, scd->ob, true); } } -static void sculpt_draw_wires_cb(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom), - void *user_data) +#ifdef SCULPT_DEBUG_BUFFERS +static void sculpt_debug_cb(void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag) { - Object *ob = user_data; + int *node_nr = (int *)user_data; + BoundBox bb; + BKE_boundbox_init_from_minmax(&bb, bmin, bmax); +# if 0 /* Nodes hierarchy. */ + if (flag & PBVH_Leaf) { + DRW_debug_bbox(&bb, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); + } + else { + DRW_debug_bbox(&bb, (float[4]){0.5f, 0.5f, 0.5f, 0.6f}); + } +# else /* Color coded leaf bounds. */ + if (flag & PBVH_Leaf) { + DRW_debug_bbox(&bb, SCULPT_DEBUG_COLOR((*node_nr)++)); + } +# endif +} +#endif + +static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol) +{ /* XXX should be ensured before but sometime it's not... go figure (see T57040). */ - PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob); + PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, scd->ob); + if (!pbvh) { + return; + } - const DRWContextState *drwctx = DRW_context_state_get(); - int fast_mode = 0; + float(*planes)[4] = NULL; /* TODO proper culling. */ + scd->fast_mode = false; + const DRWContextState *drwctx = DRW_context_state_get(); if (drwctx->evil_C != NULL) { Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C); if (p && (p->flags & PAINT_FAST_NAVIGATE)) { - fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING; + scd->fast_mode = (drwctx->rv3d->rflag & RV3D_NAVIGATING) != 0; } } - if (pbvh) { - BKE_pbvh_draw_cb(pbvh, - NULL, - NULL, - fast_mode, - true, - false, - false, - (void (*)(void *, GPUBatch *))draw_fn, - shgroup); - } + BKE_pbvh_draw_cb( + pbvh, planes, NULL, use_vcol, (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, scd); + +#ifdef SCULPT_DEBUG_BUFFERS + int node_nr = 0; + DRW_debug_modelmat(scd->ob->obmat); + BKE_pbvh_draw_debug_cb( + pbvh, + (void (*)(void *d, const float min[3], const float max[3], PBVHNodeFlags f))sculpt_debug_cb, + &node_nr); +#endif } -void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) +void DRW_shgroup_call_sculpt( + DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask, bool use_vcol) { - DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat); + DRWSculptCallbackData scd = { + .ob = ob, + .shading_groups = &shgroup, + .use_wire = use_wire, + .use_mats = false, + .use_mask = use_mask, + }; + drw_sculpt_generate_calls(&scd, use_vcol); } -void DRW_shgroup_call_sculpt_wires_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) +void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups, Object *ob, bool use_vcol) { - DRW_shgroup_call_generate_add(shgroup, sculpt_draw_wires_cb, ob, obmat); + DRWSculptCallbackData scd = { + .ob = ob, + .shading_groups = shgroups, + .use_wire = false, + .use_mats = true, + .use_mask = false, + }; + drw_sculpt_generate_calls(&scd, use_vcol); } -void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, - const void *attr[], - uint attr_len) +static GPUVertFormat inst_select_format = {0}; + +DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, + struct GPUVertFormat *format, + GPUPrimType prim_type) { + BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN)); + BLI_assert(format != NULL); + + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); + + call->state = drw_call_state_create(shgroup, NULL, NULL); + GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->vert_count); + call->batch = DRW_temp_batch_request(DST.idatalist, buf, prim_type); + call->vert_first = 0; + call->vert_count = 0; + call->inst_count = 0; + #ifdef USE_GPU_SELECT if (G.f & G_FLAG_PICKSEL) { - if (shgroup->instance_count == shgroup->inst_selectid->vertex_len) { - GPU_vertbuf_data_resize(shgroup->inst_selectid, shgroup->instance_count + 32); + /* Not actually used for rendering but alloced in one chunk. */ + if (inst_select_format.attr_len == 0) { + GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } - GPU_vertbuf_attr_set(shgroup->inst_selectid, 0, shgroup->instance_count, &DST.select_id); + call->inst_selectid = DRW_temp_buffer_request( + DST.idatalist, &inst_select_format, &call->vert_count); } #endif + return (DRWCallBuffer *)call; +} + +DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, + struct GPUVertFormat *format, + GPUBatch *geom) +{ + BLI_assert(geom != NULL); + BLI_assert(format != NULL); + + DRWCall *call = BLI_memblock_alloc(DST.vmempool->calls); + BLI_LINKS_APPEND(&shgroup->calls, call); - BLI_assert(attr_len == shgroup->attrs_count); + call->state = drw_call_state_create(shgroup, NULL, NULL); + GPUVertBuf *buf = DRW_temp_buffer_request(DST.idatalist, format, &call->inst_count); + call->batch = DRW_temp_batch_instance_request(DST.idatalist, buf, geom); + call->vert_first = 0; + call->vert_count = 0; /* Auto from batch. */ + call->inst_count = 0; + +#ifdef USE_GPU_SELECT + if (G.f & G_FLAG_PICKSEL) { + /* Not actually used for rendering but alloced in one chunk. */ + if (inst_select_format.attr_len == 0) { + GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); + } + call->inst_selectid = DRW_temp_buffer_request( + DST.idatalist, &inst_select_format, &call->inst_count); + } +#endif + return (DRWCallBuffer *)call; +} + +void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint attr_len) +{ + DRWCall *call = (DRWCall *)callbuf; + const bool is_instance = call->batch->inst != NULL; + GPUVertBuf *buf = is_instance ? call->batch->inst : call->batch->verts[0]; + uint count = is_instance ? call->inst_count++ : call->vert_count++; + const bool resize = (count == buf->vertex_alloc); + + BLI_assert(attr_len == buf->format.attr_len); UNUSED_VARS_NDEBUG(attr_len); + if (UNLIKELY(resize)) { + GPU_vertbuf_data_resize(buf, count + DRW_BUFFER_VERTS_CHUNK); + } + for (int i = 0; i < attr_len; ++i) { - if (shgroup->instance_count == shgroup->instance_vbo->vertex_len) { - GPU_vertbuf_data_resize(shgroup->instance_vbo, shgroup->instance_count + 32); - } - GPU_vertbuf_attr_set(shgroup->instance_vbo, i, shgroup->instance_count, attr[i]); + GPU_vertbuf_attr_set(buf, i, count, attr[i]); } - shgroup->instance_count += 1; +#ifdef USE_GPU_SELECT + if (G.f & G_FLAG_PICKSEL) { + if (UNLIKELY(resize)) { + GPU_vertbuf_data_resize(call->inst_selectid, count + DRW_BUFFER_VERTS_CHUNK); + } + GPU_vertbuf_attr_set(call->inst_selectid, 0, count, &DST.select_id); + } +#endif } /** \} */ @@ -756,17 +856,7 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) { - shgroup->instance_geom = NULL; - shgroup->instance_vbo = NULL; - shgroup->instance_count = 0; shgroup->uniforms = NULL; -#ifdef USE_GPU_SELECT - shgroup->inst_selectid = NULL; - shgroup->override_selectid = -1; -#endif -#ifndef NDEBUG - shgroup->attrs_count = 0; -#endif int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock"); @@ -776,178 +866,56 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) } else { /* Only here to support builtin shaders. This should not be used by engines. */ - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1); - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1); - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1); - drw_shgroup_builtin_uniform(shgroup, - GPU_UNIFORM_VIEWPROJECTION_INV, - DST.view_data.matstate.mat[DRW_MAT_PERSINV], - 16, - 1); - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1); - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1); - drw_shgroup_builtin_uniform( - shgroup, GPU_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2); + /* TODO remove. */ + DRWViewUboStorage *storage = &DST.view_storage_cpy; + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, storage->viewmat, 16, 1); + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, storage->viewinv, 16, 1); + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, storage->persmat, 16, 1); + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, storage->persinv, 16, 1); + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, storage->winmat, 16, 1); + drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, storage->wininv, 16, 1); } + /* Not supported. */ + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1); + BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1); + shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL); shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV); - shgroup->modelview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW); - shgroup->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV); shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); - shgroup->normalview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL); - shgroup->normalviewinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL_INV); - shgroup->normalworld = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_WORLDNORMAL); shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO); shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO); - shgroup->eye = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_EYE); shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID); shgroup->matflag = 0; if (shgroup->modelinverse > -1) { shgroup->matflag |= DRW_CALL_MODELINVERSE; } - if (shgroup->modelview > -1) { - shgroup->matflag |= DRW_CALL_MODELVIEW; - } - if (shgroup->modelviewinverse > -1) { - shgroup->matflag |= DRW_CALL_MODELVIEWINVERSE; - } if (shgroup->modelviewprojection > -1) { shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION; } - if (shgroup->normalview > -1) { - shgroup->matflag |= DRW_CALL_NORMALVIEW; - } - if (shgroup->normalviewinverse > -1) { - shgroup->matflag |= DRW_CALL_NORMALVIEWINVERSE; - } - if (shgroup->normalworld > -1) { - shgroup->matflag |= DRW_CALL_NORMALWORLD; - } if (shgroup->orcotexfac > -1) { shgroup->matflag |= DRW_CALL_ORCOTEXFAC; } if (shgroup->objectinfo > -1) { shgroup->matflag |= DRW_CALL_OBJECTINFO; } - if (shgroup->eye > -1) { - shgroup->matflag |= DRW_CALL_EYEVEC; - } -} - -static void drw_shgroup_instance_init(DRWShadingGroup *shgroup, - GPUShader *shader, - GPUBatch *batch, - GPUVertFormat *format) -{ - BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(batch != NULL); - BLI_assert(format != NULL); - - drw_shgroup_init(shgroup, shader); - - shgroup->instance_geom = batch; -#ifndef NDEBUG - shgroup->attrs_count = format->attr_len; -#endif - - DRW_instancing_buffer_request( - DST.idatalist, format, batch, shgroup, &shgroup->instance_geom, &shgroup->instance_vbo); - -#ifdef USE_GPU_SELECT - if (G.f & G_FLAG_PICKSEL) { - /* Not actually used for rendering but alloced in one chunk. - * Plus we don't have to care about ownership. */ - static GPUVertFormat inst_select_format = {0}; - if (inst_select_format.attr_len == 0) { - GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); - } - GPUBatch *batch_dummy; /* Not used */ - DRW_batching_buffer_request(DST.idatalist, - &inst_select_format, - GPU_PRIM_POINTS, - shgroup, - &batch_dummy, - &shgroup->inst_selectid); - } -#endif -} - -static void drw_shgroup_batching_init(DRWShadingGroup *shgroup, - GPUShader *shader, - GPUVertFormat *format) -{ - drw_shgroup_init(shgroup, shader); - -#ifndef NDEBUG - shgroup->attrs_count = (format != NULL) ? format->attr_len : 0; -#endif - BLI_assert(format != NULL); - - GPUPrimType type; - switch (shgroup->type) { - case DRW_SHG_POINT_BATCH: - type = GPU_PRIM_POINTS; - break; - case DRW_SHG_LINE_BATCH: - type = GPU_PRIM_LINES; - break; - case DRW_SHG_TRIANGLE_BATCH: - type = GPU_PRIM_TRIS; - break; - default: - type = GPU_PRIM_NONE; - BLI_assert(0); - break; - } - - DRW_batching_buffer_request( - DST.idatalist, format, type, shgroup, &shgroup->batch_geom, &shgroup->batch_vbo); - -#ifdef USE_GPU_SELECT - if (G.f & G_FLAG_PICKSEL) { - /* Not actually used for rendering but alloced in one chunk. */ - static GPUVertFormat inst_select_format = {0}; - if (inst_select_format.attr_len == 0) { - GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); - } - GPUBatch *batch; /* Not used */ - DRW_batching_buffer_request(DST.idatalist, - &inst_select_format, - GPU_PRIM_POINTS, - shgroup, - &batch, - &shgroup->inst_selectid); - } -#endif } static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) { - DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); + DRWShadingGroup *shgroup = BLI_memblock_alloc(DST.vmempool->shgroups); BLI_LINKS_APPEND(&pass->shgroups, shgroup); - shgroup->type = DRW_SHG_NORMAL; shgroup->shader = shader; shgroup->state_extra = 0; shgroup->state_extra_disable = ~0x0; shgroup->stencil_mask = 0; shgroup->calls.first = NULL; shgroup->calls.last = NULL; -#if 0 /* All the same in the union! */ - shgroup->batch_geom = NULL; - shgroup->batch_vbo = NULL; - - shgroup->instance_geom = NULL; - shgroup->instance_vbo = NULL; -#endif + shgroup->tfeedback_target = NULL; shgroup->pass_parent = pass; return shgroup; @@ -983,10 +951,9 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, GPUTexture *tex = NULL; if (input->ima) { - GPUTexture **tex_ref = BLI_mempool_alloc(DST.vmempool->images); + GPUTexture **tex_ref = BLI_memblock_alloc(DST.vmempool->images); - *tex_ref = tex = GPU_texture_from_blender( - input->ima, input->iuser, GL_TEXTURE_2D, input->image_isdata); + *tex_ref = tex = GPU_texture_from_blender(input->ima, input->iuser, GL_TEXTURE_2D); GPU_texture_ref(tex); } @@ -1033,218 +1000,536 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); drw_shgroup_material_inputs(shgroup, material); } - return shgroup; } -DRWShadingGroup *DRW_shgroup_material_instance_create( - struct GPUMaterial *material, DRWPass *pass, GPUBatch *geom, Object *ob, GPUVertFormat *format) +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) { - GPUPass *gpupass = GPU_material_get_pass(material); - DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); - - if (shgroup) { - shgroup->type = DRW_SHG_INSTANCE; - shgroup->instance_geom = geom; - drw_call_calc_orco(ob, shgroup->instance_orcofac); - drw_shgroup_instance_init(shgroup, GPU_pass_shader_get(gpupass), geom, format); - drw_shgroup_material_inputs(shgroup, material); - } + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + drw_shgroup_init(shgroup, shader); + return shgroup; +} +DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, + DRWPass *pass, + GPUVertBuf *tf_target) +{ + BLI_assert(tf_target != NULL); + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + drw_shgroup_init(shgroup, shader); + shgroup->tfeedback_target = tf_target; return shgroup; } -DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(struct GPUMaterial *material, - DRWPass *pass, - int tri_count) +/** + * State is added to #Pass.state while drawing. + * Use to temporarily enable draw options. + */ +void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) { -#ifdef USE_GPU_SELECT - BLI_assert((G.f & G_FLAG_PICKSEL) == 0); -#endif - GPUPass *gpupass = GPU_material_get_pass(material); - DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); + shgroup->state_extra |= state; +} - if (shgroup) { - /* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */ - drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass)); - shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->instance_count = tri_count * 3; - drw_shgroup_material_inputs(shgroup, material); - } +void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) +{ + shgroup->state_extra_disable &= ~state; +} - return shgroup; +void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask) +{ + BLI_assert(mask <= 255); + shgroup->stencil_mask = mask; } -DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) +bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) { - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - drw_shgroup_init(shgroup, shader); - return shgroup; + return shgroup->calls.first == NULL; } -DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, - DRWPass *pass, - GPUBatch *geom, - GPUVertFormat *format) +DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) { - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - shgroup->type = DRW_SHG_INSTANCE; - shgroup->instance_geom = geom; - drw_call_calc_orco(NULL, shgroup->instance_orcofac); - drw_shgroup_instance_init(shgroup, shader, geom, format); + /* Remove this assertion if needed but implement the other cases first! */ + DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups); - return shgroup; + *shgroup_new = *shgroup; + shgroup_new->uniforms = NULL; + shgroup_new->calls.first = NULL; + shgroup_new->calls.last = NULL; + + BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new); + + return shgroup_new; } -DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass) -{ - DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTR_FLOAT, 3}}); +/** \} */ - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - shgroup->type = DRW_SHG_POINT_BATCH; +/* -------------------------------------------------------------------- */ +/** \name View (DRW_view) + * \{ */ + +/* Extract the 8 corners from a Projection Matrix. + * Although less accurate, this solution can be simplified as follows: + * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const + * float[3]){1.0f, 1.0f, 1.0f}); for (int i = 0; i < 8; i++) {mul_project_m4_v3(projinv, + * bbox.vec[i]);} + */ +static void draw_frustum_boundbox_calc(const float (*viewinv)[4], + const float (*projmat)[4], + BoundBox *r_bbox) +{ + float left, right, bottom, top, near, far; + bool is_persp = projmat[3][3] == 0.0f; + +#if 0 /* Equivalent to this but it has accuracy problems. */ + BKE_boundbox_init_from_minmax( + &bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f}); + for (int i = 0; i < 8; i++) { + mul_project_m4_v3(projinv, bbox.vec[i]); + } +#endif - drw_shgroup_batching_init(shgroup, shader, g_pos_format); + projmat_dimensions(projmat, &left, &right, &bottom, &top, &near, &far); - return shgroup; + if (is_persp) { + left *= near; + right *= near; + bottom *= near; + top *= near; + } + + r_bbox->vec[0][2] = r_bbox->vec[3][2] = r_bbox->vec[7][2] = r_bbox->vec[4][2] = -near; + r_bbox->vec[0][0] = r_bbox->vec[3][0] = left; + r_bbox->vec[4][0] = r_bbox->vec[7][0] = right; + r_bbox->vec[0][1] = r_bbox->vec[4][1] = bottom; + r_bbox->vec[7][1] = r_bbox->vec[3][1] = top; + + /* Get the coordinates of the far plane. */ + if (is_persp) { + float sca_far = far / near; + left *= sca_far; + right *= sca_far; + bottom *= sca_far; + top *= sca_far; + } + + r_bbox->vec[1][2] = r_bbox->vec[2][2] = r_bbox->vec[6][2] = r_bbox->vec[5][2] = -far; + r_bbox->vec[1][0] = r_bbox->vec[2][0] = left; + r_bbox->vec[6][0] = r_bbox->vec[5][0] = right; + r_bbox->vec[1][1] = r_bbox->vec[5][1] = bottom; + r_bbox->vec[2][1] = r_bbox->vec[6][1] = top; + + /* Transform into world space. */ + for (int i = 0; i < 8; i++) { + mul_m4_v3(viewinv, r_bbox->vec[i]); + } +} + +static void draw_frustum_culling_planes_calc(const BoundBox *bbox, float (*frustum_planes)[4]) +{ + /* TODO See if planes_from_projmat cannot do the job. */ + + /* Compute clip planes using the world space frustum corners. */ + for (int p = 0; p < 6; p++) { + int q, r, s; + switch (p) { + case 0: + q = 1; + r = 2; + s = 3; + break; /* -X */ + case 1: + q = 0; + r = 4; + s = 5; + break; /* -Y */ + case 2: + q = 1; + r = 5; + s = 6; + break; /* +Z (far) */ + case 3: + q = 2; + r = 6; + s = 7; + break; /* +Y */ + case 4: + q = 0; + r = 3; + s = 7; + break; /* -Z (near) */ + default: + q = 4; + r = 7; + s = 6; + break; /* +X */ + } + + normal_quad_v3(frustum_planes[p], bbox->vec[p], bbox->vec[q], bbox->vec[r], bbox->vec[s]); + /* Increase precision and use the mean of all 4 corners. */ + frustum_planes[p][3] = -dot_v3v3(frustum_planes[p], bbox->vec[p]); + frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[q]); + frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[r]); + frustum_planes[p][3] += -dot_v3v3(frustum_planes[p], bbox->vec[s]); + frustum_planes[p][3] *= 0.25f; + } } -DRWShadingGroup *DRW_shgroup_line_batch_create_with_format(struct GPUShader *shader, - DRWPass *pass, - GPUVertFormat *format) +static void draw_frustum_bound_sphere_calc(const BoundBox *bbox, + const float (*viewinv)[4], + const float (*projmat)[4], + const float (*projinv)[4], + BoundSphere *bsphere) { - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - shgroup->type = DRW_SHG_LINE_BATCH; + /* Extract Bounding Sphere */ + if (projmat[3][3] != 0.0f) { + /* Orthographic */ + /* The most extreme points on the near and far plane. (normalized device coords). */ + const float *nearpoint = bbox->vec[0]; + const float *farpoint = bbox->vec[6]; - drw_shgroup_batching_init(shgroup, shader, format); + /* just use median point */ + mid_v3_v3v3(bsphere->center, farpoint, nearpoint); + bsphere->radius = len_v3v3(bsphere->center, farpoint); + } + else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) { + /* Perspective with symmetrical frustum. */ - return shgroup; + /* We obtain the center and radius of the circumscribed circle of the + * isosceles trapezoid composed by the diagonals of the near and far clipping plane */ + + /* center of each clipping plane */ + float mid_min[3], mid_max[3]; + mid_v3_v3v3(mid_min, bbox->vec[3], bbox->vec[4]); + mid_v3_v3v3(mid_max, bbox->vec[2], bbox->vec[5]); + + /* square length of the diagonals of each clipping plane */ + float a_sq = len_squared_v3v3(bbox->vec[3], bbox->vec[4]); + float b_sq = len_squared_v3v3(bbox->vec[2], bbox->vec[5]); + + /* distance squared between clipping planes */ + float h_sq = len_squared_v3v3(mid_min, mid_max); + + float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq); + + /* The goal is to get the smallest sphere, + * not the sphere that passes through each corner */ + CLAMP(fac, 0.0f, 1.0f); + + interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac); + + /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */ + bsphere->radius = len_v3v3(bsphere->center, bbox->vec[1]); + } + else { + /* Perspective with asymmetrical frustum. */ + + /* We put the sphere center on the line that goes from origin + * to the center of the far clipping plane. */ + + /* Detect which of the corner of the far clipping plane is the farthest to the origin */ + float nfar[4]; /* most extreme far point in NDC space */ + float farxy[2]; /* farpoint projection onto the near plane */ + float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */ + float nearpoint[3]; /* most extreme near point in camera coordinate */ + float farcenter[3] = {0.0f}; /* center of far cliping plane in camera coordinate */ + float F = -1.0f, N; /* square distance of far and near point to origin */ + float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */ + float e, s; /* far and near clipping distance (<0) */ + float c; /* slope of center line = distance of far clipping center + * to z axis / far clipping distance. */ + float z; /* projection of sphere center on z axis (<0) */ + + /* Find farthest corner and center of far clip plane. */ + float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */ + for (int i = 0; i < 4; i++) { + float point[3]; + mul_v3_project_m4_v3(point, projinv, corner); + float len = len_squared_v3(point); + if (len > F) { + copy_v3_v3(nfar, corner); + copy_v3_v3(farpoint, point); + F = len; + } + add_v3_v3(farcenter, point); + /* rotate by 90 degree to walk through the 4 points of the far clip plane */ + float tmp = corner[0]; + corner[0] = -corner[1]; + corner[1] = tmp; + } + + /* the far center is the average of the far clipping points */ + mul_v3_fl(farcenter, 0.25f); + /* the extreme near point is the opposite point on the near clipping plane */ + copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f); + mul_v3_project_m4_v3(nearpoint, projinv, nfar); + /* this is a frustum projection */ + N = len_squared_v3(nearpoint); + e = farpoint[2]; + s = nearpoint[2]; + /* distance to view Z axis */ + f = len_v2(farpoint); + /* get corresponding point on the near plane */ + mul_v2_v2fl(farxy, farpoint, s / e); + /* this formula preserve the sign of n */ + sub_v2_v2(nearpoint, farxy); + n = f * s / e - len_v2(nearpoint); + c = len_v2(farcenter) / e; + /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */ + z = (F - N) / (2.0f * (e - s + c * (f - n))); + + bsphere->center[0] = farcenter[0] * z / e; + bsphere->center[1] = farcenter[1] * z / e; + bsphere->center[2] = z; + bsphere->radius = len_v3v3(bsphere->center, farpoint); + + /* Transform to world space. */ + mul_m4_v3(viewinv, bsphere->center); + } } -DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass) +static void draw_view_matrix_state_update(DRWViewUboStorage *storage, + const float viewmat[4][4], + const float winmat[4][4]) { - DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTR_FLOAT, 3}}); + /* If only one the matrices is negative, then the + * polygon winding changes and we don't want that. */ + BLI_assert(is_negative_m4(viewmat) != is_negative_m4(winmat)); + + copy_m4_m4(storage->viewmat, viewmat); + invert_m4_m4(storage->viewinv, storage->viewmat); - return DRW_shgroup_line_batch_create_with_format(shader, pass, g_pos_format); + copy_m4_m4(storage->winmat, winmat); + invert_m4_m4(storage->wininv, storage->winmat); + + mul_m4_m4m4(storage->persmat, winmat, viewmat); + invert_m4_m4(storage->persinv, storage->persmat); } -/** - * Very special batch. Use this if you position - * your vertices with the vertex shader - * and dont need any VBO attribute. - */ -DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, - DRWPass *pass, - int tri_count) +/* Create a view with culling. */ +DRWView *DRW_view_create(const float viewmat[4][4], + const float winmat[4][4], + const float (*culling_viewmat)[4], + const float (*culling_winmat)[4], + DRWCallVisibilityFn *visibility_fn) { -#ifdef USE_GPU_SELECT - BLI_assert((G.f & G_FLAG_PICKSEL) == 0); -#endif - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + DRWView *view = BLI_memblock_alloc(DST.vmempool->views); - /* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */ - drw_shgroup_init(shgroup, shader); + if (DST.primary_view_ct < MAX_CULLED_VIEWS) { + view->culling_mask = 1u << DST.primary_view_ct++; + } + else { + BLI_assert(0); + view->culling_mask = 0u; + } + view->clip_planes_len = 0; + view->visibility_fn = visibility_fn; + view->parent = NULL; - shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->instance_count = tri_count * 3; + copy_v4_fl4(view->storage.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); - return shgroup; + DRW_view_update(view, viewmat, winmat, culling_viewmat, culling_winmat); + + return view; } -DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, - DRWPass *pass, - GPUVertBuf *tf_target) +/* Create a view with culling done by another view. */ +DRWView *DRW_view_create_sub(const DRWView *parent_view, + const float viewmat[4][4], + const float winmat[4][4]) { - BLI_assert(tf_target != NULL); - DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); - shgroup->type = DRW_SHG_FEEDBACK_TRANSFORM; + BLI_assert(parent_view && parent_view->parent == NULL); - drw_shgroup_init(shgroup, shader); + DRWView *view = BLI_memblock_alloc(DST.vmempool->views); - shgroup->tfeedback_target = tf_target; + /* Perform copy. */ + *view = *parent_view; + view->parent = (DRWView *)parent_view; - return shgroup; + DRW_view_update_sub(view, viewmat, winmat); + + return view; } /** - * Specify an external batch instead of adding each attribute one by one. - */ -void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct GPUBatch *batch) + * DRWView Update: + * This is meant to be done on existing views when rendering in a loop and there is no + * need to allocate more DRWViews. + **/ + +/* Update matrices of a view created with DRW_view_create_sub. */ +void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]) { - BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(shgroup->instance_count == 0); - /* You cannot use external instancing batch without a dummy format. */ - BLI_assert(shgroup->attrs_count != 0); + BLI_assert(view->parent != NULL); - shgroup->type = DRW_SHG_INSTANCE_EXTERNAL; - drw_call_calc_orco(NULL, shgroup->instance_orcofac); - /* PERF : This destroys the vaos cache so better check if it's necessary. */ - /* Note: This WILL break if batch->verts[0] is destroyed and reallocated - * at the same address. Bindings/VAOs would remain obsolete. */ - // if (shgroup->instancing_geom->inst != batch->verts[0]) - GPU_batch_instbuf_set(shgroup->instance_geom, batch->verts[0], false); + view->is_dirty = true; -#ifdef USE_GPU_SELECT - shgroup->override_selectid = DST.select_id; + draw_view_matrix_state_update(&view->storage, viewmat, winmat); +} + +/* Update matrices of a view created with DRW_view_create. */ +void DRW_view_update(DRWView *view, + const float viewmat[4][4], + const float winmat[4][4], + const float (*culling_viewmat)[4], + const float (*culling_winmat)[4]) +{ + /* DO NOT UPDATE THE DEFAULT VIEW. + * Create subviews instead, or a copy. */ + BLI_assert(view != DST.view_default); + BLI_assert(view->parent == NULL); + + view->is_dirty = true; + + draw_view_matrix_state_update(&view->storage, viewmat, winmat); + + /* Prepare frustum culling. */ + +#ifdef DRW_DEBUG_CULLING + static float mv[MAX_CULLED_VIEWS][4][4], mw[MAX_CULLED_VIEWS][4][4]; + + /* Select view here. */ + if (view->culling_mask != 0) { + uint index = bitscan_forward_uint(view->culling_mask); + + if (G.debug_value == 0) { + copy_m4_m4(mv[index], culling_viewmat ? culling_viewmat : viewmat); + copy_m4_m4(mw[index], culling_winmat ? culling_winmat : winmat); + } + else { + culling_winmat = mw[index]; + culling_viewmat = mv[index]; + } + } +#endif + + float wininv[4][4]; + if (culling_winmat) { + winmat = culling_winmat; + invert_m4_m4(wininv, winmat); + } + else { + copy_m4_m4(wininv, view->storage.wininv); + } + + float viewinv[4][4]; + if (culling_viewmat) { + viewmat = culling_viewmat; + invert_m4_m4(viewinv, viewmat); + } + else { + copy_m4_m4(viewinv, view->storage.viewinv); + } + + draw_frustum_boundbox_calc(viewinv, winmat, &view->frustum_corners); + draw_frustum_culling_planes_calc(&view->frustum_corners, view->frustum_planes); + draw_frustum_bound_sphere_calc( + &view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere); + +#ifdef DRW_DEBUG_CULLING + if (G.debug_value != 0) { + DRW_debug_sphere( + view->frustum_bsphere.center, view->frustum_bsphere.radius, (const float[4]){1, 1, 0, 1}); + DRW_debug_bbox(&view->frustum_corners, (const float[4]){1, 1, 0, 1}); + } #endif } -uint DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup) +/* Return default view if it is a viewport render. */ +const DRWView *DRW_view_default_get(void) { - return shgroup->instance_count; + return DST.view_default; +} + +/* MUST only be called once per render and only in render mode. Sets default view. */ +void DRW_view_default_set(DRWView *view) +{ + BLI_assert(DST.view_default == NULL); + DST.view_default = view; } /** - * State is added to #Pass.state while drawing. - * Use to temporarily enable draw options. + * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES, + * and if the shaders have support for it (see usage of gl_ClipDistance). + * NOTE: planes must be in world space. */ -void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) +void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len) { - shgroup->state_extra |= state; + BLI_assert(plane_len <= MAX_CLIP_PLANES); + view->clip_planes_len = plane_len; + if (plane_len > 0) { + memcpy(view->storage.clipplanes, planes, sizeof(float) * 4 * plane_len); + } } -void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) +void DRW_view_camtexco_set(DRWView *view, float texco[4]) { - shgroup->state_extra_disable &= ~state; + copy_v4_v4(view->storage.viewcamtexcofac, texco); } -void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask) +/* Return world space frustum corners. */ +void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners) { - BLI_assert(mask <= 255); - shgroup->stencil_mask = mask; + memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners)); } -bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) +/* Return world space frustum sides as planes. + * See draw_frustum_culling_planes_calc() for the plane order. */ +void DRW_view_frustum_planes_get(const DRWView *view, float planes[6][4]) { - switch (shgroup->type) { - case DRW_SHG_NORMAL: - case DRW_SHG_FEEDBACK_TRANSFORM: - return shgroup->calls.first == NULL; - case DRW_SHG_POINT_BATCH: - case DRW_SHG_LINE_BATCH: - case DRW_SHG_TRIANGLE_BATCH: - case DRW_SHG_INSTANCE: - case DRW_SHG_INSTANCE_EXTERNAL: - return shgroup->instance_count == 0; - } - BLI_assert(!"Shading Group type not supported"); - return true; + memcpy(planes, &view->frustum_planes, sizeof(view->frustum_planes)); } -DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) +bool DRW_view_is_persp_get(const DRWView *view) { - /* Remove this assertion if needed but implement the other cases first! */ - BLI_assert(shgroup->type == DRW_SHG_NORMAL); + view = (view) ? view : DST.view_default; + return view->storage.winmat[3][3] == 0.0f; +} - DRWShadingGroup *shgroup_new = BLI_mempool_alloc(DST.vmempool->shgroups); +float DRW_view_near_distance_get(const DRWView *view) +{ + view = (view) ? view : DST.view_default; + const float(*projmat)[4] = view->storage.winmat; - *shgroup_new = *shgroup; - shgroup_new->uniforms = NULL; - shgroup_new->calls.first = NULL; - shgroup_new->calls.last = NULL; + if (DRW_view_is_persp_get(view)) { + return -projmat[3][2] / (projmat[2][2] - 1.0f); + } + else { + return -(projmat[3][2] + 1.0f) / projmat[2][2]; + } +} - BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new); +float DRW_view_far_distance_get(const DRWView *view) +{ + view = (view) ? view : DST.view_default; + const float(*projmat)[4] = view->storage.winmat; - return shgroup_new; + if (DRW_view_is_persp_get(view)) { + return -projmat[3][2] / (projmat[2][2] + 1.0f); + } + else { + return -(projmat[3][2] - 1.0f) / projmat[2][2]; + } +} + +void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse) +{ + view = (view) ? view : DST.view_default; + const DRWViewUboStorage *storage = &view->storage; + copy_m4_m4(mat, (inverse) ? storage->viewinv : storage->viewmat); +} + +void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse) +{ + view = (view) ? view : DST.view_default; + const DRWViewUboStorage *storage = &view->storage; + copy_m4_m4(mat, (inverse) ? storage->wininv : storage->winmat); +} + +void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse) +{ + view = (view) ? view : DST.view_default; + const DRWViewUboStorage *storage = &view->storage; + copy_m4_m4(mat, (inverse) ? storage->persinv : storage->persmat); } /** \} */ @@ -1255,7 +1540,7 @@ DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) DRWPass *DRW_pass_create(const char *name, DRWState state) { - DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes); + DRWPass *pass = BLI_memblock_alloc(DST.vmempool->passes); pass->state = state; if (((G.debug_value > 20) && (G.debug_value < 30)) || (G.debug & G_DEBUG)) { BLI_strncpy(pass->name, name, MAX_PASS_NAME); @@ -1292,12 +1577,6 @@ void DRW_pass_state_remove(DRWPass *pass, DRWState state) pass->state &= ~state; } -void DRW_pass_free(DRWPass *pass) -{ - pass->shgroups.first = NULL; - pass->shgroups.last = NULL; -} - void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData) @@ -1308,8 +1587,8 @@ void DRW_pass_foreach_shgroup(DRWPass *pass, } typedef struct ZSortData { - float *axis; - float *origin; + const float *axis; + const float *origin; } ZSortData; static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) @@ -1372,8 +1651,7 @@ static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) */ void DRW_pass_sort_shgroup_z(DRWPass *pass) { - float(*viewinv)[4]; - viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV]; + const float(*viewinv)[4] = DST.view_active->storage.viewinv; ZSortData zsortdata = {viewinv[2], viewinv[3]}; diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 8e23a616ff5..7c53d8f4fff 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -23,13 +23,14 @@ #include "draw_manager.h" #include "BLI_math_bits.h" -#include "BLI_mempool.h" +#include "BLI_memblock.h" #include "BKE_global.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "intern/gpu_shader_private.h" +#include "intern/gpu_primitive_private.h" #ifdef USE_GPU_SELECT # include "GPU_select.h" @@ -167,18 +168,11 @@ void drw_state_set(DRWState state) /* Wire Width */ { int test; - if (CHANGED_ANY_STORE_VAR(DRW_STATE_WIRE | DRW_STATE_WIRE_WIDE | DRW_STATE_WIRE_SMOOTH, - test)) { - if (test & DRW_STATE_WIRE_WIDE) { - GPU_line_width(3.0f); - } - else if (test & DRW_STATE_WIRE_SMOOTH) { + if ((test = CHANGED_TO(DRW_STATE_WIRE_SMOOTH))) { + if (test == 1) { GPU_line_width(2.0f); GPU_line_smooth(true); } - else if (test & DRW_STATE_WIRE) { - GPU_line_width(1.0f); - } else { GPU_line_width(1.0f); GPU_line_smooth(false); @@ -186,20 +180,6 @@ void drw_state_set(DRWState state) } } - /* Points Size */ - { - int test; - if ((test = CHANGED_TO(DRW_STATE_POINT))) { - if (test == 1) { - GPU_enable_program_point_size(); - glPointSize(5.0f); - } - else { - GPU_disable_program_point_size(); - } - } - } - /* Blending (all buffer) */ { int test; @@ -258,7 +238,7 @@ void drw_state_set(DRWState state) int test; if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) { if (test == 1) { - for (int i = 0; i < DST.clip_planes_len; ++i) { + for (int i = 0; i < DST.view_active->clip_planes_len; ++i) { glEnable(GL_CLIP_DISTANCE0 + i); } } @@ -400,320 +380,67 @@ void DRW_state_reset(void) { DRW_state_reset_ex(DRW_STATE_DEFAULT); + GPU_point_size(5); + GPU_enable_program_point_size(); + /* Reset blending function */ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } -/* NOTE : Make sure to reset after use! */ -void DRW_state_invert_facing(void) -{ - SWAP(GLenum, DST.backface, DST.frontface); - glFrontFace(DST.frontface); -} - -/** - * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES, - * and if the shaders have support for it (see usage of gl_ClipDistance). - * Be sure to call DRW_state_clip_planes_reset() after you finish drawing. - */ -void DRW_state_clip_planes_len_set(uint plane_len) -{ - BLI_assert(plane_len <= MAX_CLIP_PLANES); - DST.clip_planes_len = plane_len; -} - -void DRW_state_clip_planes_reset(void) -{ - DST.clip_planes_len = 0; -} - -void DRW_state_clip_planes_set_from_rv3d(RegionView3D *rv3d) -{ - int max_len = 6; - int real_len = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : max_len; - while (real_len < max_len) { - /* Fill in dummy values that wont change results (6 is hard coded in shaders). */ - copy_v4_v4(rv3d->clip[real_len], rv3d->clip[3]); - real_len++; - } - - DRW_state_clip_planes_len_set(max_len); -} - /** \} */ /* -------------------------------------------------------------------- */ -/** \name Clipping (DRW_clipping) +/** \name Culling (DRW_culling) * \{ */ -/* Extract the 8 corners from a Projection Matrix. - * Although less accurate, this solution can be simplified as follows: - * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const - * float[3]){1.0f, 1.0f, 1.0f}); for (int i = 0; i < 8; i++) {mul_project_m4_v3(projinv, - * bbox.vec[i]);} - */ -static void draw_frustum_boundbox_calc(const float (*projmat)[4], BoundBox *r_bbox) +static bool draw_call_is_culled(DRWCall *call, DRWView *view) { - float left, right, bottom, top, near, far; - bool is_persp = projmat[3][3] == 0.0f; - - projmat_dimensions(projmat, &left, &right, &bottom, &top, &near, &far); - - if (is_persp) { - left *= near; - right *= near; - bottom *= near; - top *= near; - } - - r_bbox->vec[0][2] = r_bbox->vec[3][2] = r_bbox->vec[7][2] = r_bbox->vec[4][2] = -near; - r_bbox->vec[0][0] = r_bbox->vec[3][0] = left; - r_bbox->vec[4][0] = r_bbox->vec[7][0] = right; - r_bbox->vec[0][1] = r_bbox->vec[4][1] = bottom; - r_bbox->vec[7][1] = r_bbox->vec[3][1] = top; - - /* Get the coordinates of the far plane. */ - if (is_persp) { - float sca_far = far / near; - left *= sca_far; - right *= sca_far; - bottom *= sca_far; - top *= sca_far; - } - - r_bbox->vec[1][2] = r_bbox->vec[2][2] = r_bbox->vec[6][2] = r_bbox->vec[5][2] = -far; - r_bbox->vec[1][0] = r_bbox->vec[2][0] = left; - r_bbox->vec[6][0] = r_bbox->vec[5][0] = right; - r_bbox->vec[1][1] = r_bbox->vec[5][1] = bottom; - r_bbox->vec[2][1] = r_bbox->vec[6][1] = top; + return (call->state->culling->mask & view->culling_mask) != 0; } -static void draw_clipping_setup_from_view(void) +/* Set active view for rendering. */ +void DRW_view_set_active(DRWView *view) { - if (DST.clipping.updated) { - return; - } - - float(*viewinv)[4] = DST.view_data.matstate.mat[DRW_MAT_VIEWINV]; - float(*projmat)[4] = DST.view_data.matstate.mat[DRW_MAT_WIN]; - float(*projinv)[4] = DST.view_data.matstate.mat[DRW_MAT_WININV]; - BoundSphere *bsphere = &DST.clipping.frustum_bsphere; - - /* Extract Clipping Planes */ - BoundBox bbox; -#if 0 /* It has accuracy problems. */ - BKE_boundbox_init_from_minmax( - &bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f}); - for (int i = 0; i < 8; i++) { - mul_project_m4_v3(projinv, bbox.vec[i]); - } -#else - draw_frustum_boundbox_calc(projmat, &bbox); -#endif - /* Transform into world space. */ - for (int i = 0; i < 8; i++) { - mul_m4_v3(viewinv, bbox.vec[i]); - } - - memcpy(&DST.clipping.frustum_corners, &bbox, sizeof(BoundBox)); - - /* Compute clip planes using the world space frustum corners. */ - for (int p = 0; p < 6; p++) { - int q, r, s; - switch (p) { - case 0: - q = 1; - r = 2; - s = 3; - break; /* -X */ - case 1: - q = 0; - r = 4; - s = 5; - break; /* -Y */ - case 2: - q = 1; - r = 5; - s = 6; - break; /* +Z (far) */ - case 3: - q = 2; - r = 6; - s = 7; - break; /* +Y */ - case 4: - q = 0; - r = 3; - s = 7; - break; /* -Z (near) */ - default: - q = 4; - r = 7; - s = 6; - break; /* +X */ - } - if (DST.frontface == GL_CW) { - SWAP(int, q, s); - } - - normal_quad_v3( - DST.clipping.frustum_planes[p], bbox.vec[p], bbox.vec[q], bbox.vec[r], bbox.vec[s]); - /* Increase precision and use the mean of all 4 corners. */ - DST.clipping.frustum_planes[p][3] = -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[p]); - DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[q]); - DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[r]); - DST.clipping.frustum_planes[p][3] += -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[s]); - DST.clipping.frustum_planes[p][3] *= 0.25f; - } - - /* Extract Bounding Sphere */ - if (projmat[3][3] != 0.0f) { - /* Orthographic */ - /* The most extreme points on the near and far plane. (normalized device coords). */ - float *nearpoint = bbox.vec[0]; - float *farpoint = bbox.vec[6]; - - /* just use median point */ - mid_v3_v3v3(bsphere->center, farpoint, nearpoint); - bsphere->radius = len_v3v3(bsphere->center, farpoint); - } - else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) { - /* Perspective with symmetrical frustum. */ - - /* We obtain the center and radius of the circumscribed circle of the - * isosceles trapezoid composed by the diagonals of the near and far clipping plane */ - - /* center of each clipping plane */ - float mid_min[3], mid_max[3]; - mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]); - mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]); - - /* square length of the diagonals of each clipping plane */ - float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]); - float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]); - - /* distance squared between clipping planes */ - float h_sq = len_squared_v3v3(mid_min, mid_max); - - float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq); - - /* The goal is to get the smallest sphere, - * not the sphere that passes through each corner */ - CLAMP(fac, 0.0f, 1.0f); - - interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac); - - /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */ - bsphere->radius = len_v3v3(bsphere->center, bbox.vec[1]); - } - else { - /* Perspective with asymmetrical frustum. */ - - /* We put the sphere center on the line that goes from origin - * to the center of the far clipping plane. */ - - /* Detect which of the corner of the far clipping plane is the farthest to the origin */ - float nfar[4]; /* most extreme far point in NDC space */ - float farxy[2]; /* farpoint projection onto the near plane */ - float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */ - float nearpoint[3]; /* most extreme near point in camera coordinate */ - float farcenter[3] = {0.0f}; /* center of far cliping plane in camera coordinate */ - float F = -1.0f, N; /* square distance of far and near point to origin */ - float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */ - float e, s; /* far and near clipping distance (<0) */ - float c; /* slope of center line = distance of far clipping center - * to z axis / far clipping distance. */ - float z; /* projection of sphere center on z axis (<0) */ - - /* Find farthest corner and center of far clip plane. */ - float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */ - for (int i = 0; i < 4; i++) { - float point[3]; - mul_v3_project_m4_v3(point, projinv, corner); - float len = len_squared_v3(point); - if (len > F) { - copy_v3_v3(nfar, corner); - copy_v3_v3(farpoint, point); - F = len; - } - add_v3_v3(farcenter, point); - /* rotate by 90 degree to walk through the 4 points of the far clip plane */ - float tmp = corner[0]; - corner[0] = -corner[1]; - corner[1] = tmp; - } - - /* the far center is the average of the far clipping points */ - mul_v3_fl(farcenter, 0.25f); - /* the extreme near point is the opposite point on the near clipping plane */ - copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f); - mul_v3_project_m4_v3(nearpoint, projinv, nfar); - /* this is a frustum projection */ - N = len_squared_v3(nearpoint); - e = farpoint[2]; - s = nearpoint[2]; - /* distance to view Z axis */ - f = len_v2(farpoint); - /* get corresponding point on the near plane */ - mul_v2_v2fl(farxy, farpoint, s / e); - /* this formula preserve the sign of n */ - sub_v2_v2(nearpoint, farxy); - n = f * s / e - len_v2(nearpoint); - c = len_v2(farcenter) / e; - /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */ - z = (F - N) / (2.0f * (e - s + c * (f - n))); - - bsphere->center[0] = farcenter[0] * z / e; - bsphere->center[1] = farcenter[1] * z / e; - bsphere->center[2] = z; - bsphere->radius = len_v3v3(bsphere->center, farpoint); - - /* Transform to world space. */ - mul_m4_v3(viewinv, bsphere->center); - } - - DST.clipping.updated = true; + DST.view_active = (view) ? view : DST.view_default; } /* Return True if the given BoundSphere intersect the current view frustum */ -bool DRW_culling_sphere_test(BoundSphere *bsphere) +static bool draw_culling_sphere_test(const BoundSphere *frustum_bsphere, + const float (*frustum_planes)[4], + const BoundSphere *bsphere) { - draw_clipping_setup_from_view(); - /* Bypass test if radius is negative. */ if (bsphere->radius < 0.0f) { return true; } /* Do a rough test first: Sphere VS Sphere intersect. */ - BoundSphere *frustum_bsphere = &DST.clipping.frustum_bsphere; - float center_dist = len_squared_v3v3(bsphere->center, frustum_bsphere->center); - if (center_dist > SQUARE(bsphere->radius + frustum_bsphere->radius)) { + float center_dist_sq = len_squared_v3v3(bsphere->center, frustum_bsphere->center); + float radius_sum = bsphere->radius + frustum_bsphere->radius; + if (center_dist_sq > SQUARE(radius_sum)) { return false; } + /* TODO we could test against the inscribed sphere of the frustum to early out positively. */ /* Test against the 6 frustum planes. */ + /* TODO order planes with sides first then far then near clip. Should be better culling + * heuristic when sculpting. */ for (int p = 0; p < 6; p++) { - float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bsphere->center); + float dist = plane_point_side_v3(frustum_planes[p], bsphere->center); if (dist < -bsphere->radius) { return false; } } - return true; } -/* Return True if the given BoundBox intersect the current view frustum. - * bbox must be in world space. */ -bool DRW_culling_box_test(BoundBox *bbox) +static bool draw_culling_box_test(const float (*frustum_planes)[4], const BoundBox *bbox) { - draw_clipping_setup_from_view(); - /* 6 view frustum planes */ for (int p = 0; p < 6; p++) { /* 8 box vertices. */ for (int v = 0; v < 8; v++) { - float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bbox->vec[v]); + float dist = plane_point_side_v3(frustum_planes[p], bbox->vec[v]); if (dist > 0.0f) { /* At least one point in front of this plane. * Go to next plane. */ @@ -725,202 +452,166 @@ bool DRW_culling_box_test(BoundBox *bbox) } } } - return true; } -/* Return True if the current view frustum is inside or intersect the given plane */ -bool DRW_culling_plane_test(float plane[4]) +static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4]) { - draw_clipping_setup_from_view(); - /* Test against the 8 frustum corners. */ for (int c = 0; c < 8; c++) { - float dist = plane_point_side_v3(plane, DST.clipping.frustum_corners.vec[c]); + float dist = plane_point_side_v3(plane, corners->vec[c]); if (dist < 0.0f) { return true; } } - return false; } -void DRW_culling_frustum_corners_get(BoundBox *corners) +/* Return True if the given BoundSphere intersect the current view frustum. + * bsphere must be in world space. */ +bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere) { - draw_clipping_setup_from_view(); - memcpy(corners, &DST.clipping.frustum_corners, sizeof(BoundBox)); + view = view ? view : DST.view_default; + return draw_culling_sphere_test(&view->frustum_bsphere, view->frustum_planes, bsphere); } -/* See draw_clipping_setup_from_view() for the plane order. */ -void DRW_culling_frustum_planes_get(float planes[6][4]) +/* Return True if the given BoundBox intersect the current view frustum. + * bbox must be in world space. */ +bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox) { - draw_clipping_setup_from_view(); - memcpy(planes, &DST.clipping.frustum_planes, sizeof(DST.clipping.frustum_planes)); + view = view ? view : DST.view_default; + return draw_culling_box_test(view->frustum_planes, bbox); } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Draw (DRW_draw) - * \{ */ - -static void draw_visibility_eval(DRWCallState *st) +/* Return True if the view frustum is inside or intersect the given plane. + * plane must be in world space. */ +bool DRW_culling_plane_test(const DRWView *view, const float plane[4]) { - bool culled = st->flag & DRW_CALL_CULLED; - - if (st->cache_id != DST.state_cache_id) { - /* Update culling result for this view. */ - culled = !DRW_culling_sphere_test(&st->bsphere); - } + view = view ? view : DST.view_default; + return draw_culling_plane_test(&view->frustum_corners, plane); +} - if (st->visibility_cb) { - culled = !st->visibility_cb(!culled, st->user_data); - } +void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners) +{ + view = view ? view : DST.view_default; + *corners = view->frustum_corners; +} - SET_FLAG_FROM_TEST(st->flag, culled, DRW_CALL_CULLED); +void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4]) +{ + view = view ? view : DST.view_default; + memcpy(planes, view->frustum_planes, sizeof(float) * 6 * 4); } -static void draw_matrices_model_prepare(DRWCallState *st) +static void draw_compute_culling(DRWView *view) { - if (st->cache_id == DST.state_cache_id) { - /* Values are already updated for this view. */ - return; - } - else { - st->cache_id = DST.state_cache_id; - } + view = view->parent ? view->parent : view; - /* No need to go further the call will not be used. */ - if ((st->flag & DRW_CALL_CULLED) != 0 && (st->flag & DRW_CALL_BYPASS_CULLING) == 0) { + /* TODO(fclem) multithread this. */ + /* TODO(fclem) compute all dirty views at once. */ + if (!view->is_dirty) { return; } - /* Order matters */ - if (st->matflag & - (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE | DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) { - mul_m4_m4m4(st->modelview, DST.view_data.matstate.mat[DRW_MAT_VIEW], st->model); - } - if (st->matflag & DRW_CALL_MODELVIEWINVERSE) { - invert_m4_m4(st->modelviewinverse, st->modelview); - } - if (st->matflag & DRW_CALL_MODELVIEWPROJECTION) { - mul_m4_m4m4(st->modelviewprojection, DST.view_data.matstate.mat[DRW_MAT_PERS], st->model); - } - if (st->matflag & (DRW_CALL_NORMALVIEW | DRW_CALL_NORMALVIEWINVERSE | DRW_CALL_EYEVEC)) { - copy_m3_m4(st->normalview, st->modelview); - invert_m3(st->normalview); - transpose_m3(st->normalview); - } - if (st->matflag & (DRW_CALL_NORMALVIEWINVERSE | DRW_CALL_EYEVEC)) { - invert_m3_m3(st->normalviewinverse, st->normalview); - } - /* TODO remove eye vec (unused) */ - if (st->matflag & DRW_CALL_EYEVEC) { - /* Used by orthographic wires */ - copy_v3_fl3(st->eyevec, 0.0f, 0.0f, 1.0f); - /* set eye vector, transformed to object coords */ - mul_m3_v3(st->normalviewinverse, st->eyevec); - } - /* Non view dependent */ - if (st->matflag & DRW_CALL_MODELINVERSE) { - invert_m4_m4(st->modelinverse, st->model); - st->matflag &= ~DRW_CALL_MODELINVERSE; - } - if (st->matflag & DRW_CALL_NORMALWORLD) { - copy_m3_m4(st->normalworld, st->model); - invert_m3(st->normalworld); - transpose_m3(st->normalworld); - st->matflag &= ~DRW_CALL_NORMALWORLD; + + BLI_memblock_iter iter; + BLI_memblock_iternew(DST.vmempool->cullstates, &iter); + DRWCullingState *cull; + while ((cull = BLI_memblock_iterstep(&iter))) { + if (cull->bsphere.radius < 0.0) { + cull->mask = 0; + } + else { + bool culled = !draw_culling_sphere_test( + &view->frustum_bsphere, view->frustum_planes, &cull->bsphere); + +#ifdef DRW_DEBUG_CULLING + if (G.debug_value != 0) { + if (culled) { + DRW_debug_sphere( + cull->bsphere.center, cull->bsphere.radius, (const float[4]){1, 0, 0, 1}); + } + else { + DRW_debug_sphere( + cull->bsphere.center, cull->bsphere.radius, (const float[4]){0, 1, 0, 1}); + } + } +#endif + + if (view->visibility_fn) { + culled = !view->visibility_fn(!culled, cull->user_data); + } + + SET_FLAG_FROM_TEST(cull->mask, culled, view->culling_mask); + } } + + view->is_dirty = false; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Draw (DRW_draw) + * \{ */ + static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call) { - /* step 1 : bind object dependent matrices */ - if (call != NULL) { - DRWCallState *state = call->state; - float objectinfo[4]; - objectinfo[0] = state->objectinfo[0]; - objectinfo[1] = call->single.ma_index; /* WATCH this is only valid for single drawcalls. */ - objectinfo[2] = state->objectinfo[1]; - objectinfo[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f; + BLI_assert(call); + DRWCallState *state = call->state; + if (shgroup->model != -1) { GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model); + } + if (shgroup->modelinverse != -1) { GPU_shader_uniform_vector( shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->modelview, 16, 1, (float *)state->modelview); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)state->modelviewinverse); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)state->modelviewprojection); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->normalview, 9, 1, (float *)state->normalview); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->normalviewinverse, 9, 1, (float *)state->normalviewinverse); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->normalworld, 9, 1, (float *)state->normalworld); - GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)objectinfo); + } + if (shgroup->objectinfo != -1) { + float infos[4]; + infos[0] = state->ob_index; + // infos[1]; /* UNUSED. */ + infos[2] = state->ob_random; + infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f; + GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos); + } + if (shgroup->orcotexfac != -1) { GPU_shader_uniform_vector( shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac); - GPU_shader_uniform_vector(shgroup->shader, shgroup->eye, 3, 1, (float *)state->eyevec); } - else { - BLI_assert((shgroup->normalview == -1) && (shgroup->normalworld == -1) && - (shgroup->eye == -1)); - /* For instancing and batching. */ - float unitmat[4][4]; - unit_m4(unitmat); - GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)unitmat); - GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)unitmat); - GPU_shader_uniform_vector(shgroup->shader, - shgroup->modelview, - 16, - 1, - (float *)DST.view_data.matstate.mat[DRW_MAT_VIEW]); - GPU_shader_uniform_vector(shgroup->shader, - shgroup->modelviewinverse, - 16, - 1, - (float *)DST.view_data.matstate.mat[DRW_MAT_VIEWINV]); - GPU_shader_uniform_vector(shgroup->shader, - shgroup->modelviewprojection, - 16, - 1, - (float *)DST.view_data.matstate.mat[DRW_MAT_PERS]); - GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)unitmat); - GPU_shader_uniform_vector( - shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)shgroup->instance_orcofac); + /* Still supported for compatibility with gpu_shader_* but should be forbidden + * and is slow (since it does not cache the result). */ + if (shgroup->modelviewprojection != -1) { + float mvp[4][4]; + mul_m4_m4m4(mvp, DST.view_active->storage.persmat, state->model); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)mvp); } } -static void draw_geometry_execute_ex( - DRWShadingGroup *shgroup, GPUBatch *geom, uint start, uint count, bool draw_instance) +BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup, + GPUBatch *geom, + uint vert_first, + uint vert_count, + uint inst_first, + uint inst_count) { - /* Special case: empty drawcall, placement is done via shader, don't bind anything. */ - /* TODO use DRW_CALL_PROCEDURAL instead */ - if (geom == NULL) { - BLI_assert(shgroup->type == DRW_SHG_TRIANGLE_BATCH); /* Add other type if needed. */ - /* Shader is already bound. */ - GPU_draw_primitive(GPU_PRIM_TRIS, count); - return; + /* bind vertex array */ + if (DST.batch != geom) { + DST.batch = geom; + + GPU_batch_program_set_no_use( + geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); + + GPU_batch_bind(geom); } - /* step 2 : bind vertex array & draw */ - GPU_batch_program_set_no_use( - geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */ geom->program_in_use = true; - GPU_batch_draw_range_ex(geom, start, count, draw_instance); + GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count); geom->program_in_use = false; /* XXX hacking gawain */ } -static void draw_geometry_execute(DRWShadingGroup *shgroup, GPUBatch *geom) -{ - draw_geometry_execute_ex(shgroup, geom, 0, 0, false); -} - enum { BIND_NONE = 0, BIND_TEMP = 1, /* Release slot after this shading group. */ @@ -929,7 +620,7 @@ enum { static void set_bound_flags(uint64_t *slots, uint64_t *persist_slots, int slot_idx, char bind_type) { - uint64_t slot = 1lu << slot_idx; + uint64_t slot = 1lu << (unsigned long)slot_idx; *slots |= slot; if (bind_type == BIND_PERSIST) { *persist_slots |= slot; @@ -1089,39 +780,11 @@ static void release_ubo_slots(bool with_persist) } } -static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) +static void draw_update_uniforms(DRWShadingGroup *shgroup) { - BLI_assert(shgroup->shader); - - GPUTexture *tex; - GPUUniformBuffer *ubo; - int val; - float fval; - const bool shader_changed = (DST.shader != shgroup->shader); - bool use_tfeedback = false; - - if (shader_changed) { - if (DST.shader) { - GPU_shader_unbind(); - } - GPU_shader_bind(shgroup->shader); - DST.shader = shgroup->shader; - } - - if ((pass_state & DRW_STATE_TRANS_FEEDBACK) != 0 && - (shgroup->type == DRW_SHG_FEEDBACK_TRANSFORM)) { - use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, - shgroup->tfeedback_target->vbo_id); - } - - release_ubo_slots(shader_changed); - release_texture_slots(shader_changed); - - drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); - drw_stencil_set(shgroup->stencil_mask); - - /* Binding Uniform */ for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) { + GPUTexture *tex; + GPUUniformBuffer *ubo; if (uni->location == -2) { uni->location = GPU_shader_get_uniform_ensure(shgroup->shader, DST.uniform_names.buffer + uni->name_ofs); @@ -1129,34 +792,20 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) continue; } } + const void *data = uni->pvalue; + if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) { + data = uni->fvalue; + } switch (uni->type) { - case DRW_UNIFORM_SHORT_TO_INT: - val = (int)*((short *)uni->pvalue); - GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, &val); - break; - case DRW_UNIFORM_SHORT_TO_FLOAT: - fval = (float)*((short *)uni->pvalue); - GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval); - break; - case DRW_UNIFORM_BOOL_COPY: case DRW_UNIFORM_INT_COPY: - GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, &uni->ivalue); - break; - case DRW_UNIFORM_BOOL: case DRW_UNIFORM_INT: GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->pvalue); + shgroup->shader, uni->location, uni->length, uni->arraysize, data); break; case DRW_UNIFORM_FLOAT_COPY: - GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, &uni->fvalue); - break; case DRW_UNIFORM_FLOAT: GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->pvalue); + shgroup->shader, uni->location, uni->length, uni->arraysize, data); break; case DRW_UNIFORM_TEXTURE: tex = (GPUTexture *)uni->pvalue; @@ -1189,112 +838,93 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } } -#ifdef USE_GPU_SELECT -# define GPU_SELECT_LOAD_IF_PICKSEL(_select_id) \ - if (G.f & G_FLAG_PICKSEL) { \ - GPU_select_load_id(_select_id); \ - } \ - ((void)0) - -# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(_call) \ - if ((G.f & G_FLAG_PICKSEL) && (_call)) { \ - GPU_select_load_id((_call)->select_id); \ - } \ - ((void)0) - -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ - _start = 0; \ - _count = _shgroup->instance_count; \ - int *select_id = NULL; \ - if (G.f & G_FLAG_PICKSEL) { \ - if (_shgroup->override_selectid == -1) { \ - /* Hack : get vbo data without actually drawing. */ \ - GPUVertBufRaw raw; \ - GPU_vertbuf_attr_get_raw_data(_shgroup->inst_selectid, 0, &raw); \ - select_id = GPU_vertbuf_raw_step(&raw); \ - switch (_shgroup->type) { \ - case DRW_SHG_TRIANGLE_BATCH: \ - _count = 3; \ - break; \ - case DRW_SHG_LINE_BATCH: \ - _count = 2; \ - break; \ - default: \ - _count = 1; \ - break; \ - } \ - } \ - else { \ - GPU_select_load_id(_shgroup->override_selectid); \ - } \ - } \ - while (_start < _shgroup->instance_count) { \ - if (select_id) { \ - GPU_select_load_id(select_id[_start]); \ - } - -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \ - _start += _count; \ - } \ - ((void)0) - -#else -# define GPU_SELECT_LOAD_IF_PICKSEL(select_id) -# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(call) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) ((void)0) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ - _start = 0; \ - _count = _shgroup->instance_count; - -#endif - BLI_assert(ubo_bindings_validate(shgroup)); +} - /* Rendering Calls */ - if (!ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)) { - /* Replacing multiple calls with only one */ - if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) { - if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) { - if (shgroup->instance_geom != NULL) { - GPU_SELECT_LOAD_IF_PICKSEL(shgroup->override_selectid); - draw_geometry_prepare(shgroup, NULL); - draw_geometry_execute_ex(shgroup, shgroup->instance_geom, 0, 0, true); - } +BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call) +{ +#ifdef USE_GPU_SELECT + if ((G.f & G_FLAG_PICKSEL) == 0) { + return false; + } + if (call->inst_selectid != NULL) { + const bool is_instancing = (call->inst_count != 0); + uint start = 0; + uint count = 1; + uint tot = is_instancing ? call->inst_count : call->vert_count; + /* Hack : get vbo data without actually drawing. */ + GPUVertBufRaw raw; + GPU_vertbuf_attr_get_raw_data(call->inst_selectid, 0, &raw); + int *select_id = GPU_vertbuf_raw_step(&raw); + + /* Batching */ + if (!is_instancing) { + /* FIXME: Meh a bit nasty. */ + if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_TRIS)) { + count = 3; } - else { - if (shgroup->instance_count > 0) { - uint count, start; - draw_geometry_prepare(shgroup, NULL); - GPU_SELECT_LOAD_IF_PICKSEL_LIST (shgroup, start, count) { - draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count, true); - } - GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count); - } + else if (call->batch->gl_prim_type == convert_prim_type_to_gl(GPU_PRIM_LINES)) { + count = 2; } } - else { /* DRW_SHG_***_BATCH */ - /* Some dynamic batch can have no geom (no call to aggregate) */ - if (shgroup->instance_count > 0) { - uint count, start; - draw_geometry_prepare(shgroup, NULL); - GPU_SELECT_LOAD_IF_PICKSEL_LIST (shgroup, start, count) { - draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count, false); - } - GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count); + + while (start < tot) { + GPU_select_load_id(select_id[start]); + if (is_instancing) { + draw_geometry_execute(shgroup, call->batch, 0, 0, start, count); + } + else { + draw_geometry_execute(shgroup, call->batch, start, count, 0, 0); } + start += count; } + return true; } else { + GPU_select_load_id(call->select_id); + return false; + } +#else + return false; +#endif +} + +static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) +{ + BLI_assert(shgroup->shader); + + const bool shader_changed = (DST.shader != shgroup->shader); + bool use_tfeedback = false; + + if (shader_changed) { + if (DST.shader) { + GPU_shader_unbind(); + } + GPU_shader_bind(shgroup->shader); + DST.shader = shgroup->shader; + DST.batch = NULL; + } + + if (shgroup->tfeedback_target != NULL) { + use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, + shgroup->tfeedback_target->vbo_id); + } + + release_ubo_slots(shader_changed); + release_texture_slots(shader_changed); + + drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); + drw_stencil_set(shgroup->stencil_mask); + + draw_update_uniforms(shgroup); + + /* Rendering Calls */ + { bool prev_neg_scale = false; int callid = 0; for (DRWCall *call = shgroup->calls.first; call; call = call->next) { - /* OPTI/IDEA(clem): Do this preparation in another thread. */ - draw_visibility_eval(call->state); - draw_matrices_model_prepare(call->state); - - if ((call->state->flag & DRW_CALL_CULLED) != 0 && - (call->state->flag & DRW_CALL_BYPASS_CULLING) == 0) { + if (draw_call_is_culled(call, DST.view_active)) { continue; } @@ -1307,37 +937,21 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) /* Negative scale objects */ bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE; if (neg_scale != prev_neg_scale) { - glFrontFace((neg_scale) ? DST.backface : DST.frontface); + glFrontFace((neg_scale) ? GL_CW : GL_CCW); prev_neg_scale = neg_scale; } - GPU_SELECT_LOAD_IF_PICKSEL_CALL(call); draw_geometry_prepare(shgroup, call); - switch (call->type) { - case DRW_CALL_SINGLE: - draw_geometry_execute(shgroup, call->single.geometry); - break; - case DRW_CALL_RANGE: - draw_geometry_execute_ex( - shgroup, call->range.geometry, call->range.start, call->range.count, false); - break; - case DRW_CALL_INSTANCES: - draw_geometry_execute_ex( - shgroup, call->instances.geometry, 0, *call->instances.count, true); - break; - case DRW_CALL_GENERATE: - call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data); - break; - case DRW_CALL_PROCEDURAL: - GPU_draw_primitive(call->procedural.prim_type, call->procedural.vert_count); - break; - default: - BLI_assert(0); + if (draw_select_do_call(shgroup, call)) { + continue; } + + draw_geometry_execute( + shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count); } /* Reset state */ - glFrontFace(DST.frontface); + glFrontFace(GL_CCW); } if (use_tfeedback) { @@ -1347,29 +961,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) static void drw_update_view(void) { - if (DST.dirty_mat) { - DST.state_cache_id++; - DST.dirty_mat = false; - - DRW_uniformbuffer_update(G_draw.view_ubo, &DST.view_data); - - /* Catch integer wrap around. */ - if (UNLIKELY(DST.state_cache_id == 0)) { - DST.state_cache_id = 1; - /* We must reset all CallStates to ensure that not - * a single one stayed with cache_id equal to 1. */ - BLI_mempool_iter iter; - DRWCallState *state; - BLI_mempool_iternew(DST.vmempool->states, &iter); - while ((state = BLI_mempool_iterstep(&iter))) { - state->cache_id = 0; - } - } + /* TODO(fclem) update a big UBO and only bind ranges here. */ + DRW_uniformbuffer_update(G_draw.view_ubo, &DST.view_active->storage); - /* TODO dispatch threads to compute matrices/culling */ - } + /* TODO get rid of this. */ + DST.view_storage_cpy = DST.view_active->storage; - draw_clipping_setup_from_view(); + draw_compute_culling(DST.view_active); } static void drw_draw_pass_ex(DRWPass *pass, @@ -1385,7 +983,11 @@ static void drw_draw_pass_ex(DRWPass *pass, BLI_assert(DST.buffer_finish_called && "DRW_render_instance_buffer_finish had not been called before drawing"); - drw_update_view(); + if (DST.view_previous != DST.view_active || DST.view_active->is_dirty) { + drw_update_view(); + DST.view_active->is_dirty = false; + DST.view_previous = DST.view_active; + } /* GPU_framebuffer_clear calls can change the state outside the DRW module. * Force reset the affected states to avoid problems later. */ diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index b60a41ab0c9..186bbae5cad 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -394,6 +394,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, if (mat == NULL) { scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, + NULL, wo->nodetree, &wo->gpumaterial, engine_type, @@ -430,6 +431,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, if (mat == NULL) { scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id); mat = GPU_material_from_nodetree(scene, + ma, ma->nodetree, &ma->gpumaterial, engine_type, diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index d1ef0d0e104..9a10323c4e8 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -95,7 +95,7 @@ static void EDIT_ARMATURE_cache_init(void *vedata) psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state); state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND | DRW_STATE_WIRE; + DRW_STATE_BLEND; psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state); } diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index e47393c88c4..ff9f433ad14 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -39,6 +39,7 @@ * Not needed for constant color. */ extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[]; extern char datatoc_edit_curve_overlay_normals_vert_glsl[]; extern char datatoc_edit_curve_overlay_handle_vert_glsl[]; @@ -111,10 +112,6 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) const DRWContextState *draw_ctx = DRW_context_state_get(); EDIT_CURVE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; if (!sh_data->wire_sh) { @@ -124,8 +121,10 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) if (!sh_data->wire_normals_sh) { sh_data->wire_normals_sh = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){sh_cfg_data->lib, datatoc_edit_curve_overlay_normals_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_edit_curve_overlay_normals_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -133,8 +132,10 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) if (!sh_data->overlay_edge_sh) { sh_data->overlay_edge_sh = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){sh_cfg_data->lib, datatoc_edit_curve_overlay_handle_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_edit_curve_overlay_handle_vert_glsl, + NULL}, .geom = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, datatoc_edit_curve_overlay_handle_geom_glsl, @@ -148,6 +149,7 @@ static void EDIT_CURVE_engine_init(void *UNUSED(vedata)) sh_data->overlay_vert_sh = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_edit_curve_overlay_loosevert_vert_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, @@ -201,9 +203,8 @@ static void EDIT_CURVE_cache_init(void *vedata) DRWShadingGroup *grp; /* Center-Line (wire) */ - psl->wire_pass = DRW_pass_create("Curve Wire", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE); + psl->wire_pass = DRW_pass_create( + "Curve Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); EDIT_CURVE_wire_shgrp_create(sh_data, v3d, rv3d, @@ -211,9 +212,8 @@ static void EDIT_CURVE_cache_init(void *vedata) &stl->g_data->wire_shgrp, &stl->g_data->wire_normals_shgrp); - psl->wire_pass_xray = DRW_pass_create("Curve Wire Xray", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WIRE); + psl->wire_pass_xray = DRW_pass_create( + "Curve Wire Xray", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); EDIT_CURVE_wire_shgrp_create(sh_data, v3d, rv3d, @@ -233,8 +233,7 @@ static void EDIT_CURVE_cache_init(void *vedata) } stl->g_data->overlay_edge_shgrp = grp; - psl->overlay_vert_pass = DRW_pass_create("Curve Vert Overlay", - DRW_STATE_WRITE_COLOR | DRW_STATE_POINT); + psl->overlay_vert_pass = DRW_pass_create("Curve Vert Overlay", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(sh_data->overlay_vert_sh, psl->overlay_vert_pass); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); @@ -270,31 +269,30 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) } geom = DRW_cache_curve_edge_wire_get(ob); - DRW_shgroup_call_add(wire_shgrp, geom, ob->obmat); + DRW_shgroup_call(wire_shgrp, geom, ob->obmat); if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) { - static uint instance_len = 2; geom = DRW_cache_curve_edge_normal_get(ob); - DRW_shgroup_call_instances_add(wire_normals_shgrp, geom, ob->obmat, &instance_len); + DRW_shgroup_call_instances(wire_normals_shgrp, geom, ob->obmat, 2); } geom = DRW_cache_curve_edge_overlay_get(ob); if (geom) { - DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob->obmat); } geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles); - DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob->obmat); } } if (ob->type == OB_SURF) { if (BKE_object_is_in_editmode(ob)) { struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob); - DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->overlay_edge_shgrp, geom, ob->obmat); geom = DRW_cache_curve_vert_overlay_get(ob, false); - DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->overlay_vert_shgrp, geom, ob->obmat); } } } @@ -332,8 +330,6 @@ static void EDIT_CURVE_draw_scene(void *vedata) /* Thoses passes don't write to depth and are AA'ed using other tricks. */ DRW_draw_pass(psl->overlay_edge_pass); DRW_draw_pass(psl->overlay_vert_pass); - - DRW_state_clip_planes_reset(); } /* Cleanup when destroying the engine. diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c index 273480b8127..42d377f2abd 100644 --- a/source/blender/draw/modes/edit_lattice_mode.c +++ b/source/blender/draw/modes/edit_lattice_mode.c @@ -32,6 +32,7 @@ #include "draw_mode_engines.h" extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_edit_lattice_overlay_loosevert_vert_glsl[]; extern char datatoc_edit_lattice_overlay_frag_glsl[]; @@ -138,9 +139,7 @@ static void EDIT_LATTICE_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); EDIT_LATTICE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } + const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; if (!sh_data->wire) { @@ -152,6 +151,7 @@ static void EDIT_LATTICE_engine_init(void *vedata) sh_data->overlay_vert = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_edit_lattice_overlay_loosevert_vert_glsl, NULL}, .frag = (const char *[]){datatoc_common_globals_lib_glsl, @@ -181,14 +181,14 @@ static void EDIT_LATTICE_cache_init(void *vedata) { psl->wire_pass = DRW_pass_create("Lattice Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE); + DRW_STATE_DEPTH_LESS_EQUAL); stl->g_data->wire_shgrp = DRW_shgroup_create(sh_data->wire, psl->wire_pass); if (rv3d->rflag & RV3D_CLIPPING) { DRW_shgroup_world_clip_planes_from_rv3d(stl->g_data->wire_shgrp, rv3d); } - psl->vert_pass = DRW_pass_create( - "Lattice Verts", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT); + psl->vert_pass = DRW_pass_create("Lattice Verts", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH); stl->g_data->vert_shgrp = DRW_shgroup_create(sh_data->overlay_vert, psl->vert_pass); DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", G_draw.block_ubo); if (rv3d->rflag & RV3D_CLIPPING) { @@ -212,10 +212,10 @@ static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob) struct GPUBatch *geom; geom = DRW_cache_lattice_wire_get(ob, true); - DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob->obmat); geom = DRW_cache_lattice_vert_overlay_get(ob); - DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->vert_shgrp, geom, ob->obmat); } } } diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index ffe7fe5845c..2b17dd43ee5 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -60,6 +60,7 @@ extern char datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl[]; extern char datatoc_edit_normals_vert_glsl[]; extern char datatoc_edit_normals_geom_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; @@ -187,16 +188,13 @@ static void EDIT_MESH_engine_init(void *vedata) {GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_depth_tx), GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_color_tx)}); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; if (!sh_data->weight_face) { sh_data->weight_face = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_paint_weight_vert_glsl, NULL}, .frag = (const char *[]){datatoc_common_globals_lib_glsl, @@ -207,6 +205,7 @@ static void EDIT_MESH_engine_init(void *vedata) char *lib = BLI_string_joinN(sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_edit_mesh_overlay_common_lib_glsl); /* Use geometry shader to draw edge wireframe. This ensure us * the same result accross platforms and more flexibility. But @@ -265,43 +264,43 @@ static void EDIT_MESH_engine_init(void *vedata) sh_data->overlay_mix = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl, NULL); + lib = BLI_string_joinN(sh_cfg_data->lib, datatoc_common_view_lib_glsl); + sh_data->normals_face = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_vert_glsl, NULL}, - .geom = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_geom_glsl, NULL}, + .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL}, + .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define FACE_NORMALS\n", NULL}, }); sh_data->normals_loop = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_vert_glsl, NULL}, - .geom = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_geom_glsl, NULL}, + .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL}, + .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define LOOP_NORMALS\n", NULL}, }); sh_data->normals = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_vert_glsl, NULL}, - .geom = (const char *[]){sh_cfg_data->lib, datatoc_edit_normals_geom_glsl, NULL}, + .vert = (const char *[]){lib, datatoc_edit_normals_vert_glsl, NULL}, + .geom = (const char *[]){lib, datatoc_edit_normals_geom_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); /* Mesh Analysis */ sh_data->mesh_analysis_face = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, - NULL}, + .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL}, .frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define FACE_COLOR\n", NULL}, }); sh_data->mesh_analysis_vertex = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, - datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, - NULL}, + .vert = (const char *[]){lib, datatoc_edit_mesh_overlay_mesh_analysis_vert_glsl, NULL}, .frag = (const char *[]){datatoc_edit_mesh_overlay_mesh_analysis_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define VERTEX_COLOR\n", NULL}, }); + MEM_freeN(lib); + sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg); } } @@ -327,15 +326,15 @@ static DRWPass *edit_mesh_create_overlay_pass(float *face_alpha, float winmat[4][4]; float viewdist = rv3d->dist; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); + DRW_view_winmat_get(NULL, winmat, false); + /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ if (rv3d->persp == RV3D_CAMOB && rv3d->is_persp == false) { viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); } const float depth_ofs = bglPolygonOffsetCalc((float *)winmat, viewdist, 1.0f); - DRWPass *pass = DRW_pass_create("Edit Mesh Face Overlay Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_POINT | statemod); + DRWPass *pass = DRW_pass_create("Edit Mesh Face Overlay Pass", DRW_STATE_WRITE_COLOR | statemod); DRWShadingGroup *grp; @@ -603,7 +602,7 @@ static void EDIT_MESH_cache_init(void *vedata) psl->mix_occlude = DRW_pass_create("Mix Occluded Wires", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND); DRWShadingGroup *mix_shgrp = DRW_shgroup_create(sh_data->overlay_mix, psl->mix_occlude); - DRW_shgroup_call_add(mix_shgrp, quad, NULL); + DRW_shgroup_call(mix_shgrp, quad, NULL); DRW_shgroup_uniform_float(mix_shgrp, "alpha", &backwire_opacity, 1); DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx); DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx); @@ -636,17 +635,17 @@ static void edit_mesh_add_ob_to_pass(Scene *scene, geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data); geom_edges = DRW_mesh_batch_cache_get_edit_edges(ob->data); - DRW_shgroup_call_add(edge_shgrp, geom_edges, ob->obmat); - DRW_shgroup_call_add(face_shgrp, geom_tris, ob->obmat); + DRW_shgroup_call(edge_shgrp, geom_edges, ob->obmat); + DRW_shgroup_call(face_shgrp, geom_tris, ob->obmat); if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) { geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data); - DRW_shgroup_call_add(vert_shgrp, geom_verts, ob->obmat); + DRW_shgroup_call(vert_shgrp, geom_verts, ob->obmat); } if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0) { geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data); - DRW_shgroup_call_add(facedot_shgrp, geom_fcenter, ob->obmat); + DRW_shgroup_call(facedot_shgrp, geom_fcenter, ob->obmat); } } @@ -691,7 +690,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) if (do_show_weight) { geom = DRW_cache_mesh_surface_weights_get(ob); - DRW_shgroup_call_add(g_data->fweights_shgrp, geom, ob->obmat); + DRW_shgroup_call(g_data->fweights_shgrp, geom, ob->obmat); } if (do_show_mesh_analysis) { @@ -702,30 +701,30 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) if (is_original) { geom = DRW_cache_mesh_surface_mesh_analysis_get(ob); if (geom) { - DRW_shgroup_call_add(g_data->mesh_analysis_shgrp, geom, ob->obmat); + DRW_shgroup_call(g_data->mesh_analysis_shgrp, geom, ob->obmat); } } } if (do_occlude_wire || do_in_front) { geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call_add(do_in_front ? g_data->depth_shgrp_hidden_wire_in_front : - g_data->depth_shgrp_hidden_wire, - geom, - ob->obmat); + DRW_shgroup_call(do_in_front ? g_data->depth_shgrp_hidden_wire_in_front : + g_data->depth_shgrp_hidden_wire, + geom, + ob->obmat); } if (vnormals_do) { geom = DRW_mesh_batch_cache_get_edit_vertices(ob->data); - DRW_shgroup_call_add(g_data->vnormals_shgrp, geom, ob->obmat); + DRW_shgroup_call(g_data->vnormals_shgrp, geom, ob->obmat); } if (lnormals_do) { geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data); - DRW_shgroup_call_add(g_data->lnormals_shgrp, geom, ob->obmat); + DRW_shgroup_call(g_data->lnormals_shgrp, geom, ob->obmat); } if (fnormals_do) { geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data); - DRW_shgroup_call_add(g_data->fnormals_shgrp, geom, ob->obmat); + DRW_shgroup_call(g_data->fnormals_shgrp, geom, ob->obmat); } if (g_data->do_zbufclip) { @@ -822,8 +821,6 @@ static void EDIT_MESH_draw_scene(void *vedata) DRW_draw_pass(psl->depth_hidden_wire_in_front); DRW_draw_pass(psl->edit_face_overlay_in_front); } - - DRW_state_clip_planes_reset(); } static void EDIT_MESH_engine_free(void) diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c index aa7c6863423..82b1ddbd66d 100644 --- a/source/blender/draw/modes/edit_metaball_mode.c +++ b/source/blender/draw/modes/edit_metaball_mode.c @@ -26,6 +26,8 @@ #include "BKE_object.h" +#include "DEG_depsgraph_query.h" + #include "ED_mball.h" /* If builtin shaders are needed */ @@ -86,19 +88,11 @@ typedef struct EDIT_METABALL_Data { typedef struct EDIT_METABALL_PrivateData { /* This keeps the references of the shading groups for * easy access in EDIT_METABALL_cache_populate() */ - DRWShadingGroup *group; + DRWCallBuffer *group; } EDIT_METABALL_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ -static void EDIT_METABALL_engine_init(void *UNUSED(vedata)) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } -} - /* Here init all passes and shading groups * Assume that all Passes are NULL */ static void EDIT_METABALL_cache_init(void *vedata) @@ -115,11 +109,11 @@ static void EDIT_METABALL_cache_init(void *vedata) { /* Create a pass */ DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND | DRW_STATE_WIRE); + DRW_STATE_BLEND); psl->pass = DRW_pass_create("My Pass", state); /* Create a shadingGroup using a function in draw_common.c or custom one */ - stl->g_data->group = shgroup_instance_mball_handles(psl->pass, draw_ctx->sh_cfg); + stl->g_data->group = buffer_instance_mball_handles(psl->pass, draw_ctx->sh_cfg); } } @@ -131,7 +125,7 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) if (ob->type == OB_MBALL) { const DRWContextState *draw_ctx = DRW_context_state_get(); - DRWShadingGroup *group = stl->g_data->group; + DRWCallBuffer *group = stl->g_data->group; if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) { MetaBall *mb = ob->data; @@ -160,7 +154,8 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) copy_v3_v3(draw_scale_xform[2], scamat[2]); } - int select_id = ob->select_id; + const Object *orig_object = DEG_get_original_object(ob); + int select_id = orig_object->runtime.select_id; for (MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next, select_id += 0x10000) { float world_pos[3]; mul_v3_m4v3(world_pos, ob->obmat, &ml->x); @@ -181,7 +176,7 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) DRW_select_load_id(select_id | MBALLSEL_RADIUS); } - DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &ml->rad, color); + DRW_buffer_add_entry(group, draw_scale_xform, &ml->rad, color); if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) { color = col_stiffness_select; @@ -194,7 +189,7 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) DRW_select_load_id(select_id | MBALLSEL_STIFF); } - DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &draw_stiffness_radius, color); + DRW_buffer_add_entry(group, draw_scale_xform, &draw_stiffness_radius, color); } } } @@ -206,11 +201,6 @@ static void EDIT_METABALL_draw_scene(void *vedata) EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl; /* render passes on default framebuffer. */ DRW_draw_pass(psl->pass); - - /* If you changed framebuffer, double check you rebind - * the default one with its textures attached before finishing */ - - DRW_state_clip_planes_reset(); } /* Cleanup when destroying the engine. @@ -229,7 +219,7 @@ DrawEngineType draw_engine_edit_metaball_type = { NULL, N_("EditMetaballMode"), &EDIT_METABALL_data_size, - &EDIT_METABALL_engine_init, + NULL, &EDIT_METABALL_engine_free, &EDIT_METABALL_cache_init, &EDIT_METABALL_cache_populate, diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index 5f44a74b24e..b7215d5ef08 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -102,8 +102,8 @@ typedef struct EDIT_TEXT_PrivateData { DRWShadingGroup *wire_shgrp; DRWShadingGroup *overlay_select_shgrp; DRWShadingGroup *overlay_cursor_shgrp; - DRWShadingGroup *box_shgrp; - DRWShadingGroup *box_active_shgrp; + DRWCallBuffer *box_shgrp; + DRWCallBuffer *box_active_shgrp; } EDIT_TEXT_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -162,9 +162,8 @@ static void EDIT_TEXT_cache_init(void *vedata) { /* Text outline (fast drawing!) */ - psl->wire_pass = DRW_pass_create("Font Wire", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE); + psl->wire_pass = DRW_pass_create( + "Font Wire", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass); psl->overlay_select_pass = DRW_pass_create("Font Select", @@ -179,9 +178,9 @@ static void EDIT_TEXT_cache_init(void *vedata) psl->text_box_pass = DRW_pass_create("Font Text Boxes", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH); - stl->g_data->box_shgrp = shgroup_dynlines_dashed_uniform_color( + stl->g_data->box_shgrp = buffer_dynlines_dashed_uniform_color( psl->text_box_pass, G_draw.block.colorWire, draw_ctx->sh_cfg); - stl->g_data->box_active_shgrp = shgroup_dynlines_dashed_uniform_color( + stl->g_data->box_active_shgrp = buffer_dynlines_dashed_uniform_color( psl->text_box_pass, G_draw.block.colorActive, draw_ctx->sh_cfg); } } @@ -241,7 +240,7 @@ static void edit_text_cache_populate_select(void *vedata, Object *ob) v2_quad_corners_to_mat4(box, final_mat); mul_m4_m4m4(final_mat, ob->obmat, final_mat); - DRW_shgroup_call_add(stl->g_data->overlay_select_shgrp, geom, final_mat); + DRW_shgroup_call(stl->g_data->overlay_select_shgrp, geom, final_mat); } } @@ -257,7 +256,7 @@ static void edit_text_cache_populate_cursor(void *vedata, Object *ob) mul_m4_m4m4(mat, ob->obmat, mat); struct GPUBatch *geom = DRW_cache_quad_get(); - DRW_shgroup_call_add(stl->g_data->overlay_cursor_shgrp, geom, mat); + DRW_shgroup_call(stl->g_data->overlay_cursor_shgrp, geom, mat); } static void edit_text_cache_populate_boxes(void *vedata, Object *ob) @@ -265,7 +264,7 @@ static void edit_text_cache_populate_boxes(void *vedata, Object *ob) EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl; const Curve *cu = ob->data; - DRWShadingGroup *shading_groups[] = { + DRWCallBuffer *callbufs[] = { stl->g_data->box_active_shgrp, stl->g_data->box_shgrp, }; @@ -279,7 +278,7 @@ static void edit_text_cache_populate_boxes(void *vedata, Object *ob) } const bool is_active = i == (cu->actbox - 1); - DRWShadingGroup *shading_group = shading_groups[is_active ? 0 : 1]; + DRWCallBuffer *callbuf = callbufs[is_active ? 0 : 1]; vec[0] = cu->xof + tb->x; vec[1] = cu->yof + tb->y + cu->fsize_realtime; @@ -289,29 +288,29 @@ static void edit_text_cache_populate_boxes(void *vedata, Object *ob) vec[0] += tb->w; mul_v3_m4v3(vec2, ob->obmat, vec); - DRW_shgroup_call_dynamic_add(shading_group, vec1); - DRW_shgroup_call_dynamic_add(shading_group, vec2); + DRW_buffer_add_entry(callbuf, vec1); + DRW_buffer_add_entry(callbuf, vec2); vec[1] -= tb->h; copy_v3_v3(vec1, vec2); mul_v3_m4v3(vec2, ob->obmat, vec); - DRW_shgroup_call_dynamic_add(shading_group, vec1); - DRW_shgroup_call_dynamic_add(shading_group, vec2); + DRW_buffer_add_entry(callbuf, vec1); + DRW_buffer_add_entry(callbuf, vec2); vec[0] -= tb->w; copy_v3_v3(vec1, vec2); mul_v3_m4v3(vec2, ob->obmat, vec); - DRW_shgroup_call_dynamic_add(shading_group, vec1); - DRW_shgroup_call_dynamic_add(shading_group, vec2); + DRW_buffer_add_entry(callbuf, vec1); + DRW_buffer_add_entry(callbuf, vec2); vec[1] += tb->h; copy_v3_v3(vec1, vec2); mul_v3_m4v3(vec2, ob->obmat, vec); - DRW_shgroup_call_dynamic_add(shading_group, vec1); - DRW_shgroup_call_dynamic_add(shading_group, vec2); + DRW_buffer_add_entry(callbuf, vec1); + DRW_buffer_add_entry(callbuf, vec2); } } @@ -334,7 +333,7 @@ static void EDIT_TEXT_cache_populate(void *vedata, Object *ob) if ((cu->flag & CU_FAST) || !has_surface) { geom = DRW_cache_text_edge_wire_get(ob); if (geom) { - DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->wire_shgrp, geom, ob->obmat); } } else { diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index ee2c660ca06..68af4fc0c4a 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -88,6 +88,7 @@ extern char datatoc_object_particle_prim_vert_glsl[]; extern char datatoc_object_particle_dot_vert_glsl[]; extern char datatoc_object_particle_dot_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_flat_id_frag_glsl[]; @@ -171,82 +172,82 @@ typedef struct OBJECT_ShadingGroupList { struct DRWPass *bone_axes; /* Empties */ - DRWShadingGroup *plain_axes; - DRWShadingGroup *cube; - DRWShadingGroup *circle; - DRWShadingGroup *sphere; - DRWShadingGroup *sphere_solid; - DRWShadingGroup *cylinder; - DRWShadingGroup *capsule_cap; - DRWShadingGroup *capsule_body; - DRWShadingGroup *cone; - DRWShadingGroup *single_arrow; - DRWShadingGroup *single_arrow_line; - DRWShadingGroup *empty_axes; + DRWCallBuffer *plain_axes; + DRWCallBuffer *cube; + DRWCallBuffer *circle; + DRWCallBuffer *sphere; + DRWCallBuffer *sphere_solid; + DRWCallBuffer *cylinder; + DRWCallBuffer *capsule_cap; + DRWCallBuffer *capsule_body; + DRWCallBuffer *cone; + DRWCallBuffer *single_arrow; + DRWCallBuffer *single_arrow_line; + DRWCallBuffer *empty_axes; /* Force Field */ - DRWShadingGroup *field_wind; - DRWShadingGroup *field_force; - DRWShadingGroup *field_vortex; - DRWShadingGroup *field_curve_sta; - DRWShadingGroup *field_curve_end; - DRWShadingGroup *field_tube_limit; - DRWShadingGroup *field_cone_limit; + DRWCallBuffer *field_wind; + DRWCallBuffer *field_force; + DRWCallBuffer *field_vortex; + DRWCallBuffer *field_curve_sta; + DRWCallBuffer *field_curve_end; + DRWCallBuffer *field_tube_limit; + DRWCallBuffer *field_cone_limit; /* Grease Pencil */ - DRWShadingGroup *gpencil_axes; + DRWCallBuffer *gpencil_axes; /* Speaker */ - DRWShadingGroup *speaker; + DRWCallBuffer *speaker; /* Probe */ - DRWShadingGroup *probe_cube; - DRWShadingGroup *probe_planar; - DRWShadingGroup *probe_grid; + DRWCallBuffer *probe_cube; + DRWCallBuffer *probe_planar; + DRWCallBuffer *probe_grid; /* MetaBalls */ - DRWShadingGroup *mball_handle; + DRWCallBuffer *mball_handle; /* Lights */ - DRWShadingGroup *light_center; - DRWShadingGroup *light_groundpoint; - DRWShadingGroup *light_groundline; - DRWShadingGroup *light_circle; - DRWShadingGroup *light_circle_shadow; - DRWShadingGroup *light_sunrays; - DRWShadingGroup *light_distance; - DRWShadingGroup *light_buflimit; - DRWShadingGroup *light_buflimit_points; - DRWShadingGroup *light_area_sphere; - DRWShadingGroup *light_area_square; - DRWShadingGroup *light_area_disk; - DRWShadingGroup *light_hemi; - DRWShadingGroup *light_spot_cone; - DRWShadingGroup *light_spot_blend; - DRWShadingGroup *light_spot_pyramid; - DRWShadingGroup *light_spot_blend_rect; - DRWShadingGroup *light_spot_volume; - DRWShadingGroup *light_spot_volume_rect; - DRWShadingGroup *light_spot_volume_outside; - DRWShadingGroup *light_spot_volume_rect_outside; + DRWCallBuffer *light_center; + DRWCallBuffer *light_groundpoint; + DRWCallBuffer *light_groundline; + DRWCallBuffer *light_circle; + DRWCallBuffer *light_circle_shadow; + DRWCallBuffer *light_sunrays; + DRWCallBuffer *light_distance; + DRWCallBuffer *light_buflimit; + DRWCallBuffer *light_buflimit_points; + DRWCallBuffer *light_area_sphere; + DRWCallBuffer *light_area_square; + DRWCallBuffer *light_area_disk; + DRWCallBuffer *light_hemi; + DRWCallBuffer *light_spot_cone; + DRWCallBuffer *light_spot_blend; + DRWCallBuffer *light_spot_pyramid; + DRWCallBuffer *light_spot_blend_rect; + DRWCallBuffer *light_spot_volume; + DRWCallBuffer *light_spot_volume_rect; + DRWCallBuffer *light_spot_volume_outside; + DRWCallBuffer *light_spot_volume_rect_outside; /* Helpers */ - DRWShadingGroup *relationship_lines; - DRWShadingGroup *constraint_lines; + DRWCallBuffer *relationship_lines; + DRWCallBuffer *constraint_lines; /* Camera */ - DRWShadingGroup *camera; - DRWShadingGroup *camera_frame; - DRWShadingGroup *camera_tria; - DRWShadingGroup *camera_focus; - DRWShadingGroup *camera_clip; - DRWShadingGroup *camera_clip_points; - DRWShadingGroup *camera_mist; - DRWShadingGroup *camera_mist_points; - DRWShadingGroup *camera_stereo_plane; - DRWShadingGroup *camera_stereo_plane_wires; - DRWShadingGroup *camera_stereo_volume; - DRWShadingGroup *camera_stereo_volume_wires; + DRWCallBuffer *camera; + DRWCallBuffer *camera_frame; + DRWCallBuffer *camera_tria; + DRWCallBuffer *camera_focus; + DRWCallBuffer *camera_clip; + DRWCallBuffer *camera_clip_points; + DRWCallBuffer *camera_mist; + DRWCallBuffer *camera_mist_points; + DRWCallBuffer *camera_stereo_plane; + DRWCallBuffer *camera_stereo_plane_wires; + DRWCallBuffer *camera_stereo_volume; + DRWCallBuffer *camera_stereo_volume_wires; ListBase camera_path; /* Wire */ @@ -268,7 +269,7 @@ typedef struct OBJECT_ShadingGroupList { DRWShadingGroup *points_dupli_select; /* Texture Space */ - DRWShadingGroup *texspace; + DRWCallBuffer *texspace; } OBJECT_ShadingGroupList; typedef struct OBJECT_PrivateData { @@ -284,22 +285,22 @@ typedef struct OBJECT_PrivateData { DRWShadingGroup *outlines_transform; /* Lightprobes */ - DRWShadingGroup *lightprobes_cube_select; - DRWShadingGroup *lightprobes_cube_select_dupli; - DRWShadingGroup *lightprobes_cube_active; - DRWShadingGroup *lightprobes_cube_transform; + DRWCallBuffer *lightprobes_cube_select; + DRWCallBuffer *lightprobes_cube_select_dupli; + DRWCallBuffer *lightprobes_cube_active; + DRWCallBuffer *lightprobes_cube_transform; - DRWShadingGroup *lightprobes_planar_select; - DRWShadingGroup *lightprobes_planar_select_dupli; - DRWShadingGroup *lightprobes_planar_active; - DRWShadingGroup *lightprobes_planar_transform; + DRWCallBuffer *lightprobes_planar_select; + DRWCallBuffer *lightprobes_planar_select_dupli; + DRWCallBuffer *lightprobes_planar_active; + DRWCallBuffer *lightprobes_planar_transform; /* Objects Centers */ - DRWShadingGroup *center_active; - DRWShadingGroup *center_selected; - DRWShadingGroup *center_deselected; - DRWShadingGroup *center_selected_lib; - DRWShadingGroup *center_deselected_lib; + DRWCallBuffer *center_active; + DRWCallBuffer *center_selected; + DRWCallBuffer *center_deselected; + DRWCallBuffer *center_selected_lib; + DRWCallBuffer *center_deselected_lib; /* Outlines id offset (accessed as an array) */ int id_ofs_active; @@ -316,15 +317,20 @@ typedef struct OBJECT_PrivateData { bool xray_enabled_and_not_wire; } OBJECT_PrivateData; /* Transient data */ +typedef struct OBJECT_DupliData { + DRWShadingGroup *outline_shgrp; + GPUBatch *outline_geom; + DRWShadingGroup *extra_shgrp; + GPUBatch *extra_geom; +} OBJECT_DupliData; + static struct { /* Instance Data format */ - struct GPUVertFormat *particle_format; struct GPUVertFormat *empty_image_format; struct GPUVertFormat *empty_image_wire_format; OBJECT_Shaders sh_data[GPU_SHADER_CFG_LEN]; - float camera_pos[3]; float grid_settings[5]; float grid_mesh_size; int grid_flag; @@ -412,8 +418,14 @@ static void OBJECT_engine_init(void *vedata) .defs = (const char *[]){sh_cfg_data->def, NULL}, }); sh_data->outline_prepass_wire = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_outline_prepass_vert_glsl, NULL}, - .geom = (const char *[]){sh_cfg_data->lib, datatoc_object_outline_prepass_geom_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_object_outline_prepass_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_object_outline_prepass_geom_glsl, + NULL}, .frag = (const char *[]){datatoc_object_outline_prepass_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -455,37 +467,53 @@ static void OBJECT_engine_init(void *vedata) "#define DEPTH_BACK " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_BACK) "\n"); sh_data->object_empty_image = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_empty_image_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_object_empty_image_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_object_empty_image_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, empty_image_defs, NULL}, }); sh_data->object_empty_image_wire = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_object_empty_image_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_object_empty_image_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_object_empty_image_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define USE_WIRE\n", empty_image_defs, NULL}, }); } /* Grid */ - sh_data->grid = DRW_shader_create_with_lib(datatoc_object_grid_vert_glsl, - NULL, - datatoc_object_grid_frag_glsl, - datatoc_common_globals_lib_glsl, - NULL); + sh_data->grid = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_object_grid_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_object_grid_frag_glsl, + NULL}, + }); /* Particles */ - sh_data->part_prim = DRW_shader_create(datatoc_object_particle_prim_vert_glsl, - NULL, - datatoc_gpu_shader_flat_color_frag_glsl, - NULL); - - sh_data->part_axis = DRW_shader_create(datatoc_object_particle_prim_vert_glsl, - NULL, - datatoc_gpu_shader_flat_color_frag_glsl, - "#define USE_AXIS\n"); - - sh_data->part_dot = DRW_shader_create( - datatoc_object_particle_dot_vert_glsl, NULL, datatoc_object_particle_dot_frag_glsl, NULL); + sh_data->part_prim = DRW_shader_create_with_lib(datatoc_object_particle_prim_vert_glsl, + NULL, + datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + + sh_data->part_axis = DRW_shader_create_with_lib(datatoc_object_particle_prim_vert_glsl, + NULL, + datatoc_gpu_shader_flat_color_frag_glsl, + datatoc_common_view_lib_glsl, + "#define USE_AXIS\n"); + + sh_data->part_dot = DRW_shader_create_with_lib(datatoc_object_particle_dot_vert_glsl, + NULL, + datatoc_object_particle_dot_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); /* Lightprobes */ sh_data->lightprobe_grid = DRW_shader_create(datatoc_object_lightprobe_grid_vert_glsl, @@ -503,7 +531,7 @@ static void OBJECT_engine_init(void *vedata) { /* Grid precompute */ - float invviewmat[4][4], invwinmat[4][4]; + float viewinv[4][4], wininv[4][4]; float viewmat[4][4], winmat[4][4]; View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; @@ -518,13 +546,10 @@ static void OBJECT_engine_init(void *vedata) const bool show_ortho_grid = (v3d->gridflag & V3D_SHOW_ORTHO_GRID) != 0; e_data.draw_grid = show_axis_x || show_axis_y || show_axis_z || show_floor; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(invwinmat, DRW_MAT_WININV); - DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV); - - /* Setup camera pos */ - copy_v3_v3(e_data.camera_pos, invviewmat[3]); + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_winmat_get(NULL, wininv, true); + DRW_view_viewmat_get(NULL, viewmat, false); + DRW_view_viewmat_get(NULL, viewinv, true); /* if perps */ if (winmat[3][3] == 0.0f) { @@ -536,7 +561,7 @@ static void OBJECT_engine_init(void *vedata) /* convert the view vectors to view space */ for (int i = 0; i < 2; i++) { - mul_m4_v4(invwinmat, viewvecs[i]); + mul_m4_v4(wininv, viewvecs[i]); mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* perspective divide */ } @@ -597,8 +622,9 @@ static void OBJECT_engine_init(void *vedata) if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) { e_data.zpos_flag = SHOW_AXIS_Z; - float zvec[4] = {0.0f, 0.0f, -1.0f, 0.0f}; - mul_m4_v4(invviewmat, zvec); + float zvec[3], campos[3]; + negate_v3_v3(zvec, viewinv[2]); + copy_v3_v3(campos, viewinv[3]); /* z axis : chose the most facing plane */ if (fabsf(zvec[0]) < fabsf(zvec[1])) { @@ -612,7 +638,7 @@ static void OBJECT_engine_init(void *vedata) /* Persp : If camera is below floor plane, we switch clipping * Ortho : If eye vector is looking up, we switch clipping */ - if (((winmat[3][3] == 0.0f) && (e_data.camera_pos[2] > 0.0f)) || + if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) || ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) { e_data.zpos_flag |= CLIP_ZPOS; e_data.zneg_flag |= CLIP_ZNEG; @@ -661,7 +687,6 @@ static void OBJECT_engine_init(void *vedata) static void OBJECT_engine_free(void) { - MEM_SAFE_FREE(e_data.particle_format); MEM_SAFE_FREE(e_data.empty_image_format); MEM_SAFE_FREE(e_data.empty_image_wire_format); @@ -771,8 +796,8 @@ static int *shgroup_theme_id_to_outline_counter(OBJECT_StorageList *stl, } } -static DRWShadingGroup *shgroup_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl, - int theme_id) +static DRWCallBuffer *buffer_theme_id_to_probe_planar_outline_shgrp(OBJECT_StorageList *stl, + int theme_id) { /* does not increment counter */ switch (theme_id) { @@ -786,9 +811,9 @@ static DRWShadingGroup *shgroup_theme_id_to_probe_planar_outline_shgrp(OBJECT_St } } -static DRWShadingGroup *shgroup_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl, - int theme_id, - const int base_flag) +static DRWCallBuffer *buffer_theme_id_to_probe_cube_outline_shgrp(OBJECT_StorageList *stl, + int theme_id, + const int base_flag) { /* does not increment counter */ if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) { @@ -961,7 +986,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, GPUTexture *tex = NULL; if (ob->data != NULL) { - tex = GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false); + tex = GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D); if (tex) { size[0] = GPU_texture_width(tex); size[1] = GPU_texture_height(tex); @@ -985,9 +1010,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, { DRWShadingGroup *grp = DRW_shgroup_create(sh_data->object_empty_image_wire, sgl->non_meshes); - /* TODO(fclem) implement DRW_shgroup_uniform_vec2_copy */ - DRW_shgroup_uniform_float_copy(grp, "aspectX", image_aspect[0]); - DRW_shgroup_uniform_float_copy(grp, "aspectY", image_aspect[1]); + DRW_shgroup_uniform_vec2_copy(grp, "aspect", image_aspect); DRW_shgroup_uniform_int_copy(grp, "depthMode", depth_mode); DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1); DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1); @@ -995,7 +1018,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - DRW_shgroup_call_add(grp, DRW_cache_image_plane_wire_get(), ob->obmat); + DRW_shgroup_call(grp, DRW_cache_image_plane_wire_get(), ob->obmat); } if (!BKE_object_empty_image_data_is_visible_in_view3d(ob, rv3d)) { @@ -1005,8 +1028,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, if (tex && ((ob->color[3] > 0.0f) || !use_alpha_blend)) { DRWShadingGroup *grp = DRW_shgroup_create( sh_data->object_empty_image, (use_alpha_blend) ? sgl->image_empties : sgl->non_meshes); - DRW_shgroup_uniform_float_copy(grp, "aspectX", image_aspect[0]); - DRW_shgroup_uniform_float_copy(grp, "aspectY", image_aspect[1]); + DRW_shgroup_uniform_vec2_copy(grp, "aspect", image_aspect); DRW_shgroup_uniform_int_copy(grp, "depthMode", depth_mode); DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1); DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1); @@ -1016,7 +1038,7 @@ static void DRW_shgroup_empty_image(OBJECT_Shaders *sh_data, if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); } - DRW_shgroup_call_add(grp, DRW_cache_image_plane_get(), ob->obmat); + DRW_shgroup_call(grp, DRW_cache_image_plane_get(), ob->obmat); } } @@ -1048,8 +1070,7 @@ static void OBJECT_cache_init(void *vedata) g_data->custom_shapes = BLI_ghash_ptr_new(__func__); { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_WIRE; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; psl->outlines = DRW_pass_create("Outlines Depth Pass", state); GPUShader *sh = sh_data->outline_prepass; @@ -1074,30 +1095,29 @@ static void OBJECT_cache_init(void *vedata) } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_POINT; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state); struct GPUBatch *sphere = DRW_cache_sphere_get(); struct GPUBatch *quad = DRW_cache_quad_get(); /* Cubemap */ - g_data->lightprobes_cube_select = shgroup_instance_outline( + g_data->lightprobes_cube_select = buffer_instance_outline( pass, sphere, &g_data->id_ofs_prb_select); - g_data->lightprobes_cube_select_dupli = shgroup_instance_outline( + g_data->lightprobes_cube_select_dupli = buffer_instance_outline( pass, sphere, &g_data->id_ofs_prb_select_dupli); - g_data->lightprobes_cube_active = shgroup_instance_outline( + g_data->lightprobes_cube_active = buffer_instance_outline( pass, sphere, &g_data->id_ofs_prb_active); - g_data->lightprobes_cube_transform = shgroup_instance_outline( + g_data->lightprobes_cube_transform = buffer_instance_outline( pass, sphere, &g_data->id_ofs_prb_transform); /* Planar */ - g_data->lightprobes_planar_select = shgroup_instance_outline( + g_data->lightprobes_planar_select = buffer_instance_outline( pass, quad, &g_data->id_ofs_prb_select); - g_data->lightprobes_planar_select_dupli = shgroup_instance_outline( + g_data->lightprobes_planar_select_dupli = buffer_instance_outline( pass, quad, &g_data->id_ofs_prb_select_dupli); - g_data->lightprobes_planar_active = shgroup_instance_outline( + g_data->lightprobes_planar_active = buffer_instance_outline( pass, quad, &g_data->id_ofs_prb_active); - g_data->lightprobes_planar_transform = shgroup_instance_outline( + g_data->lightprobes_planar_transform = buffer_instance_outline( pass, quad, &g_data->id_ofs_prb_transform); g_data->id_ofs_prb_select = 0; @@ -1123,7 +1143,7 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu); DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 4); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); /* This is the bleed pass if do_outline_expand is false. */ GPUShader *fade_sh = (do_large_expand) ? sh_data->outline_fade_large : sh_data->outline_fade; @@ -1132,7 +1152,7 @@ static void OBJECT_cache_init(void *vedata) grp = DRW_shgroup_create(fade_sh, psl->outlines_expand); DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_blur_tx); DRW_shgroup_uniform_bool_copy(grp, "doExpand", do_outline_expand); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); psl->outlines_bleed = DRW_pass_create("Outlines Bleed Pass", state); @@ -1140,7 +1160,7 @@ static void OBJECT_cache_init(void *vedata) grp = DRW_shgroup_create(sh_data->outline_fade, psl->outlines_bleed); DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx); DRW_shgroup_uniform_bool_copy(grp, "doExpand", false); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } } @@ -1155,7 +1175,7 @@ static void OBJECT_cache_init(void *vedata) DRWShadingGroup *grp = DRW_shgroup_create(sh_data->outline_resolve_aa, psl->outlines_resolve); DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx); DRW_shgroup_uniform_vec2(grp, "rcpDimensions", e_data.inv_viewport_size, 1); - DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_call(grp, quad, NULL); } { @@ -1172,28 +1192,27 @@ static void OBJECT_cache_init(void *vedata) DRWShadingGroup *grp = DRW_shgroup_create(sh_data->grid, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1); - DRW_shgroup_uniform_vec3(grp, "cameraPos", e_data.camera_pos, 1); DRW_shgroup_uniform_vec4(grp, "gridSettings", e_data.grid_settings, 1); DRW_shgroup_uniform_float_copy(grp, "lineKernel", grid_line_size); DRW_shgroup_uniform_float_copy(grp, "meshSize", e_data.grid_mesh_size); DRW_shgroup_uniform_float(grp, "gridOneOverLogSubdiv", &e_data.grid_settings[4], 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call_add(grp, geom, mat); + DRW_shgroup_call(grp, geom, mat); grp = DRW_shgroup_create(sh_data->grid, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call_add(grp, geom, mat); + DRW_shgroup_call(grp, geom, mat); grp = DRW_shgroup_create(sh_data->grid, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call_add(grp, geom, mat); + DRW_shgroup_call(grp, geom, mat); } for (int i = 0; i < 2; ++i) { @@ -1215,8 +1234,7 @@ static void OBJECT_cache_init(void *vedata) sgl->bone_envelope = psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state); - state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_WIRE; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; sgl->bone_axes = psl->bone_axes[i] = DRW_pass_create("Bone Axes Pass", state); } @@ -1228,121 +1246,119 @@ static void OBJECT_cache_init(void *vedata) struct GPUShader *sh; DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND | DRW_STATE_POINT | DRW_STATE_WIRE; + DRW_STATE_BLEND; sgl->non_meshes = psl->non_meshes[i] = DRW_pass_create("Non Meshes Pass", state); - state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_WIRE; + state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND; sgl->image_empties = psl->image_empties[i] = DRW_pass_create("Image Empties", state); /* Empties */ geom = DRW_cache_plain_axes_get(); - sgl->plain_axes = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->plain_axes = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_cube_get(); - sgl->cube = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->cube = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_circle_get(); - sgl->circle = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->circle = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_sphere_get(); - sgl->sphere = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->sphere = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_sphere_get(); - sgl->sphere_solid = shgroup_instance_solid(sgl->non_meshes, geom); + sgl->sphere_solid = buffer_instance_solid(sgl->non_meshes, geom); geom = DRW_cache_empty_cylinder_get(); - sgl->cylinder = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->cylinder = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_capsule_cap_get(); - sgl->capsule_cap = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->capsule_cap = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_capsule_body_get(); - sgl->capsule_body = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->capsule_body = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_cone_get(); - sgl->cone = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->cone = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_arrow_get(); - sgl->single_arrow = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->single_arrow = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_line_get(); - sgl->single_arrow_line = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->single_arrow_line = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_bone_arrows_get(); - sgl->empty_axes = shgroup_instance_empty_axes(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->empty_axes = buffer_instance_empty_axes(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Force Field */ geom = DRW_cache_field_wind_get(); - sgl->field_wind = shgroup_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_wind = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_field_force_get(); - sgl->field_force = shgroup_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_force = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_field_vortex_get(); - sgl->field_vortex = shgroup_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_vortex = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_screenspace_circle_get(); - sgl->field_curve_sta = shgroup_instance_screen_aligned( - sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_curve_sta = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Grease Pencil */ geom = DRW_cache_gpencil_axes_get(); - sgl->gpencil_axes = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->gpencil_axes = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Speaker */ geom = DRW_cache_speaker_get(); - sgl->speaker = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->speaker = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Probe */ static float probeSize = 14.0f; geom = DRW_cache_lightprobe_cube_get(); - sgl->probe_cube = shgroup_instance_screenspace( + sgl->probe_cube = buffer_instance_screenspace( sgl->non_meshes, geom, &probeSize, draw_ctx->sh_cfg); geom = DRW_cache_lightprobe_grid_get(); - sgl->probe_grid = shgroup_instance_screenspace( + sgl->probe_grid = buffer_instance_screenspace( sgl->non_meshes, geom, &probeSize, draw_ctx->sh_cfg); static float probePlanarSize = 20.0f; geom = DRW_cache_lightprobe_planar_get(); - sgl->probe_planar = shgroup_instance_screenspace( + sgl->probe_planar = buffer_instance_screenspace( sgl->non_meshes, geom, &probePlanarSize, draw_ctx->sh_cfg); /* Camera */ geom = DRW_cache_camera_get(); - sgl->camera = shgroup_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_camera_frame_get(); - sgl->camera_frame = shgroup_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_frame = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_camera_tria_get(); - sgl->camera_tria = shgroup_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_tria = buffer_camera_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_plain_axes_get(); - sgl->camera_focus = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_focus = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_line_get(); - sgl->camera_clip = shgroup_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); - sgl->camera_mist = shgroup_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_clip = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_mist = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_line_endpoints_get(); - sgl->camera_clip_points = shgroup_distance_lines_instance( + sgl->camera_clip_points = buffer_distance_lines_instance( sgl->non_meshes, geom, draw_ctx->sh_cfg); - sgl->camera_mist_points = shgroup_distance_lines_instance( + sgl->camera_mist_points = buffer_distance_lines_instance( sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_quad_wires_get(); - sgl->camera_stereo_plane_wires = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); - DRW_shgroup_state_enable(sgl->camera_stereo_plane_wires, DRW_STATE_WIRE); + sgl->camera_stereo_plane_wires = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_empty_cube_get(); - sgl->camera_stereo_volume_wires = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->camera_stereo_volume_wires = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); BLI_listbase_clear(&sgl->camera_path); /* Texture Space */ geom = DRW_cache_empty_cube_get(); - sgl->texspace = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->texspace = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Wires (for loose edges) */ sh = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_UNIFORM_COLOR, draw_ctx->sh_cfg); @@ -1374,123 +1390,137 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_state_disable(sgl->points_dupli_select, DRW_STATE_BLEND); /* Metaballs Handles */ - sgl->mball_handle = shgroup_instance_mball_handles(sgl->non_meshes, draw_ctx->sh_cfg); + sgl->mball_handle = buffer_instance_mball_handles(sgl->non_meshes, draw_ctx->sh_cfg); /* Lights */ /* TODO * for now we create multiple times the same VBO with only light center coordinates * but ideally we would only create it once */ - /* start with buflimit because we don't want stipples */ - geom = DRW_cache_single_line_get(); - sgl->light_buflimit = shgroup_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sh = GPU_shader_get_builtin_shader_with_config( + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, draw_ctx->sh_cfg); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, sgl->non_meshes); + DRW_shgroup_uniform_vec4(grp, "color", gb->colorLightNoAlpha, 1); + DRW_shgroup_uniform_float(grp, "size", &gb->sizeLightCenter, 1); + if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { + DRW_shgroup_world_clip_planes_from_rv3d(grp, DRW_context_state_get()->rv3d); + } - sgl->light_center = shgroup_dynpoints_uniform_color( - sgl->non_meshes, gb->colorLightNoAlpha, &gb->sizeLightCenter, draw_ctx->sh_cfg); + sgl->light_center = buffer_dynpoints_uniform_color(grp); + + geom = DRW_cache_single_line_get(); + sgl->light_buflimit = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_get(); - sgl->light_circle = shgroup_instance_screenspace( + sgl->light_circle = buffer_instance_screenspace( sgl->non_meshes, geom, &gb->sizeLightCircle, draw_ctx->sh_cfg); geom = DRW_cache_light_shadows_get(); - sgl->light_circle_shadow = shgroup_instance_screenspace( + sgl->light_circle_shadow = buffer_instance_screenspace( sgl->non_meshes, geom, &gb->sizeLightCircleShadow, draw_ctx->sh_cfg); geom = DRW_cache_light_sunrays_get(); - sgl->light_sunrays = shgroup_instance_screenspace( + sgl->light_sunrays = buffer_instance_screenspace( sgl->non_meshes, geom, &gb->sizeLightCircle, draw_ctx->sh_cfg); - sgl->light_groundline = shgroup_groundlines_uniform_color( + sgl->light_groundline = buffer_groundlines_uniform_color( sgl->non_meshes, gb->colorLight, draw_ctx->sh_cfg); - sgl->light_groundpoint = shgroup_groundpoints_uniform_color( + sgl->light_groundpoint = buffer_groundpoints_uniform_color( sgl->non_meshes, gb->colorLight, draw_ctx->sh_cfg); geom = DRW_cache_screenspace_circle_get(); - sgl->light_area_sphere = shgroup_instance_screen_aligned( + sgl->light_area_sphere = buffer_instance_screen_aligned( sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_area_square_get(); - sgl->light_area_square = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_area_square = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_area_disk_get(); - sgl->light_area_disk = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_area_disk = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_hemi_get(); - sgl->light_hemi = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_hemi = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_line_get(); - sgl->light_distance = shgroup_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_distance = buffer_distance_lines_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_single_line_endpoints_get(); - sgl->light_buflimit_points = shgroup_distance_lines_instance( + sgl->light_buflimit_points = buffer_distance_lines_instance( sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_spot_get(); - sgl->light_spot_cone = shgroup_spot_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_spot_cone = buffer_spot_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_circle_get(); - sgl->light_spot_blend = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_spot_blend = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_light_spot_square_get(); - sgl->light_spot_pyramid = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_spot_pyramid = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); geom = DRW_cache_square_get(); - sgl->light_spot_blend_rect = shgroup_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->light_spot_blend_rect = buffer_instance(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* -------- STIPPLES ------- */ /* Relationship Lines */ - sgl->relationship_lines = shgroup_dynlines_dashed_uniform_color( + sgl->relationship_lines = buffer_dynlines_dashed_uniform_color( sgl->non_meshes, gb->colorWire, draw_ctx->sh_cfg); - sgl->constraint_lines = shgroup_dynlines_dashed_uniform_color( + sgl->constraint_lines = buffer_dynlines_dashed_uniform_color( sgl->non_meshes, gb->colorGridAxisZ, draw_ctx->sh_cfg); /* Force Field Curve Guide End (here because of stipple) */ /* TODO port to shader stipple */ geom = DRW_cache_screenspace_circle_get(); - sgl->field_curve_end = shgroup_instance_screen_aligned( - sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_curve_end = buffer_instance_screen_aligned(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Force Field Limits */ /* TODO port to shader stipple */ geom = DRW_cache_field_tube_limit_get(); - sgl->field_tube_limit = shgroup_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_tube_limit = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* TODO port to shader stipple */ geom = DRW_cache_field_cone_limit_get(); - sgl->field_cone_limit = shgroup_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); + sgl->field_cone_limit = buffer_instance_scaled(sgl->non_meshes, geom, draw_ctx->sh_cfg); /* Transparent Shapes */ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_CULL_FRONT; sgl->transp_shapes = psl->transp_shapes[i] = DRW_pass_create("Transparent Shapes", state); + sh = GPU_shader_get_builtin_shader_with_config( + GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, draw_ctx->sh_cfg); + + DRWShadingGroup *grp_transp = DRW_shgroup_create(sh, sgl->transp_shapes); + if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { + DRW_shgroup_world_clip_planes_from_rv3d(grp_transp, DRW_context_state_get()->rv3d); + } + + DRWShadingGroup *grp_cull_back = DRW_shgroup_create_sub(grp_transp); + DRW_shgroup_state_disable(grp_cull_back, DRW_STATE_CULL_FRONT); + DRW_shgroup_state_enable(grp_cull_back, DRW_STATE_CULL_BACK); + + DRWShadingGroup *grp_cull_none = DRW_shgroup_create_sub(grp_transp); + DRW_shgroup_state_disable(grp_cull_none, DRW_STATE_CULL_FRONT); + /* Spot cones */ geom = DRW_cache_light_spot_volume_get(); - sgl->light_spot_volume = shgroup_instance_alpha(sgl->transp_shapes, geom, draw_ctx->sh_cfg); + sgl->light_spot_volume = buffer_instance_alpha(grp_transp, geom); geom = DRW_cache_light_spot_square_volume_get(); - sgl->light_spot_volume_rect = shgroup_instance_alpha( - sgl->transp_shapes, geom, draw_ctx->sh_cfg); + sgl->light_spot_volume_rect = buffer_instance_alpha(grp_transp, geom); geom = DRW_cache_light_spot_volume_get(); - sgl->light_spot_volume_outside = shgroup_instance_alpha( - sgl->transp_shapes, geom, draw_ctx->sh_cfg); - DRW_shgroup_state_disable(sgl->light_spot_volume_outside, DRW_STATE_CULL_FRONT); - DRW_shgroup_state_enable(sgl->light_spot_volume_outside, DRW_STATE_CULL_BACK); + sgl->light_spot_volume_outside = buffer_instance_alpha(grp_cull_back, geom); geom = DRW_cache_light_spot_square_volume_get(); - sgl->light_spot_volume_rect_outside = shgroup_instance_alpha( - sgl->transp_shapes, geom, draw_ctx->sh_cfg); - DRW_shgroup_state_disable(sgl->light_spot_volume_rect_outside, DRW_STATE_CULL_FRONT); - DRW_shgroup_state_enable(sgl->light_spot_volume_rect_outside, DRW_STATE_CULL_BACK); + sgl->light_spot_volume_rect_outside = buffer_instance_alpha(grp_cull_back, geom); /* Camera stereo volumes */ geom = DRW_cache_cube_get(); - sgl->camera_stereo_volume = shgroup_instance_alpha(sgl->transp_shapes, geom, draw_ctx->sh_cfg); + sgl->camera_stereo_volume = buffer_instance_alpha(grp_transp, geom); geom = DRW_cache_quad_get(); - sgl->camera_stereo_plane = shgroup_instance_alpha(sgl->transp_shapes, geom, draw_ctx->sh_cfg); - DRW_shgroup_state_disable(sgl->camera_stereo_plane, DRW_STATE_CULL_FRONT); + sgl->camera_stereo_plane = buffer_instance_alpha(grp_cull_none, geom); } { @@ -1498,7 +1528,7 @@ static void OBJECT_cache_init(void *vedata) DRWShadingGroup *grp; static float outlineWidth, size; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_POINT; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND; psl->ob_center = DRW_pass_create("Obj Center Pass", state); outlineWidth = 1.0f * U.pixelsize; @@ -1508,7 +1538,7 @@ static void OBJECT_cache_init(void *vedata) GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, draw_ctx->sh_cfg); /* Active */ - grp = DRW_shgroup_point_batch_create(sh, psl->ob_center); + grp = DRW_shgroup_create(sh, psl->ob_center); DRW_shgroup_uniform_float(grp, "size", &size, 1); DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1); DRW_shgroup_uniform_vec4(grp, "color", gb->colorActive, 1); @@ -1516,47 +1546,35 @@ static void OBJECT_cache_init(void *vedata) if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { DRW_shgroup_world_clip_planes_from_rv3d(grp, draw_ctx->rv3d); } - stl->g_data->center_active = grp; + /* TODO find better name. */ + stl->g_data->center_active = buffer_dynpoints_uniform_color(grp); /* Select */ - grp = DRW_shgroup_point_batch_create(sh, psl->ob_center); + grp = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4(grp, "color", gb->colorSelect, 1); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, draw_ctx->rv3d); - } - stl->g_data->center_selected = grp; + stl->g_data->center_selected = buffer_dynpoints_uniform_color(grp); /* Deselect */ - grp = DRW_shgroup_point_batch_create(sh, psl->ob_center); + grp = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4(grp, "color", gb->colorDeselect, 1); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, draw_ctx->rv3d); - } - stl->g_data->center_deselected = grp; + stl->g_data->center_deselected = buffer_dynpoints_uniform_color(grp); /* Select (library) */ - grp = DRW_shgroup_point_batch_create(sh, psl->ob_center); + grp = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4(grp, "color", gb->colorLibrarySelect, 1); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, draw_ctx->rv3d); - } - stl->g_data->center_selected_lib = grp; + stl->g_data->center_selected_lib = buffer_dynpoints_uniform_color(grp); /* Deselect (library) */ - grp = DRW_shgroup_point_batch_create(sh, psl->ob_center); + grp = DRW_shgroup_create_sub(grp); DRW_shgroup_uniform_vec4(grp, "color", gb->colorLibrary, 1); - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_world_clip_planes_from_rv3d(grp, draw_ctx->rv3d); - } - stl->g_data->center_deselected_lib = grp; + stl->g_data->center_deselected_lib = buffer_dynpoints_uniform_color(grp); } { /* Particle Pass */ psl->particle = DRW_pass_create("Particle Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_POINT | - DRW_STATE_BLEND); + DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND); } } @@ -1593,7 +1611,7 @@ static void DRW_shgroup_mball_handles(OBJECT_ShadingGroupList *sgl, draw_scale_xform[1][3] = world_pos[1]; draw_scale_xform[2][3] = world_pos[2]; - DRW_shgroup_call_dynamic_add(sgl->mball_handle, draw_scale_xform, &ml->rad, color); + DRW_buffer_add_entry(sgl->mball_handle, draw_scale_xform, &ml->rad, color); } } @@ -1619,25 +1637,25 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { /* Don't draw the center if it's selected or active */ if (theme_id == TH_LIGHT) { - DRW_shgroup_call_dynamic_add(sgl->light_center, ob->obmat[3]); + DRW_buffer_add_entry(sgl->light_center, ob->obmat[3]); } } /* First circle */ - DRW_shgroup_call_dynamic_add(sgl->light_circle, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->light_circle, ob->obmat[3], color); /* draw dashed outer circle for shadow */ - DRW_shgroup_call_dynamic_add(sgl->light_circle_shadow, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->light_circle_shadow, ob->obmat[3], color); /* Distance */ if (ELEM(la->type, LA_SUN, LA_AREA)) { - DRW_shgroup_call_dynamic_add(sgl->light_distance, color, &zero, &la->dist, ob->obmat); + DRW_buffer_add_entry(sgl->light_distance, color, &zero, &la->dist, ob->obmat); } copy_m4_m4(shapemat, ob->obmat); if (la->type == LA_SUN) { - DRW_shgroup_call_dynamic_add(sgl->light_sunrays, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->light_sunrays, ob->obmat[3], color); } else if (la->type == LA_SPOT) { float size[3], sizemat[4][4]; @@ -1659,42 +1677,39 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye mul_m4_m4m4(spotblendmat, shapemat, sizemat); if (la->mode & LA_SQUARE) { - DRW_shgroup_call_dynamic_add(sgl->light_spot_pyramid, color, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_pyramid, color, &one, shapemat); /* hide line if it is zero size or overlaps with outer border, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != 1.0f) { - DRW_shgroup_call_dynamic_add(sgl->light_spot_blend_rect, color, &one, spotblendmat); + DRW_buffer_add_entry(sgl->light_spot_blend_rect, color, &one, spotblendmat); } if (la->mode & LA_SHOW_CONE) { - DRW_shgroup_call_dynamic_add(sgl->light_spot_volume_rect, cone_inside, &one, shapemat); - DRW_shgroup_call_dynamic_add( - sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume_rect, cone_inside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume_rect_outside, cone_outside, &one, shapemat); } } else { - DRW_shgroup_call_dynamic_add(sgl->light_spot_cone, color, shapemat); + DRW_buffer_add_entry(sgl->light_spot_cone, color, shapemat); /* hide line if it is zero size or overlaps with outer border, * previously it adjusted to always to show it but that seems * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != 1.0f) { - DRW_shgroup_call_dynamic_add(sgl->light_spot_blend, color, &one, spotblendmat); + DRW_buffer_add_entry(sgl->light_spot_blend, color, &one, spotblendmat); } if (la->mode & LA_SHOW_CONE) { - DRW_shgroup_call_dynamic_add(sgl->light_spot_volume, cone_inside, &one, shapemat); - DRW_shgroup_call_dynamic_add(sgl->light_spot_volume_outside, cone_outside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume, cone_inside, &one, shapemat); + DRW_buffer_add_entry(sgl->light_spot_volume_outside, cone_outside, &one, shapemat); } } - DRW_shgroup_call_dynamic_add( - sgl->light_buflimit, color, &la->clipsta, &la->clipend, ob->obmat); - DRW_shgroup_call_dynamic_add( - sgl->light_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat); + DRW_buffer_add_entry(sgl->light_buflimit, color, &la->clipsta, &la->clipend, ob->obmat); + DRW_buffer_add_entry(sgl->light_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat); } else if (la->type == LA_AREA) { float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4]; @@ -1706,10 +1721,10 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye } if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) { - DRW_shgroup_call_dynamic_add(sgl->light_area_disk, color, &la->area_size, shapemat); + DRW_buffer_add_entry(sgl->light_area_disk, color, &la->area_size, shapemat); } else { - DRW_shgroup_call_dynamic_add(sgl->light_area_square, color, &la->area_size, shapemat); + DRW_buffer_add_entry(sgl->light_area_square, color, &la->area_size, shapemat); } } @@ -1719,12 +1734,12 @@ static void DRW_shgroup_light(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLaye shapemat[0][1] = shapemat[0][2] = 0.0f; shapemat[1][0] = shapemat[1][2] = 0.0f; shapemat[2][0] = shapemat[2][1] = 0.0f; - DRW_shgroup_call_dynamic_add(sgl->light_area_sphere, color, &la->area_size, shapemat); + DRW_buffer_add_entry(sgl->light_area_sphere, color, &la->area_size, shapemat); } /* Line and point going to the ground */ - DRW_shgroup_call_dynamic_add(sgl->light_groundline, ob->obmat[3]); - DRW_shgroup_call_dynamic_add(sgl->light_groundpoint, ob->obmat[3]); + DRW_buffer_add_entry(sgl->light_groundline, ob->obmat[3]); + DRW_buffer_add_entry(sgl->light_groundpoint, ob->obmat[3]); } static GPUBatch *batch_camera_path_get(ListBase *camera_paths, @@ -1820,19 +1835,19 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl copy_v2_v2(drw_tria_dummy[eye][1], cam->runtime.drw_corners[eye][0]); if (is_stereo3d_cameras) { - DRW_shgroup_call_dynamic_add(sgl->camera_frame, - color, - cam->runtime.drw_corners[eye], - &cam->runtime.drw_depth[eye], - cam->runtime.drw_tria, - obmat); + DRW_buffer_add_entry(sgl->camera_frame, + color, + cam->runtime.drw_corners[eye], + &cam->runtime.drw_depth[eye], + cam->runtime.drw_tria, + obmat); - DRW_shgroup_call_dynamic_add(sgl->camera, - color, - cam->runtime.drw_corners[eye], - &cam->runtime.drw_depth[eye], - drw_tria_dummy[eye], - obmat); + DRW_buffer_add_entry(sgl->camera, + color, + cam->runtime.drw_corners[eye], + &cam->runtime.drw_depth[eye], + drw_tria_dummy[eye], + obmat); } /* Connecting line. */ @@ -1841,8 +1856,8 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl /* Draw connecting lines. */ if (is_stereo3d_cameras) { - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, origin[0]); - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, origin[1]); + DRW_buffer_add_entry(sgl->relationship_lines, origin[0]); + DRW_buffer_add_entry(sgl->relationship_lines, origin[1]); } /* Draw convergence plane. */ @@ -1879,9 +1894,9 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl translate_m4(plane_mat, 2.0f * cam->shiftx, (width / height) * 2.0f * cam->shifty, 0.0f); if (v3d->stereo3d_convergence_alpha > 0.0f) { - DRW_shgroup_call_dynamic_add(sgl->camera_stereo_plane, color_plane[0], &one, plane_mat); + DRW_buffer_add_entry(sgl->camera_stereo_plane, color_plane[0], &one, plane_mat); } - DRW_shgroup_call_dynamic_add(sgl->camera_stereo_plane_wires, color_plane[1], &one, plane_mat); + DRW_buffer_add_entry(sgl->camera_stereo_plane_wires, color_plane[1], &one, plane_mat); } /* Draw convergence volume. */ @@ -1905,10 +1920,9 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl invert_m4_m4(persinv, persmat); if (v3d->stereo3d_volume_alpha > 0.0f) { - DRW_shgroup_call_dynamic_add(sgl->camera_stereo_volume, color_volume[eye], &one, persinv); + DRW_buffer_add_entry(sgl->camera_stereo_volume, color_volume[eye], &one, persinv); } - DRW_shgroup_call_dynamic_add( - sgl->camera_stereo_volume_wires, color_volume[2], &one, persinv); + DRW_buffer_add_entry(sgl->camera_stereo_volume_wires, color_volume[2], &one, persinv); } } } @@ -1916,13 +1930,14 @@ static void camera_view3d_stereoscopy_display_extra(OBJECT_ShadingGroupList *sgl static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl, Scene *scene, View3D *v3d, - const Object *camera_object, + Object *camera_object, Object *ob, const float color[4], const bool is_select) { const DRWContextState *draw_ctx = DRW_context_state_get(); Camera *cam = ob->data; + const Object *orig_camera_object = DEG_get_original_object(camera_object); if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0) { return; @@ -2003,7 +2018,7 @@ static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl, } if (is_select) { - DRW_select_load_id(camera_object->select_id | (track_index << 16)); + DRW_select_load_id(orig_camera_object->runtime.select_id | (track_index << 16)); track_index++; } @@ -2021,7 +2036,7 @@ static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl, }; mul_m4_m4m4(bundle_mat, bundle_mat, bundle_scale_mat); - DRW_shgroup_call_dynamic_add(sgl->sphere_solid, bundle_mat, bundle_color_v4); + DRW_buffer_add_entry(sgl->sphere_solid, bundle_mat, bundle_color_v4); } else { DRW_shgroup_empty_ex( @@ -2055,7 +2070,7 @@ static void camera_view3d_reconstruction(OBJECT_ShadingGroupList *sgl, GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); DRWShadingGroup *shading_group = DRW_shgroup_create(shader, sgl->non_meshes); DRW_shgroup_uniform_vec4(shading_group, "color", camera_path_color, 1); - DRW_shgroup_call_add(shading_group, geom, camera_mat); + DRW_shgroup_call(shading_group, geom, camera_mat); } } } @@ -2069,7 +2084,7 @@ static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLay RegionView3D *rv3d = draw_ctx->rv3d; Camera *cam = ob->data; - const Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); + Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); const bool is_select = DRW_state_is_select(); const bool is_active = (ob == camera_object); const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB)); @@ -2136,31 +2151,31 @@ static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLay copy_m4_m4(mat, ob->obmat); } - DRW_shgroup_call_dynamic_add(sgl->camera_frame, - color, - cam->runtime.drw_corners[0], - &cam->runtime.drw_depth[0], - cam->runtime.drw_tria, - mat); + DRW_buffer_add_entry(sgl->camera_frame, + color, + cam->runtime.drw_corners[0], + &cam->runtime.drw_depth[0], + cam->runtime.drw_tria, + mat); } else { if (!is_stereo3d_cameras) { - DRW_shgroup_call_dynamic_add(sgl->camera, - color, - cam->runtime.drw_corners[0], - &cam->runtime.drw_depth[0], - cam->runtime.drw_tria, - ob->obmat); + DRW_buffer_add_entry(sgl->camera, + color, + cam->runtime.drw_corners[0], + &cam->runtime.drw_depth[0], + cam->runtime.drw_tria, + ob->obmat); } /* Active cam */ if (is_active) { - DRW_shgroup_call_dynamic_add(sgl->camera_tria, - color, - cam->runtime.drw_corners[0], - &cam->runtime.drw_depth[0], - cam->runtime.drw_tria, - ob->obmat); + DRW_buffer_add_entry(sgl->camera_tria, + color, + cam->runtime.drw_corners[0], + &cam->runtime.drw_depth[0], + cam->runtime.drw_tria, + ob->obmat); } } @@ -2177,16 +2192,16 @@ static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLay size_to_mat4(sizemat, size); mul_m4_m4m4(cam->runtime.drw_focusmat, cam->runtime.drw_focusmat, sizemat); - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( sgl->camera_focus, (is_active ? col_hi : col), &cam->drawsize, cam->runtime.drw_focusmat); - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( sgl->camera_clip, color, &cam->clip_start, &cam->clip_end, cam->runtime.drw_normalmat); - DRW_shgroup_call_dynamic_add(sgl->camera_clip_points, - (is_active ? col_hi : col), - &cam->clip_start, - &cam->clip_end, - cam->runtime.drw_normalmat); + DRW_buffer_add_entry(sgl->camera_clip_points, + (is_active ? col_hi : col), + &cam->clip_start, + &cam->clip_end, + cam->runtime.drw_normalmat); } if (cam->flag & CAM_SHOWMIST) { @@ -2195,13 +2210,13 @@ static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLay if (world) { static float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}, col_hi[4] = {1.0f, 1.0f, 1.0f, 1.0f}; world->mistend = world->miststa + world->mistdist; - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry( sgl->camera_mist, color, &world->miststa, &world->mistend, cam->runtime.drw_normalmat); - DRW_shgroup_call_dynamic_add(sgl->camera_mist_points, - (is_active ? col_hi : col), - &world->miststa, - &world->mistend, - cam->runtime.drw_normalmat); + DRW_buffer_add_entry(sgl->camera_mist_points, + (is_active ? col_hi : col), + &world->miststa, + &world->mistend, + cam->runtime.drw_normalmat); } } @@ -2223,26 +2238,26 @@ static void DRW_shgroup_empty_ex(OBJECT_ShadingGroupList *sgl, { switch (draw_type) { case OB_PLAINAXES: - DRW_shgroup_call_dynamic_add(sgl->plain_axes, color, draw_size, mat); + DRW_buffer_add_entry(sgl->plain_axes, color, draw_size, mat); break; case OB_SINGLE_ARROW: - DRW_shgroup_call_dynamic_add(sgl->single_arrow, color, draw_size, mat); - DRW_shgroup_call_dynamic_add(sgl->single_arrow_line, color, draw_size, mat); + DRW_buffer_add_entry(sgl->single_arrow, color, draw_size, mat); + DRW_buffer_add_entry(sgl->single_arrow_line, color, draw_size, mat); break; case OB_CUBE: - DRW_shgroup_call_dynamic_add(sgl->cube, color, draw_size, mat); + DRW_buffer_add_entry(sgl->cube, color, draw_size, mat); break; case OB_CIRCLE: - DRW_shgroup_call_dynamic_add(sgl->circle, color, draw_size, mat); + DRW_buffer_add_entry(sgl->circle, color, draw_size, mat); break; case OB_EMPTY_SPHERE: - DRW_shgroup_call_dynamic_add(sgl->sphere, color, draw_size, mat); + DRW_buffer_add_entry(sgl->sphere, color, draw_size, mat); break; case OB_EMPTY_CONE: - DRW_shgroup_call_dynamic_add(sgl->cone, color, draw_size, mat); + DRW_buffer_add_entry(sgl->cone, color, draw_size, mat); break; case OB_ARROWS: - DRW_shgroup_call_dynamic_add(sgl->empty_axes, color, draw_size, mat); + DRW_buffer_add_entry(sgl->empty_axes, color, draw_size, mat); break; case OB_EMPTY_IMAGE: BLI_assert(!"Should never happen, use DRW_shgroup_empty instead."); @@ -2334,19 +2349,19 @@ static void DRW_shgroup_forcefield(OBJECT_ShadingGroupList *sgl, Object *ob, Vie switch (pd->forcefield) { case PFIELD_WIND: - DRW_shgroup_call_dynamic_add(sgl->field_wind, color, &pd->drawvec1, ob->obmat); + DRW_buffer_add_entry(sgl->field_wind, color, &pd->drawvec1, ob->obmat); break; case PFIELD_FORCE: - DRW_shgroup_call_dynamic_add(sgl->field_force, color, &pd->drawvec1, ob->obmat); + DRW_buffer_add_entry(sgl->field_force, color, &pd->drawvec1, ob->obmat); break; case PFIELD_VORTEX: - DRW_shgroup_call_dynamic_add(sgl->field_vortex, color, &pd->drawvec1, ob->obmat); + DRW_buffer_add_entry(sgl->field_vortex, color, &pd->drawvec1, ob->obmat); break; case PFIELD_GUIDE: if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path && ob->runtime.curve_cache->path->data) { - DRW_shgroup_call_dynamic_add(sgl->field_curve_sta, color, &pd->f_strength, ob->obmat); - DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->f_strength, ob->obmat); + DRW_buffer_add_entry(sgl->field_curve_sta, color, &pd->f_strength, ob->obmat); + DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->f_strength, ob->obmat); } break; } @@ -2354,33 +2369,29 @@ static void DRW_shgroup_forcefield(OBJECT_ShadingGroupList *sgl, Object *ob, Vie if (pd->falloff == PFIELD_FALL_SPHERE) { /* as last, guide curve alters it */ if ((pd->flag & PFIELD_USEMAX) != 0) { - DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->maxdist, ob->obmat); + DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->maxdist, ob->obmat); } if ((pd->flag & PFIELD_USEMIN) != 0) { - DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->mindist, ob->obmat); + DRW_buffer_add_entry(sgl->field_curve_end, color, &pd->mindist, ob->obmat); } } else if (pd->falloff == PFIELD_FALL_TUBE) { if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) { - DRW_shgroup_call_dynamic_add( - sgl->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat); + DRW_buffer_add_entry(sgl->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat); } if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) { - DRW_shgroup_call_dynamic_add( - sgl->field_tube_limit, color, &pd->drawvec_falloff_min, ob->obmat); + DRW_buffer_add_entry(sgl->field_tube_limit, color, &pd->drawvec_falloff_min, ob->obmat); } } else if (pd->falloff == PFIELD_FALL_CONE) { if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) { - DRW_shgroup_call_dynamic_add( - sgl->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat); + DRW_buffer_add_entry(sgl->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat); } if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) { - DRW_shgroup_call_dynamic_add( - sgl->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat); + DRW_buffer_add_entry(sgl->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat); } } } @@ -2412,7 +2423,7 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl, translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f); mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, voxel_cubemat); + DRW_buffer_add_entry(sgl->cube, color, &one, voxel_cubemat); /* Don't show smoke before simulation starts, this could be made an option in the future. */ if (!sds->draw_velocity || !sds->fluid || CFRA < sds->point_cache[0]->startframe) { @@ -2426,12 +2437,11 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl, if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED && sds->axis_slice_method == AXIS_SLICE_SINGLE) { - float invviewmat[4][4]; - DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV); + float viewinv[4][4]; + DRW_view_viewmat_get(NULL, viewinv, true); - const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? - axis_dominant_v3_single(invviewmat[2]) : - sds->slice_axis - 1; + const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) : + sds->slice_axis - 1; slice_axis = axis; line_count /= sds->res[axis]; } @@ -2446,7 +2456,7 @@ static void DRW_shgroup_volume_extra(OBJECT_ShadingGroupList *sgl, DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale); DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); - DRW_shgroup_call_procedural_lines_add(grp, line_count, ob->obmat); + DRW_shgroup_call_procedural_lines(grp, line_count, ob->obmat); BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd)); } @@ -2472,7 +2482,7 @@ static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLa static float one = 1.0f; DRW_object_wire_theme_get(ob, view_layer, &color); - DRW_shgroup_call_dynamic_add(sgl->speaker, color, &one, ob->obmat); + DRW_buffer_add_entry(sgl->speaker, color, &one, ob->obmat); } typedef struct OBJECT_LightProbeEngineData { @@ -2547,7 +2557,7 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1); DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1); DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1); - DRW_shgroup_call_procedural_points_add(grp, cell_count, NULL); + DRW_shgroup_call_procedural_points(grp, cell_count, NULL); } else if (prb->type == LIGHTPROBE_TYPE_CUBE) { float draw_size = 1.0f; @@ -2556,17 +2566,17 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, // unit_m4(prb_data->probe_cube_mat); // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]); - DRWShadingGroup *grp = shgroup_theme_id_to_probe_cube_outline_shgrp( + DRWCallBuffer *buf = buffer_theme_id_to_probe_cube_outline_shgrp( stl, theme_id, ob->base_flag); /* TODO remove or change the drawing of the cube probes. Theses line draws nothing on purpose * to keep the call ids correct. */ zero_m4(probe_cube_mat); - DRW_shgroup_call_dynamic_add(grp, call_id, &draw_size, probe_cube_mat); + DRW_buffer_add_entry(buf, call_id, &draw_size, probe_cube_mat); } else { float draw_size = 1.0f; - DRWShadingGroup *grp = shgroup_theme_id_to_probe_planar_outline_shgrp(stl, theme_id); - DRW_shgroup_call_dynamic_add(grp, call_id, &draw_size, ob->obmat); + DRWCallBuffer *buf = buffer_theme_id_to_probe_planar_outline_shgrp(stl, theme_id); + DRW_buffer_add_entry(buf, call_id, &draw_size, ob->obmat); } *call_id += 1; @@ -2574,14 +2584,14 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, switch (prb->type) { case LIGHTPROBE_TYPE_PLANAR: - DRW_shgroup_call_dynamic_add(sgl->probe_planar, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->probe_planar, ob->obmat[3], color); break; case LIGHTPROBE_TYPE_GRID: - DRW_shgroup_call_dynamic_add(sgl->probe_grid, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->probe_grid, ob->obmat[3], color); break; case LIGHTPROBE_TYPE_CUBE: default: - DRW_shgroup_call_dynamic_add(sgl->probe_cube, ob->obmat[3], color); + DRW_buffer_add_entry(sgl->probe_cube, ob->obmat[3], color); break; } @@ -2590,13 +2600,13 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, copy_m4_m4(mat, ob->obmat); normalize_m4(mat); - DRW_shgroup_call_dynamic_add(sgl->single_arrow, color, &ob->empty_drawsize, mat); - DRW_shgroup_call_dynamic_add(sgl->single_arrow_line, color, &ob->empty_drawsize, mat); + DRW_buffer_add_entry(sgl->single_arrow, color, &ob->empty_drawsize, mat); + DRW_buffer_add_entry(sgl->single_arrow_line, color, &ob->empty_drawsize, mat); copy_m4_m4(mat, ob->obmat); zero_v3(mat[2]); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, mat); + DRW_buffer_add_entry(sgl->cube, color, &one, mat); } if ((prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0) { @@ -2610,8 +2620,8 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, } if (prb->type == LIGHTPROBE_TYPE_GRID || prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) { - DRW_shgroup_call_dynamic_add(sgl->cube, color, &prb->distgridinf, ob->obmat); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &prb->distfalloff, ob->obmat); + DRW_buffer_add_entry(sgl->cube, color, &prb->distgridinf, ob->obmat); + DRW_buffer_add_entry(sgl->cube, color, &prb->distfalloff, ob->obmat); } else if (prb->type == LIGHTPROBE_TYPE_PLANAR) { float rangemat[4][4]; @@ -2619,17 +2629,17 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, normalize_v3(rangemat[2]); mul_v3_fl(rangemat[2], prb->distinf); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, rangemat); + DRW_buffer_add_entry(sgl->cube, color, &one, rangemat); copy_m4_m4(rangemat, ob->obmat); normalize_v3(rangemat[2]); mul_v3_fl(rangemat[2], prb->distfalloff); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, rangemat); + DRW_buffer_add_entry(sgl->cube, color, &one, rangemat); } else { - DRW_shgroup_call_dynamic_add(sgl->sphere, color, &prb->distgridinf, ob->obmat); - DRW_shgroup_call_dynamic_add(sgl->sphere, color, &prb->distfalloff, ob->obmat); + DRW_buffer_add_entry(sgl->sphere, color, &prb->distgridinf, ob->obmat); + DRW_buffer_add_entry(sgl->sphere, color, &prb->distfalloff, ob->obmat); } } @@ -2648,10 +2658,10 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, } if (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) { - DRW_shgroup_call_dynamic_add(sgl->cube, color, dist, obmat); + DRW_buffer_add_entry(sgl->cube, color, dist, obmat); } else { - DRW_shgroup_call_dynamic_add(sgl->sphere, color, dist, obmat); + DRW_buffer_add_entry(sgl->sphere, color, dist, obmat); } } } @@ -2690,9 +2700,8 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, normalize_m4_m4(clipmat, ob->obmat); mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]); - DRW_shgroup_call_dynamic_add( - sgl->light_buflimit, color, &prb->clipsta, &prb->clipend, clipmat); - DRW_shgroup_call_dynamic_add( + DRW_buffer_add_entry(sgl->light_buflimit, color, &prb->clipsta, &prb->clipend, clipmat); + DRW_buffer_add_entry( sgl->light_buflimit_points, color, &prb->clipsta, &prb->clipend, clipmat); } } @@ -2700,8 +2709,8 @@ static void DRW_shgroup_lightprobe(OBJECT_Shaders *sh_data, /* Line and point going to the ground */ if (prb->type == LIGHTPROBE_TYPE_CUBE) { - DRW_shgroup_call_dynamic_add(sgl->light_groundline, ob->obmat[3]); - DRW_shgroup_call_dynamic_add(sgl->light_groundpoint, ob->obmat[3]); + DRW_buffer_add_entry(sgl->light_groundline, ob->obmat[3]); + DRW_buffer_add_entry(sgl->light_groundpoint, ob->obmat[3]); } } @@ -2711,20 +2720,20 @@ static void DRW_shgroup_relationship_lines(OBJECT_ShadingGroupList *sgl, Object *ob) { if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) { - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->runtime.parent_display_origin); - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]); + DRW_buffer_add_entry(sgl->relationship_lines, ob->runtime.parent_display_origin); + DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]); } if (ob->rigidbody_constraint) { Object *rbc_ob1 = ob->rigidbody_constraint->ob1; Object *rbc_ob2 = ob->rigidbody_constraint->ob2; if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) { - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, rbc_ob1->obmat[3]); - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]); + DRW_buffer_add_entry(sgl->relationship_lines, rbc_ob1->obmat[3]); + DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]); } if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) { - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, rbc_ob2->obmat[3]); - DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]); + DRW_buffer_add_entry(sgl->relationship_lines, rbc_ob2->obmat[3]); + DRW_buffer_add_entry(sgl->relationship_lines, ob->obmat[3]); } } @@ -2756,8 +2765,8 @@ static void DRW_shgroup_relationship_lines(OBJECT_ShadingGroupList *sgl, } if (camob) { - DRW_shgroup_call_dynamic_add(sgl->constraint_lines, camob->obmat[3]); - DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ob->obmat[3]); + DRW_buffer_add_entry(sgl->constraint_lines, camob->obmat[3]); + DRW_buffer_add_entry(sgl->constraint_lines, ob->obmat[3]); } } else { @@ -2778,8 +2787,8 @@ static void DRW_shgroup_relationship_lines(OBJECT_ShadingGroupList *sgl, unit_m4(ct->matrix); } - DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ct->matrix[3]); - DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ob->obmat[3]); + DRW_buffer_add_entry(sgl->constraint_lines, ct->matrix[3]); + DRW_buffer_add_entry(sgl->constraint_lines, ob->obmat[3]); } if (cti->flush_constraint_targets) { @@ -2802,32 +2811,32 @@ static void DRW_shgroup_object_center(OBJECT_StorageList *stl, return; } const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob); - DRWShadingGroup *shgroup; + DRWCallBuffer *buf; if (ob == OBACT(view_layer)) { - shgroup = stl->g_data->center_active; + buf = stl->g_data->center_active; } else if (ob->base_flag & BASE_SELECTED) { if (is_library) { - shgroup = stl->g_data->center_selected_lib; + buf = stl->g_data->center_selected_lib; } else { - shgroup = stl->g_data->center_selected; + buf = stl->g_data->center_selected; } } else if (v3d->flag & V3D_DRAW_CENTERS) { if (is_library) { - shgroup = stl->g_data->center_deselected_lib; + buf = stl->g_data->center_deselected_lib; } else { - shgroup = stl->g_data->center_deselected; + buf = stl->g_data->center_deselected; } } else { return; } - DRW_shgroup_call_dynamic_add(shgroup, ob->obmat[3]); + DRW_buffer_add_entry(buf, ob->obmat[3]); } static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id) @@ -2877,7 +2886,7 @@ static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, float color[4]; UI_GetThemeColor4fv(theme_id, color); - DRW_shgroup_call_dynamic_add(sgl->texspace, color, &one, tmp); + DRW_buffer_add_entry(sgl->texspace, color, &one, tmp); } static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id) @@ -2914,7 +2923,7 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); mul_m4_m4m4(tmp, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, tmp); + DRW_buffer_add_entry(sgl->cube, color, &one, tmp); break; case OB_BOUND_SPHERE: size[0] = max_fff(size[0], size[1], size[2]); @@ -2922,7 +2931,7 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); mul_m4_m4m4(tmp, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->sphere, color, &one, tmp); + DRW_buffer_add_entry(sgl->sphere, color, &one, tmp); break; case OB_BOUND_CYLINDER: size[0] = max_ff(size[0], size[1]); @@ -2930,7 +2939,7 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the size_to_mat4(tmp, size); copy_v3_v3(tmp[3], center); mul_m4_m4m4(tmp, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->cylinder, color, &one, tmp); + DRW_buffer_add_entry(sgl->cylinder, color, &one, tmp); break; case OB_BOUND_CONE: size[0] = max_ff(size[0], size[1]); @@ -2941,7 +2950,7 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the swap_v3_v3(tmp[1], tmp[2]); tmp[3][2] -= size[2]; mul_m4_m4m4(tmp, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->cone, color, &one, tmp); + DRW_buffer_add_entry(sgl->cone, color, &one, tmp); break; case OB_BOUND_CAPSULE: size[0] = max_ff(size[0], size[1]); @@ -2950,14 +2959,14 @@ static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int the copy_v2_v2(tmp[3], center); tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]); mul_m4_m4m4(final_mat, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->capsule_cap, color, &one, final_mat); + DRW_buffer_add_entry(sgl->capsule_cap, color, &one, final_mat); negate_v3(tmp[2]); tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]); mul_m4_m4m4(final_mat, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->capsule_cap, color, &one, final_mat); + DRW_buffer_add_entry(sgl->capsule_cap, color, &one, final_mat); tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f); mul_m4_m4m4(final_mat, ob->obmat, tmp); - DRW_shgroup_call_dynamic_add(sgl->capsule_body, color, &one, final_mat); + DRW_buffer_add_entry(sgl->capsule_body, color, &one, final_mat); break; } } @@ -2980,13 +2989,10 @@ static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, if (draw_as != PART_DRAW_PATH) { struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys); DRWShadingGroup *shgrp = NULL; - static int screen_space[2] = {0, 1}; + struct GPUBatch *shape = NULL; static float def_prim_col[3] = {0.5f, 0.5f, 0.5f}; static float def_sec_col[3] = {1.0f, 1.0f, 1.0f}; - /* Dummy particle format for instancing to work. */ - DRW_shgroup_instance_format(e_data.particle_format, {{"dummy", DRW_ATTR_FLOAT, 1}}); - Material *ma = give_current_material(ob, part->omat); switch (draw_as) { @@ -2997,43 +3003,36 @@ static void OBJECT_cache_populate_particles(OBJECT_Shaders *sh_data, DRW_shgroup_uniform_float(shgrp, "pixel_size", DRW_viewport_pixelsize_get(), 1); DRW_shgroup_uniform_float(shgrp, "size", &part->draw_size, 1); DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp); - DRW_shgroup_call_add(shgrp, geom, mat); + DRW_shgroup_call(shgrp, geom, mat); break; case PART_DRAW_CROSS: - shgrp = DRW_shgroup_instance_create(sh_data->part_prim, - psl->particle, - DRW_cache_particles_get_prim(PART_DRAW_CROSS), - e_data.particle_format); + shgrp = DRW_shgroup_create(sh_data->part_prim, psl->particle); DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp); DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1); - DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1); + DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1); + DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", false); + shape = DRW_cache_particles_get_prim(PART_DRAW_CROSS); + DRW_shgroup_call_instances_with_attribs(shgrp, shape, NULL, geom); break; case PART_DRAW_CIRC: - shgrp = DRW_shgroup_instance_create(sh_data->part_prim, - psl->particle, - DRW_cache_particles_get_prim(PART_DRAW_CIRC), - e_data.particle_format); + shape = DRW_cache_particles_get_prim(PART_DRAW_CIRC); + shgrp = DRW_shgroup_create(sh_data->part_prim, psl->particle); DRW_shgroup_uniform_texture(shgrp, "ramp", G_draw.ramp); DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1); - DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[1], 1); + DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1); + DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", true); + DRW_shgroup_call_instances_with_attribs(shgrp, shape, NULL, geom); break; case PART_DRAW_AXIS: - shgrp = DRW_shgroup_instance_create(sh_data->part_axis, - psl->particle, - DRW_cache_particles_get_prim(PART_DRAW_AXIS), - e_data.particle_format); - DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1); + shape = DRW_cache_particles_get_prim(PART_DRAW_AXIS); + shgrp = DRW_shgroup_create(sh_data->part_axis, psl->particle); + DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1); + DRW_shgroup_uniform_bool_copy(shgrp, "screen_space", false); + DRW_shgroup_call_instances_with_attribs(shgrp, shape, NULL, geom); break; default: break; } - - if (shgrp) { - if (draw_as != PART_DRAW_DOT) { - DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1); - DRW_shgroup_instance_batch(shgrp, geom); - } - } } } } @@ -3096,6 +3095,24 @@ static void OBJECT_gpencil_color_names(Object *ob, struct DRWTextStore *dt, ucha } } +BLI_INLINE OBJECT_DupliData *OBJECT_duplidata_get(Object *ob, void *vedata, bool *init) +{ + OBJECT_DupliData **dupli_data = (OBJECT_DupliData **)DRW_duplidata_get(vedata); + *init = false; + if (!ELEM(ob->type, OB_MESH, OB_SURF, OB_LATTICE, OB_CURVE, OB_FONT)) { + return NULL; + } + + if (dupli_data) { + if (*dupli_data == NULL) { + *dupli_data = MEM_callocN(sizeof(OBJECT_DupliData), "OBJECT_DupliData"); + *init = true; + } + return *dupli_data; + } + return NULL; +} + static void OBJECT_cache_populate(void *vedata, Object *ob) { OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl; @@ -3132,10 +3149,15 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) /* Show if this is the camera we're looking through since it's useful for selecting. */ (((rv3d->persp == RV3D_CAMOB) && ((ID *)v3d->camera == ob->id.orig_id)) == 0)); + /* Fast path for duplis. */ + bool init_duplidata; + OBJECT_DupliData *dupli_data = OBJECT_duplidata_get(ob, vedata, &init_duplidata); + if (do_outlines) { if (!BKE_object_is_in_editmode(ob) && !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) { struct GPUBatch *geom; + DRWShadingGroup *shgroup = NULL; /* This fixes only the biggest case which is a plane in ortho view. */ int flat_axis = 0; @@ -3143,185 +3165,211 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) DRW_object_is_flat(ob, &flat_axis) && DRW_object_axis_orthogonal_to_view(ob, flat_axis)); - if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) { - geom = DRW_cache_object_edge_detection_get(ob, NULL); + if (dupli_data && !init_duplidata) { + geom = dupli_data->outline_geom; + shgroup = dupli_data->outline_shgrp; } else { - geom = DRW_cache_object_surface_get(ob); - } + if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) { + geom = DRW_cache_object_edge_detection_get(ob, NULL); + } + else { + geom = DRW_cache_object_surface_get(ob); + } - if (geom) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or_null( - stl, theme_id, ob->base_flag); - if (shgroup != NULL) { - DRW_shgroup_call_object_add(shgroup, geom, ob); + if (geom) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + shgroup = shgroup_theme_id_to_outline_or_null(stl, theme_id, ob->base_flag); } } - } - } - switch (ob->type) { - case OB_MESH: { - if (hide_object_extra) { - break; + if (shgroup && geom) { + DRW_shgroup_call_object(shgroup, geom, ob); } - Mesh *me = ob->data; - if (!is_edit_mode && me->totedge == 0) { - struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob); - if (geom) { - if (theme_id == TH_UNDEFINED) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - } - DRWShadingGroup *shgroup = shgroup_theme_id_to_point(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); - } + + if (init_duplidata) { + dupli_data->outline_shgrp = shgroup; + dupli_data->outline_geom = geom; } - else { - bool has_edit_mesh_cage = false; - /* TODO: Should be its own function. */ - if (is_edit_mode) { - BMEditMesh *embm = me->edit_mesh; - has_edit_mesh_cage = embm->mesh_eval_cage && - (embm->mesh_eval_cage != embm->mesh_eval_final); + } + } + + if (dupli_data && !init_duplidata) { + if (dupli_data->extra_shgrp && dupli_data->extra_geom) { + DRW_shgroup_call_object(dupli_data->extra_shgrp, dupli_data->extra_geom, ob); + } + } + else { + struct GPUBatch *geom = NULL; + DRWShadingGroup *shgroup = NULL; + switch (ob->type) { + case OB_MESH: { + if (hide_object_extra) { + break; } - if ((!is_edit_mode && me->totedge > 0) || has_edit_mesh_cage) { - struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob); + Mesh *me = ob->data; + if (!is_edit_mode && me->totedge == 0) { + geom = DRW_cache_mesh_all_verts_get(ob); if (geom) { if (theme_id == TH_UNDEFINED) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); } - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); + shgroup = shgroup_theme_id_to_point(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); + } + } + else { + bool has_edit_mesh_cage = false; + /* TODO: Should be its own function. */ + if (is_edit_mode) { + BMEditMesh *embm = me->edit_mesh; + has_edit_mesh_cage = embm->mesh_eval_cage && + (embm->mesh_eval_cage != embm->mesh_eval_final); + } + if ((!is_edit_mode && me->totedge > 0) || has_edit_mesh_cage) { + geom = DRW_cache_mesh_loose_edges_get(ob); + if (geom) { + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); + } } } - } - break; - } - case OB_SURF: { - if (hide_object_extra) { - break; - } - struct GPUBatch *geom = DRW_cache_surf_edge_wire_get(ob); - if (geom == NULL) { break; } - if (theme_id == TH_UNDEFINED) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - } - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); - break; - } - case OB_LATTICE: { - if (!is_edit_mode) { + case OB_SURF: { if (hide_object_extra) { break; } - struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false); - if (theme_id == TH_UNDEFINED) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - } - - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); - } - break; - } - case OB_CURVE: { - if (!is_edit_mode) { - if (hide_object_extra) { + geom = DRW_cache_surf_edge_wire_get(ob); + if (geom == NULL) { break; } - struct GPUBatch *geom = DRW_cache_curve_edge_wire_get(ob); if (theme_id == TH_UNDEFINED) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); } - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); - } - break; - } - case OB_MBALL: { - if (!is_edit_mode) { - DRW_shgroup_mball_handles(sgl, ob, view_layer); - } - break; - } - case OB_LAMP: - if (hide_object_extra) { + shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); break; } - DRW_shgroup_light(sgl, ob, view_layer); - break; - case OB_CAMERA: - if (hide_object_extra) { + case OB_LATTICE: { + if (!is_edit_mode) { + if (hide_object_extra) { + break; + } + geom = DRW_cache_lattice_wire_get(ob, false); + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + + shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); + } break; } - DRW_shgroup_camera(sgl, ob, view_layer); - break; - case OB_EMPTY: - if (hide_object_extra) { + case OB_CURVE: { + if (!is_edit_mode) { + if (hide_object_extra) { + break; + } + geom = DRW_cache_curve_edge_wire_get(ob); + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); + } break; } - DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg); - break; - case OB_SPEAKER: - if (hide_object_extra) { + case OB_MBALL: { + if (!is_edit_mode) { + DRW_shgroup_mball_handles(sgl, ob, view_layer); + } break; } - DRW_shgroup_speaker(sgl, ob, view_layer); - break; - case OB_LIGHTPROBE: - if (hide_object_extra) { + case OB_LAMP: + if (hide_object_extra) { + break; + } + DRW_shgroup_light(sgl, ob, view_layer); break; - } - DRW_shgroup_lightprobe(sh_data, stl, psl, ob, view_layer); - break; - case OB_ARMATURE: { - if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) || - ((ob->dt < OB_WIRE) && !DRW_state_is_select())) { + case OB_CAMERA: + if (hide_object_extra) { + break; + } + DRW_shgroup_camera(sgl, ob, view_layer); break; - } - bArmature *arm = ob->data; - if (arm->edbo == NULL) { - if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) { - bool is_wire = (v3d->shading.type == OB_WIRE) || (ob->dt <= OB_WIRE) || - XRAY_FLAG_ENABLED(v3d); - DRWArmaturePasses passes = { - .bone_solid = (is_wire) ? NULL : sgl->bone_solid, - .bone_outline = sgl->bone_outline, - .bone_wire = sgl->bone_wire, - .bone_envelope = sgl->bone_envelope, - .bone_axes = sgl->bone_axes, - .relationship_lines = NULL, /* Don't draw relationship lines */ - .custom_shapes = stl->g_data->custom_shapes, - }; - DRW_shgroup_armature_object(ob, view_layer, passes, is_wire); + case OB_EMPTY: + if (hide_object_extra) { + break; + } + DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg); + break; + case OB_SPEAKER: + if (hide_object_extra) { + break; + } + DRW_shgroup_speaker(sgl, ob, view_layer); + break; + case OB_LIGHTPROBE: + if (hide_object_extra) { + break; + } + DRW_shgroup_lightprobe(sh_data, stl, psl, ob, view_layer); + break; + case OB_ARMATURE: { + if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) || + ((ob->dt < OB_WIRE) && !DRW_state_is_select())) { + break; + } + bArmature *arm = ob->data; + if (arm->edbo == NULL) { + if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) { + bool is_wire = (v3d->shading.type == OB_WIRE) || (ob->dt <= OB_WIRE) || + XRAY_FLAG_ENABLED(v3d); + DRWArmaturePasses passes = { + .bone_solid = (is_wire) ? NULL : sgl->bone_solid, + .bone_outline = sgl->bone_outline, + .bone_wire = sgl->bone_wire, + .bone_envelope = sgl->bone_envelope, + .bone_axes = sgl->bone_axes, + .relationship_lines = NULL, /* Don't draw relationship lines */ + .custom_shapes = stl->g_data->custom_shapes, + }; + DRW_shgroup_armature_object(ob, view_layer, passes, is_wire); + } } - } - break; - } - case OB_FONT: { - if (hide_object_extra) { break; } - Curve *cu = (Curve *)ob->data; - bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f; - if (!has_surface) { - struct GPUBatch *geom = DRW_cache_text_edge_wire_get(ob); - if (geom) { - if (theme_id == TH_UNDEFINED) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + case OB_FONT: { + if (hide_object_extra) { + break; + } + Curve *cu = (Curve *)ob->data; + bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || + cu->ext2 != 0.0f; + if (!has_surface) { + geom = DRW_cache_text_edge_wire_get(ob); + if (geom) { + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); + DRW_shgroup_call_object(shgroup, geom, ob); } - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag); - DRW_shgroup_call_object_add(shgroup, geom, ob); } + break; } - break; + default: + break; + } + + if (init_duplidata) { + dupli_data->extra_shgrp = shgroup; + dupli_data->extra_geom = geom; } - default: - break; } if (ob->pd && ob->pd->forcefield) { @@ -3386,7 +3434,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) float *color, axes_size = 1.0f; DRW_object_wire_theme_get(ob, view_layer, &color); - DRW_shgroup_call_dynamic_add(sgl->empty_axes, color, &axes_size, ob->obmat); + DRW_buffer_add_entry(sgl->empty_axes, color, &axes_size, ob->obmat); } if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c index ed96b2a05bc..8e50d08be23 100644 --- a/source/blender/draw/modes/overlay_mode.c +++ b/source/blender/draw/modes/overlay_mode.c @@ -46,6 +46,11 @@ /* Structures */ +typedef struct OVERLAY_DupliData { + DRWShadingGroup *shgrp; + struct GPUBatch *geom; +} OVERLAY_DupliData; + typedef struct OVERLAY_StorageList { struct OVERLAY_PrivateData *g_data; } OVERLAY_StorageList; @@ -95,6 +100,8 @@ extern char datatoc_overlay_face_wireframe_geom_glsl[]; extern char datatoc_overlay_face_wireframe_frag_glsl[]; extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + /* Functions */ static void overlay_engine_init(void *vedata) { @@ -104,10 +111,6 @@ static void overlay_engine_init(void *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } - if (!stl->g_data) { /* Alloc transient pointers */ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); @@ -119,8 +122,10 @@ static void overlay_engine_init(void *vedata) if (!sh_data->face_orientation) { /* Face orientation */ sh_data->face_orientation = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_orientation_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_overlay_face_orientation_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_overlay_face_orientation_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -128,7 +133,10 @@ static void overlay_engine_init(void *vedata) if (!sh_data->face_wireframe) { sh_data->select_wireframe = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_overlay_face_wireframe_vert_glsl, + NULL}, .geom = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_geom_glsl, NULL}, .frag = (const char *[]){datatoc_gpu_shader_depth_only_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define SELECT_EDGES\n", NULL}, @@ -136,14 +144,20 @@ static void overlay_engine_init(void *vedata) #if USE_GEOM_SHADER_WORKAROUND /* Apple drivers does not support wide wires. Use geometry shader as a workaround. */ sh_data->face_wireframe = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_overlay_face_wireframe_vert_glsl, + NULL}, .geom = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_geom_glsl, NULL}, .frag = (const char *[]){datatoc_overlay_face_wireframe_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, "#define USE_GEOM\n", NULL}, }); #else sh_data->face_wireframe = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_overlay_face_wireframe_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_overlay_face_wireframe_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_overlay_face_wireframe_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); @@ -205,7 +219,7 @@ static void overlay_cache_init(void *vedata) float winmat[4][4]; float viewdist = rv3d->dist; - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); + DRW_view_winmat_get(NULL, winmat, false); /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ if (rv3d->persp == RV3D_CAMOB && rv3d->is_persp == false) { viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); @@ -337,12 +351,27 @@ static void overlay_cache_populate(void *vedata, Object *ob) if (DRW_object_is_renderable(ob) && pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) { struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { - DRW_shgroup_call_add(pd->face_orientation_shgrp, geom, ob->obmat); + DRW_shgroup_call_object(pd->face_orientation_shgrp, geom, ob); } } if ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) || (v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) { + + /* Fast path for duplis. */ + OVERLAY_DupliData **dupli_data = (OVERLAY_DupliData **)DRW_duplidata_get(vedata); + if (dupli_data) { + if (*dupli_data == NULL) { + *dupli_data = MEM_callocN(sizeof(OVERLAY_DupliData), "OVERLAY_DupliData"); + } + else { + if ((*dupli_data)->shgrp && (*dupli_data)->geom) { + DRW_shgroup_call_object((*dupli_data)->shgrp, (*dupli_data)->geom, ob); + } + return; + } + } + const bool is_edit_mode = BKE_object_is_in_editmode(ob); bool has_edit_mesh_cage = false; if (ob->type == OB_MESH) { @@ -359,7 +388,7 @@ static void overlay_cache_populate(void *vedata, Object *ob) if ((!pd->show_overlays) || (((ob != draw_ctx->object_edit) && !is_edit_mode) || has_edit_mesh_cage) || ob->type != OB_MESH) { - const bool is_sculpt_mode = (ob->sculpt != NULL); + const bool is_sculpt_mode = DRW_object_use_pbvh_drawing(ob); const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES); const bool is_wire = (ob->dt < OB_SOLID); const bool use_coloring = (pd->show_overlays && !is_edit_mode && !is_sculpt_mode && @@ -389,12 +418,18 @@ static void overlay_cache_populate(void *vedata, Object *ob) } if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_wires_add(shgrp, ob, ob->obmat); + DRW_shgroup_call_sculpt(shgrp, ob, true, false, false); } else { - DRW_shgroup_call_add(shgrp, geom, ob->obmat); + DRW_shgroup_call_object(shgrp, geom, ob); } } + + if (dupli_data) { + (*dupli_data)->shgrp = shgrp; + (*dupli_data)->geom = geom; + } + if (is_wire && shgrp != NULL) { /* If object is wireframe, don't try to use stencil test. */ DRW_shgroup_state_disable(shgrp, DRW_STATE_STENCIL_EQUAL); diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index 3e292f4e4bc..ee8ec78e91b 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -27,6 +27,8 @@ #include "BKE_node.h" +#include "BLI_string_utils.h" + /* If builtin shaders are needed */ #include "GPU_shader.h" #include "GPU_texture.h" @@ -39,6 +41,7 @@ #include "DEG_depsgraph_query.h" extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_paint_texture_vert_glsl[]; extern char datatoc_paint_texture_frag_glsl[]; extern char datatoc_paint_wire_vert_glsl[]; @@ -60,8 +63,8 @@ typedef struct PAINT_TEXTURE_PassList { * Only contains (DRWPass *) */ struct DRWPass *image_faces; - struct DRWPass *wire_overlay; - struct DRWPass *face_overlay; + struct DRWPass *wire_select_overlay; + struct DRWPass *face_select_overlay; } PAINT_TEXTURE_PassList; typedef struct PAINT_TEXTURE_FramebufferList { @@ -97,20 +100,24 @@ typedef struct PAINT_TEXTURE_Data { PAINT_TEXTURE_StorageList *stl; } PAINT_TEXTURE_Data; -/* *********** STATIC *********** */ - -static struct { +typedef struct PAINT_TEXTURE_Shaders { /* Custom shaders : * Add sources to source/blender/draw/modes/shaders * init in PAINT_TEXTURE_engine_init(); * free in PAINT_TEXTURE_engine_free(); */ - struct GPUShader *fallback_sh; - struct GPUShader *image_sh; - struct GPUShader *image_masking_sh; + struct GPUShader *fallback; + struct GPUShader *image; + struct GPUShader *image_mask; + + struct GPUShader *wire_select_overlay; + struct GPUShader *face_select_overlay; +} PAINT_TEXTURE_Shaders; - struct GPUShader *wire_overlay_shader; - struct GPUShader *face_overlay_shader; -} e_data = {NULL}; /* Engine data */ +/* *********** STATIC *********** */ + +static struct { + PAINT_TEXTURE_Shaders sh_data[GPU_SHADER_CFG_LEN]; +} e_data = {{{NULL}}}; /* Engine data */ typedef struct PAINT_TEXTURE_PrivateData { /* This keeps the references of the shading groups for @@ -119,8 +126,8 @@ typedef struct PAINT_TEXTURE_PrivateData { DRWShadingGroup **shgroup_image_array; /* face-mask */ - DRWShadingGroup *lwire_shgrp; - DRWShadingGroup *face_shgrp; + DRWShadingGroup *lwire_select_shgrp; + DRWShadingGroup *face_select_shgrp; } PAINT_TEXTURE_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -129,29 +136,54 @@ typedef struct PAINT_TEXTURE_PrivateData { * It is called for every frames. */ static void PAINT_TEXTURE_engine_init(void *UNUSED(vedata)) { - if (!e_data.fallback_sh) { - e_data.fallback_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - - e_data.image_sh = DRW_shader_create_with_lib(datatoc_paint_texture_vert_glsl, - NULL, - datatoc_paint_texture_frag_glsl, - datatoc_common_globals_lib_glsl, - NULL); - - e_data.image_masking_sh = DRW_shader_create_with_lib(datatoc_paint_texture_vert_glsl, - NULL, - datatoc_paint_texture_frag_glsl, - datatoc_common_globals_lib_glsl, - "#define TEXTURE_PAINT_MASK\n"); - - e_data.wire_overlay_shader = DRW_shader_create_with_lib(datatoc_paint_wire_vert_glsl, - NULL, - datatoc_paint_wire_frag_glsl, - datatoc_common_globals_lib_glsl, - "#define VERTEX_MODE\n"); - - e_data.face_overlay_shader = DRW_shader_create( - datatoc_paint_face_vert_glsl, NULL, datatoc_gpu_shader_uniform_color_frag_glsl, NULL); + const DRWContextState *draw_ctx = DRW_context_state_get(); + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + + if (!sh_data->fallback) { + const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + sh_data->fallback = GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_UNIFORM_COLOR, + draw_ctx->sh_cfg); + + sh_data->image = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_paint_texture_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_paint_texture_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg_data->def, NULL}, + }); + + sh_data->image_mask = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_paint_texture_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_paint_texture_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg_data->def, "#define TEXTURE_PAINT_MASK\n", NULL}, + }); + + sh_data->wire_select_overlay = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_paint_wire_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg_data->def, "#define USE_SELECT\n", NULL}, + }); + + sh_data->face_select_overlay = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_paint_face_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + NULL}, + .defs = (const char *[]){sh_cfg_data->def, NULL}, + }); } } @@ -160,13 +192,14 @@ static DRWShadingGroup *create_texture_paint_shading_group(PAINT_TEXTURE_PassLis const DRWContextState *draw_ctx, const bool nearest_interp) { + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; Scene *scene = draw_ctx->scene; const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; const bool masking_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL && imapaint->stencil != NULL; - DRWShadingGroup *grp = DRW_shgroup_create( - masking_enabled ? e_data.image_masking_sh : e_data.image_sh, psl->image_faces); + DRWShadingGroup *grp = DRW_shgroup_create(masking_enabled ? sh_data->image_mask : sh_data->image, + psl->image_faces); DRW_shgroup_uniform_texture(grp, "image", texture); DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); @@ -174,7 +207,7 @@ static DRWShadingGroup *create_texture_paint_shading_group(PAINT_TEXTURE_PassLis if (masking_enabled) { const bool masking_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) > 0; - GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D, false); + GPUTexture *stencil = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D); DRW_shgroup_uniform_texture(grp, "maskingImage", stencil); DRW_shgroup_uniform_vec3(grp, "maskingColor", imapaint->stencil_col, 1); DRW_shgroup_uniform_bool_copy(grp, "maskingInvertStencil", masking_inverted); @@ -195,87 +228,102 @@ static void PAINT_TEXTURE_cache_init(void *vedata) stl->g_data->shgroup_image_array = NULL; } - { - /* Create a pass */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND; - psl->image_faces = DRW_pass_create("Image Color Pass", state); + const DRWContextState *draw_ctx = DRW_context_state_get(); + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - stl->g_data->shgroup_fallback = DRW_shgroup_create(e_data.fallback_sh, psl->image_faces); + /* Create a pass */ + { + DRWPass *pass = DRW_pass_create( + "Image Color Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND); + DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->fallback, pass); /* Uniforms need a pointer to it's value so be sure it's accessible at * any given time (i.e. use static vars) */ static float color[4] = {1.0f, 0.0f, 1.0f, 1.0}; - DRW_shgroup_uniform_vec4(stl->g_data->shgroup_fallback, "color", color, 1); - - MEM_SAFE_FREE(stl->g_data->shgroup_image_array); - - const DRWContextState *draw_ctx = DRW_context_state_get(); - Object *ob = draw_ctx->obact; - if (ob && ob->type == OB_MESH) { - Scene *scene = draw_ctx->scene; - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - const bool use_material_slots = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); - const Mesh *me = ob->data; - const int mat_nr = max_ii(1, me->totcol); - - stl->g_data->shgroup_image_array = MEM_mallocN( - sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? mat_nr : 1), __func__); - - if (use_material_slots) { - for (int i = 0; i < mat_nr; i++) { - Material *ma = give_current_material(ob, i + 1); - Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : - NULL; - int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp : - 0; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false); - - if (tex) { - DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, tex, draw_ctx, interp == SHD_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[i] = grp; - } - else { - stl->g_data->shgroup_image_array[i] = NULL; - } - } - } - else { - Image *ima = imapaint->canvas; - GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false); + DRW_shgroup_uniform_vec4(shgrp, "color", color, 1); + + if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { + DRW_shgroup_world_clip_planes_from_rv3d(shgrp, draw_ctx->rv3d); + } + psl->image_faces = pass; + stl->g_data->shgroup_fallback = shgrp; + } + + MEM_SAFE_FREE(stl->g_data->shgroup_image_array); + + Object *ob = draw_ctx->obact; + if (ob && ob->type == OB_MESH) { + Scene *scene = draw_ctx->scene; + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + const bool use_material_slots = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); + const Mesh *me = ob->data; + const int mat_nr = max_ii(1, me->totcol); + + stl->g_data->shgroup_image_array = MEM_mallocN( + sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? mat_nr : 1), __func__); + + if (use_material_slots) { + for (int i = 0; i < mat_nr; i++) { + Material *ma = give_current_material(ob, i + 1); + Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + int interp = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].interp : 0; + GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); if (tex) { DRWShadingGroup *grp = create_texture_paint_shading_group( - psl, tex, draw_ctx, imapaint->interp == IMAGEPAINT_INTERP_CLOSEST); - stl->g_data->shgroup_image_array[0] = grp; + psl, tex, draw_ctx, interp == SHD_INTERP_CLOSEST); + stl->g_data->shgroup_image_array[i] = grp; } else { - stl->g_data->shgroup_image_array[0] = NULL; + stl->g_data->shgroup_image_array[i] = NULL; } } } + else { + Image *ima = imapaint->canvas; + GPUTexture *tex = GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D); + + if (tex) { + DRWShadingGroup *grp = create_texture_paint_shading_group( + psl, tex, draw_ctx, imapaint->interp == IMAGEPAINT_INTERP_CLOSEST); + stl->g_data->shgroup_image_array[0] = grp; + } + else { + stl->g_data->shgroup_image_array[0] = NULL; + } + } } /* Face Mask */ { - psl->wire_overlay = DRW_pass_create("Wire Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_OFFSET_NEGATIVE); + DRWPass *pass = DRW_pass_create("Wire Mask Pass", + (DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_OFFSET_NEGATIVE)); + DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->wire_select_overlay, pass); + + DRW_shgroup_uniform_block(shgrp, "globalsBlock", G_draw.block_ubo); - stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay); - DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", G_draw.block_ubo); + if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { + DRW_shgroup_world_clip_planes_from_rv3d(shgrp, draw_ctx->rv3d); + } + psl->wire_select_overlay = pass; + stl->g_data->lwire_select_shgrp = shgrp; } { - psl->face_overlay = DRW_pass_create("Face Mask Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND); - - stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay); + DRWPass *pass = DRW_pass_create("Face Mask Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND); + DRWShadingGroup *shgrp = DRW_shgroup_create(sh_data->face_select_overlay, pass); static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f}; - DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1); + DRW_shgroup_uniform_vec4(shgrp, "color", col, 1); + + if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { + DRW_shgroup_world_clip_planes_from_rv3d(shgrp, draw_ctx->rv3d); + } + psl->face_select_overlay = pass; + stl->g_data->face_select_shgrp = shgrp; } } @@ -308,24 +356,23 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) for (int i = 0; i < mat_nr; i++) { const int index = use_material_slots ? i : 0; if ((i < me->totcol) && stl->g_data->shgroup_image_array[index]) { - DRW_shgroup_call_add( - stl->g_data->shgroup_image_array[index], geom_array[i], ob->obmat); + DRW_shgroup_call(stl->g_data->shgroup_image_array[index], geom_array[i], ob->obmat); } else { - DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat); + DRW_shgroup_call(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat); } } } else { if (stl->g_data->shgroup_image_array[0]) { struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - DRW_shgroup_call_add(stl->g_data->shgroup_image_array[0], geom, ob->obmat); + DRW_shgroup_call(stl->g_data->shgroup_image_array[0], geom, ob->obmat); } } } else { struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->shgroup_fallback, geom, ob->obmat); } } @@ -333,10 +380,10 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob) if (use_face_sel) { struct GPUBatch *geom; geom = DRW_cache_mesh_surface_edges_get(ob); - DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->lwire_select_shgrp, geom, ob->obmat); geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->face_select_shgrp, geom, ob->obmat); } } } @@ -367,8 +414,8 @@ static void PAINT_TEXTURE_draw_scene(void *vedata) DRW_draw_pass(psl->image_faces); - DRW_draw_pass(psl->face_overlay); - DRW_draw_pass(psl->wire_overlay); + DRW_draw_pass(psl->face_select_overlay); + DRW_draw_pass(psl->wire_select_overlay); } /* Cleanup when destroying the engine. @@ -376,10 +423,15 @@ static void PAINT_TEXTURE_draw_scene(void *vedata) * Mostly used for freeing shaders */ static void PAINT_TEXTURE_engine_free(void) { - DRW_SHADER_FREE_SAFE(e_data.image_sh); - DRW_SHADER_FREE_SAFE(e_data.image_masking_sh); - DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader); - DRW_SHADER_FREE_SAFE(e_data.face_overlay_shader); + for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { + PAINT_TEXTURE_Shaders *sh_data = &e_data.sh_data[sh_data_index]; + /* Don't free builtins. */ + sh_data->fallback = NULL; + GPUShader **sh_data_as_array = (GPUShader **)sh_data; + for (int i = 0; i < (sizeof(PAINT_TEXTURE_Shaders) / sizeof(GPUShader *)); i++) { + DRW_SHADER_FREE_SAFE(sh_data_as_array[i]); + } + } } static const DrawEngineDataSize PAINT_TEXTURE_data_size = DRW_VIEWPORT_DATA_SIZE( diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c index ef3af1255eb..815cf09487e 100644 --- a/source/blender/draw/modes/paint_vertex_mode.c +++ b/source/blender/draw/modes/paint_vertex_mode.c @@ -42,6 +42,7 @@ extern char datatoc_paint_wire_vert_glsl[]; extern char datatoc_paint_wire_frag_glsl[]; extern char datatoc_paint_vert_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; @@ -108,19 +109,20 @@ static void PAINT_VERTEX_engine_init(void *UNUSED(vedata)) const DRWContextState *draw_ctx = DRW_context_state_get(); PAINT_VERTEX_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_state_clip_planes_set_from_rv3d(draw_ctx->rv3d); - } const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; if (!sh_data->face_select_overlay) { sh_data->by_mode[VERTEX_MODE].color_face = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_paint_vertex_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_paint_vertex_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_paint_vertex_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); sh_data->by_mode[WEIGHT_MODE].color_face = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, datatoc_common_globals_lib_glsl, datatoc_paint_weight_vert_glsl, NULL}, @@ -131,13 +133,17 @@ static void PAINT_VERTEX_engine_init(void *UNUSED(vedata)) }); sh_data->face_select_overlay = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, datatoc_paint_face_vert_glsl, NULL}, + .vert = (const char *[]){sh_cfg_data->lib, + datatoc_common_view_lib_glsl, + datatoc_paint_face_vert_glsl, + NULL}, .frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg_data->def, NULL}, }); sh_data->vert_select_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_paint_wire_vert_glsl, NULL}, .frag = (const char *[]){datatoc_paint_vert_frag_glsl, NULL}, @@ -152,6 +158,7 @@ static void PAINT_VERTEX_engine_init(void *UNUSED(vedata)) sh_data->by_mode[i].wire_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_paint_wire_vert_glsl, NULL}, .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL}, @@ -160,6 +167,7 @@ static void PAINT_VERTEX_engine_init(void *UNUSED(vedata)) sh_data->by_mode[i].wire_select_overlay = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg_data->lib, datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_paint_wire_vert_glsl, NULL}, .frag = (const char *[]){datatoc_paint_wire_frag_glsl, NULL}, @@ -301,24 +309,24 @@ static void PAINT_VERTEX_cache_populate(void *vedata, Object *ob) } } if (geom != NULL) { - DRW_shgroup_call_add(stl->g_data->by_mode[draw_mode].color_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->by_mode[draw_mode].color_shgrp, geom, ob->obmat); } if (use_face_sel || use_wire) { DRWShadingGroup *shgrp = use_face_sel ? stl->g_data->by_mode[draw_mode].lwire_select_shgrp : stl->g_data->by_mode[draw_mode].lwire_shgrp; geom = DRW_cache_mesh_surface_edges_get(ob); - DRW_shgroup_call_add(shgrp, geom, ob->obmat); + DRW_shgroup_call(shgrp, geom, ob->obmat); } if (use_face_sel) { geom = DRW_cache_mesh_surface_get(ob); - DRW_shgroup_call_add(stl->g_data->face_select_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->face_select_shgrp, geom, ob->obmat); } if (use_vert_sel) { geom = DRW_cache_mesh_all_verts_get(ob); - DRW_shgroup_call_add(stl->g_data->vert_select_shgrp, geom, ob->obmat); + DRW_shgroup_call(stl->g_data->vert_select_shgrp, geom, ob->obmat); } } } diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index 600a29fecb4..ee35fa6d169 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -27,6 +27,8 @@ #include "BKE_pointcache.h" +#include "BLI_string_utils.h" + #include "GPU_shader.h" #include "draw_common.h" @@ -39,6 +41,7 @@ extern char datatoc_particle_strand_vert_glsl[]; extern char datatoc_particle_strand_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; /* *********** LISTS *********** */ @@ -86,23 +89,23 @@ typedef struct PARTICLE_PrivateData { static void particle_engine_init(void *UNUSED(vedata)) { if (!e_data.strands_shader) { - e_data.strands_shader = DRW_shader_create_with_lib(datatoc_particle_strand_vert_glsl, - NULL, - datatoc_particle_strand_frag_glsl, - datatoc_common_globals_lib_glsl, - ""); + char *lib = BLI_string_joinN(datatoc_common_globals_lib_glsl, datatoc_common_view_lib_glsl); + + e_data.strands_shader = DRW_shader_create_with_lib( + datatoc_particle_strand_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, lib, ""); e_data.strands_weight_shader = DRW_shader_create_with_lib(datatoc_particle_strand_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, - datatoc_common_globals_lib_glsl, + lib, "#define USE_WEIGHT"); e_data.points_shader = DRW_shader_create_with_lib(datatoc_particle_strand_vert_glsl, NULL, datatoc_particle_strand_frag_glsl, - datatoc_common_globals_lib_glsl, + lib, "#define USE_POINTS"); + MEM_freeN(lib); } } @@ -120,10 +123,9 @@ static void particle_cache_init(void *vedata) } /* Create a pass */ - psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass", - (DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE | - DRW_STATE_POINT)); + psl->psys_edit_pass = DRW_pass_create( + "PSys Edit Pass", + (DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL)); GPUShader *strand_shader = (use_weight) ? e_data.strands_weight_shader : e_data.strands_shader; stl->g_data->strands_group = DRW_shgroup_create(strand_shader, psl->psys_edit_pass); @@ -147,15 +149,15 @@ static void particle_edit_cache_populate(void *vedata, { struct GPUBatch *strands = DRW_cache_particles_get_edit_strands( object, psys, edit, use_weight); - DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL); + DRW_shgroup_call(stl->g_data->strands_group, strands, NULL); } if (pset->selectmode == SCE_SELECT_POINT) { struct GPUBatch *points = DRW_cache_particles_get_edit_inner_points(object, psys, edit); - DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL); + DRW_shgroup_call(stl->g_data->inner_points_group, points, NULL); } if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) { struct GPUBatch *points = DRW_cache_particles_get_edit_tip_points(object, psys, edit); - DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL); + DRW_shgroup_call(stl->g_data->tip_points_group, points, NULL); } } diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index a37901a1fa9..08b6a99c453 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -138,7 +138,7 @@ static void POSE_cache_init(void *vedata) psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state); state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - DRW_STATE_BLEND | DRW_STATE_WIRE; + DRW_STATE_BLEND; psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state); ppd->custom_shapes[i] = BLI_ghash_ptr_new(__func__); @@ -226,10 +226,10 @@ static void POSE_cache_populate(void *vedata, Object *ob) struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { if (POSE_is_driven_by_active_armature(ob)) { - DRW_shgroup_call_object_add(ppd->bone_selection_shgrp, geom, ob); + DRW_shgroup_call_object(ppd->bone_selection_shgrp, geom, ob); } else { - DRW_shgroup_call_object_add(ppd->bone_selection_invert_shgrp, geom, ob); + DRW_shgroup_call_object(ppd->bone_selection_invert_shgrp, geom, ob); } } } diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index 8adae0a4238..363476445c1 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -37,6 +37,7 @@ #include "draw_common.h" #include "draw_mode_engines.h" +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_sculpt_mask_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; @@ -90,18 +91,11 @@ typedef struct SCULPT_Data { /* *********** STATIC *********** */ static struct { - /* Custom shaders : - * Add sources to source/blender/draw/modes/shaders - * init in SCULPT_engine_init(); - * free in SCULPT_engine_free(); */ - struct GPUShader *shader_smooth; + struct GPUShader *shader_mask; } e_data = {NULL}; /* Engine data */ typedef struct SCULPT_PrivateData { - /* This keeps the references of the shading groups for - * easy access in SCULPT_cache_populate() */ - DRWShadingGroup *group_flat; - DRWShadingGroup *group_smooth; + DRWShadingGroup *mask_overlay_grp; } SCULPT_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -117,9 +111,12 @@ static void SCULPT_engine_init(void *vedata) UNUSED_VARS(txl, fbl, stl); - if (!e_data.shader_smooth) { - e_data.shader_smooth = DRW_shader_create( - datatoc_sculpt_mask_vert_glsl, NULL, datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL); + if (!e_data.shader_mask) { + e_data.shader_mask = DRW_shader_create_with_lib(datatoc_sculpt_mask_vert_glsl, + NULL, + datatoc_gpu_shader_3D_smooth_color_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); } } @@ -141,47 +138,9 @@ static void SCULPT_cache_init(void *vedata) DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_MULTIPLY; psl->pass = DRW_pass_create("Sculpt Pass", state); - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.shader_smooth, psl->pass); + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.shader_mask, psl->pass); DRW_shgroup_uniform_float(shgrp, "maskOpacity", &v3d->overlay.sculpt_mode_mask_opacity, 1); - stl->g_data->group_smooth = shgrp; - } -} - -static void sculpt_draw_mask_cb(DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, struct GPUBatch *geom), - void *user_data) -{ - Object *ob = user_data; - PBVH *pbvh = ob->sculpt->pbvh; - - if (pbvh) { - BKE_pbvh_draw_cb(pbvh, - NULL, - NULL, - false, - false, - true, - false, - (void (*)(void *, struct GPUBatch *))draw_fn, - shgroup); - } -} - -static void sculpt_update_pbvh_normals(Object *object) -{ - Mesh *mesh = object->data; - PBVH *pbvh = object->sculpt->pbvh; - SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; - if (pbvh == NULL || subdiv_ccg == NULL) { - return; - } - BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg); - struct CCGFace **faces; - int num_faces; - BKE_pbvh_get_grid_updates(pbvh, 1, (void ***)&faces, &num_faces); - if (num_faces > 0) { - BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces); - MEM_freeN(faces); + stl->g_data->mask_overlay_grp = shgrp; } } @@ -197,73 +156,24 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) const DRWContextState *draw_ctx = DRW_context_state_get(); if (ob->sculpt && (ob == draw_ctx->obact)) { - sculpt_update_pbvh_normals(ob); - - /* XXX, needed for dyntopo-undo (which clears). - * probably depsgraph should handlle? in 2.7x - * getting derived-mesh does this (mesh_build_data). */ - if (ob->sculpt->pbvh == NULL) { - /* create PBVH immediately (would be created on the fly too, - * but this avoids waiting on first stroke) */ - Scene *scene = draw_ctx->scene; - - BKE_sculpt_update_mesh_elements( - draw_ctx->depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); - } - PBVH *pbvh = ob->sculpt->pbvh; if (pbvh && pbvh_has_mask(pbvh)) { - DRW_shgroup_call_generate_add( - stl->g_data->group_smooth, sculpt_draw_mask_cb, ob, ob->obmat); + DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false); } } } } -/* Optional: Post-cache_populate callback */ -static void SCULPT_cache_finish(void *vedata) -{ - SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl; - SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl; - - /* Do something here! dependent on the objects gathered */ - UNUSED_VARS(psl, stl); -} - -/* Draw time ! Control rendering pipeline from here */ static void SCULPT_draw_scene(void *vedata) { SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl; - SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl; - - /* Default framebuffer and texture */ - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - UNUSED_VARS(fbl, dfbl, dtxl); - /* Show / hide entire passes, swap framebuffers ... whatever you fancy */ - /* - * DRW_framebuffer_texture_detach(dtxl->depth); - * DRW_framebuffer_bind(fbl->custom_fb); - * DRW_draw_pass(psl->pass); - * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); - * DRW_framebuffer_bind(dfbl->default_fb); - */ - - /* ... or just render passes on default framebuffer. */ DRW_draw_pass(psl->pass); - - /* If you changed framebuffer, double check you rebind - * the default one with its textures attached before finishing */ } -/* Cleanup when destroying the engine. - * This is not per viewport ! only when quitting blender. - * Mostly used for freeing shaders */ static void SCULPT_engine_free(void) { - DRW_SHADER_FREE_SAFE(e_data.shader_smooth); + DRW_SHADER_FREE_SAFE(e_data.shader_mask); } static const DrawEngineDataSize SCULPT_data_size = DRW_VIEWPORT_DATA_SIZE(SCULPT_Data); @@ -277,7 +187,7 @@ DrawEngineType draw_engine_sculpt_type = { &SCULPT_engine_free, &SCULPT_cache_init, &SCULPT_cache_populate, - &SCULPT_cache_finish, + NULL, NULL, /* draw_background but not needed by mode engines */ &SCULPT_draw_scene, NULL, diff --git a/source/blender/draw/modes/shaders/armature_axes_vert.glsl b/source/blender/draw/modes/shaders/armature_axes_vert.glsl index a689dce4d70..d7ed3e9ab71 100644 --- a/source/blender/draw/modes/shaders/armature_axes_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_axes_vert.glsl @@ -1,9 +1,7 @@ uniform mat4 ViewProjectionMatrix; uniform vec3 screenVecs[3]; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif + /* ---- Instantiated Attrs ---- */ in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */ in vec2 screenPos; @@ -32,6 +30,6 @@ void main() finalColor.a = 1.0; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(pos_4d.xyz); #endif } diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl index 1e7fc4d11b8..c0bde90bf28 100644 --- a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl @@ -3,9 +3,6 @@ uniform mat4 ViewMatrix; uniform mat4 ViewMatrixInverse; uniform mat4 ViewProjectionMatrix; uniform mat4 ProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif uniform vec2 viewportSize; uniform float lineThickness = 2.0; @@ -145,7 +142,7 @@ void main() vec4 pos_4d = vec4(wpos1, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(pos_4d.xyz); #endif vec4 V = ViewMatrix * pos_4d; diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl index 7f8ccc0c95a..d9567bb84f4 100644 --- a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl @@ -2,9 +2,6 @@ uniform mat4 ViewMatrix; uniform mat4 ViewMatrixInverse; uniform mat4 ViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif /* ---- Instantiated Attrs ---- */ in vec3 pos; @@ -57,6 +54,6 @@ void main() vec4 pos_4d = vec4(sp, 1.0); gl_Position = ViewProjectionMatrix * pos_4d; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(pos_4d.xyz); #endif } diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl index 54315863a2e..dc84b8924d1 100644 --- a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl @@ -9,7 +9,6 @@ in vec2 ssNor[]; in vec4 vColSize[]; flat out vec4 finalColor; -uniform mat4 ProjectionMatrix; uniform vec2 viewportSize; uniform float lineThickness = 2.0; diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl index 82a483d91a5..fb2735c196c 100644 --- a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl @@ -1,8 +1,4 @@ -uniform mat3 NormalMatrix; - -uniform mat4 ViewMatrix; -uniform mat4 ProjectionMatrix; uniform vec2 viewportSize; /* ---- Instantiated Attrs ---- */ @@ -27,20 +23,19 @@ vec2 proj(vec4 pos) void main() { - /* This is slow and run per vertex, but it's still faster than - * doing it per instance on CPU and sending it on via instance attribute. */ - mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); - vec4 worldPosition = InstanceModelMatrix * vec4(pos, 1.0); vec4 viewpos = ViewMatrix * worldPosition; vPos = viewpos.xyz; pPos = ProjectionMatrix * viewpos; + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attribute. */ + mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix))); /* TODO FIX: there is still a problem with this vector * when the bone is scaled or in persp mode. But it's * barelly visible at the outline corners. */ - ssNor = normalize((NormalMatrix * snor).xy); + ssNor = normalize(normal_world_to_view(normal_mat * snor).xy); ssPos = proj(pPos); diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl index 2df25bf0e03..df6a9ce2d76 100644 --- a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl @@ -1,11 +1,4 @@ -uniform mat3 NormalMatrix; -uniform mat4 ViewMatrixInverse; -uniform mat4 ViewProjectionMatrix; - -uniform mat4 ViewMatrix; -uniform mat4 ProjectionMatrix; - /* ---- Instantiated Attrs ---- */ in vec3 pos; in vec3 nor; @@ -19,8 +12,10 @@ out vec4 finalColor; void main() { - mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); - vec3 normal = normalize(NormalMatrix * nor); + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attribute. */ + mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix))); + vec3 normal = normalize(normal_world_to_view(normal_mat * nor)); /* Do lighting at an angle to avoid flat shading on front facing bone. */ const vec3 light = vec3(0.1, 0.1, 0.8); diff --git a/source/blender/draw/modes/shaders/armature_stick_vert.glsl b/source/blender/draw/modes/shaders/armature_stick_vert.glsl index 9e5a3d76c0d..fd8a12fcd2c 100644 --- a/source/blender/draw/modes/shaders/armature_stick_vert.glsl +++ b/source/blender/draw/modes/shaders/armature_stick_vert.glsl @@ -1,7 +1,7 @@ uniform mat4 ProjectionMatrix; uniform mat4 ViewProjectionMatrix; -uniform mat4 ModelMatrix; + uniform mat4 ViewMatrix; uniform vec2 viewportSize; @@ -88,8 +88,7 @@ void main() gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */ #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance( - (ModelMatrix * (is_head ? boneStart_4d : boneEnd_4d)).xyz); + world_clip_planes_calc_clip_distance((is_head ? boneStart_4d : boneEnd_4d).xyz); #endif } else { diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl index a1e6bb0f43d..8a7fb97d98c 100644 --- a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl +++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl @@ -1,10 +1,11 @@ -in vec2 pos; -in vec2 uvs; out vec4 uvcoordsvar; void main() { - uvcoordsvar = vec4(uvs, 0.0, 0.0); - gl_Position = vec4(pos, 1.0, 1.0); + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = vec4(x, y, 1.0, 1.0); + uvcoordsvar = vec4((gl_Position.xy + 1.0) * 0.5, 0.0, 0.0); } diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl index 1c0a31c59fd..f9c3df34658 100644 --- a/source/blender/draw/modes/shaders/common_hair_lib.glsl +++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl @@ -160,9 +160,9 @@ void hair_get_pos_tan_binor_time(bool is_persp, } wpos = (hairDupliMatrix * vec4(wpos, 1.0)).xyz; - wtan = mat3(hairDupliMatrix) * wtan; + wtan = -normalize(mat3(hairDupliMatrix) * wtan); - vec3 camera_vec = (is_persp) ? wpos - camera_pos : -camera_z; + vec3 camera_vec = (is_persp) ? camera_pos - wpos : camera_z; wbinor = normalize(cross(camera_vec, wtan)); thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time); diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl index de9c4e2a96e..845c615c75c 100644 --- a/source/blender/draw/modes/shaders/common_view_lib.glsl +++ b/source/blender/draw/modes/shaders/common_view_lib.glsl @@ -9,7 +9,51 @@ layout(std140) uniform viewBlock mat4 ProjectionMatrix; mat4 ProjectionMatrixInverse; - vec4 CameraTexCoFactors; + vec4 clipPlanes[6]; - vec4 clipPlanes[2]; + /* TODO move it elsewhere. */ + vec4 CameraTexCoFactors; }; + +uniform mat4 ModelMatrix; +uniform mat4 ModelMatrixInverse; + +/** Transform shortcuts. */ +/* Rule of thumb: Try to reuse world positions and normals because converting though viewspace + * will always be decomposed in at least 2 matrix operation. */ + +/** + * Some clarification: + * Usually Normal matrix is transpose(inverse(ViewMatrix * ModelMatrix)) + * + * But since it is slow to multiply matrices we decompose it. Decomposing + * inversion and transposition both invert the product order leaving us with + * the same original order: + * transpose(ViewMatrixInverse) * transpose(ModelMatrixInverse) + * + * Knowing that the view matrix is orthogonal, the transpose is also the inverse. + * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse. + * ViewMatrix * transpose(ModelMatrixInverse) + **/ +#define normal_object_to_view(n) (mat3(ViewMatrix) * (transpose(mat3(ModelMatrixInverse)) * n)) +#define normal_object_to_world(n) (transpose(mat3(ModelMatrixInverse)) * n) +#define normal_world_to_object(n) (transpose(mat3(ModelMatrix)) * n) +#define normal_world_to_view(n) (mat3(ViewMatrix) * n) + +#define point_object_to_ndc(p) (ViewProjectionMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)) +#define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz) +#define point_object_to_world(p) ((ModelMatrix * vec4(p, 1.0)).xyz) +#define point_view_to_ndc(p) (ProjectionMatrix * vec4(p, 1.0)) +#define point_view_to_object(p) ((ModelMatrixInverse * (ViewMatrixInverse * vec4(p, 1.0))).xyz) +#define point_view_to_world(p) ((ViewMatrixInverse * vec4(p, 1.0)).xyz) +#define point_world_to_ndc(p) (ViewProjectionMatrix * vec4(p, 1.0)) +#define point_world_to_object(p) ((ModelMatrixInverse * vec4(p, 1.0)).xyz) +#define point_world_to_view(p) ((ViewMatrix * vec4(p, 1.0)).xyz) + +/* 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 +# define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexID); +#else +# define GPU_INTEL_VERTEX_SHADER_WORKAROUND +#endif diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl index b7166382b19..590c2905be6 100644 --- a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl @@ -1,6 +1,4 @@ /* Draw Curve Handles */ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; in vec3 pos; in int data; @@ -9,11 +7,13 @@ flat out int vertFlag; void main() { - vec4 pos_4d = vec4(pos, 1.0); - gl_Position = ModelViewProjectionMatrix * pos_4d; + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); vertFlag = data; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl index 4718f11db65..6eec43d99be 100644 --- a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl @@ -1,6 +1,5 @@ /* Draw Curve Vertices */ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; + uniform vec2 viewportSize; in vec3 pos; @@ -10,6 +9,8 @@ out vec4 finalColor; void main() { + GPU_INTEL_VERTEX_SHADER_WORKAROUND + if ((data & VERT_SELECTED) != 0) { if ((data & VERT_ACTIVE) != 0) { finalColor = colorEditMeshActive; @@ -22,10 +23,10 @@ void main() finalColor = colorVertex; } - vec4 pos_4d = vec4(pos, 1.0); - gl_Position = ModelViewProjectionMatrix * pos_4d; + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); gl_PointSize = sizeVertex * 2.0; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl index 02244086711..e1d5319ffb9 100644 --- a/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl @@ -1,6 +1,5 @@ /* Draw Curve Normals */ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; + uniform float normalSize; in vec3 pos; @@ -10,6 +9,8 @@ in float rad; void main() { + GPU_INTEL_VERTEX_SHADER_WORKAROUND + vec3 final_pos = pos; float flip = (gl_InstanceID != 0) ? -1.0 : 1.0; @@ -18,10 +19,10 @@ void main() final_pos += normalSize * rad * (flip * nor - tan); } - vec4 final_pos_4d = vec4(final_pos, 1.0); - gl_Position = ModelViewProjectionMatrix * final_pos_4d; + vec3 world_pos = point_object_to_world(final_pos); + gl_Position = point_world_to_ndc(world_pos); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * final_pos_4d).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl index 3cf808f3c52..ac6b353412d 100644 --- a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl @@ -1,8 +1,5 @@ - /* Draw Lattice Vertices */ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; uniform vec2 viewportSize; in vec3 pos; @@ -25,9 +22,12 @@ vec2 proj(vec4 pos) void main() { + GPU_INTEL_VERTEX_SHADER_WORKAROUND + clipCase = 0; - vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + vec4 pPos = point_world_to_ndc(world_pos); /* only vertex position 0 is used */ eData1 = eData2 = vec4(1e10); @@ -39,6 +39,6 @@ void main() gl_Position = pPos; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl index c84d97fa1c5..df37c6fb0bc 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl @@ -1,6 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; uniform ivec4 dataMask = ivec4(0xFF); in vec3 pos; @@ -10,13 +8,16 @@ flat out vec4 faceColor; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); ivec4 data_m = data & dataMask; faceColor = EDIT_MESH_face_color(data_m.x); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl index 94d8d2e701c..7065ce3df7c 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl @@ -1,5 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; in vec3 pos; in vec4 weight_color; @@ -14,10 +12,13 @@ out vec4 weightColor; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); weightColor = vec4(weight_color.rgb, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl index d700e69fb57..fabc317cf4f 100644 --- a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl @@ -1,9 +1,4 @@ -uniform mat3 NormalMatrix; -uniform mat4 ProjectionMatrix; -uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; uniform float faceAlphaMod; uniform ivec4 dataMask = ivec4(0xFF); uniform float ofs; @@ -25,14 +20,19 @@ out int selectOveride; void main() { + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + #if !defined(FACE) + /* TODO override the ViewProjection Matrix for this case. */ mat4 projmat = ProjectionMatrix; projmat[3][2] -= ofs; - gl_Position = projmat * (ModelViewMatrix * vec4(pos, 1.0)); + gl_Position = projmat * (ViewMatrix * vec4(world_pos, 1.0)); #else - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_Position = point_world_to_ndc(world_pos); #endif ivec4 m_data = data & dataMask; @@ -76,17 +76,16 @@ void main() #if !defined(FACE) /* Facing based color blend */ - vec4 vpos = ModelViewMatrix * vec4(pos, 1.0); - vec3 view_normal = normalize(NormalMatrix * vnor + 1e-4); - vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) ? normalize(vpos.xyz) : vec3(0.0, 0.0, 1.0); + vec3 vpos = point_world_to_view(world_pos); + vec3 view_normal = normalize(normal_object_to_view(vnor) + 1e-4); + vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) ? normalize(vpos) : vec3(0.0, 0.0, 1.0); float facing = dot(view_vec, view_normal); facing = 1.0 - abs(facing) * 0.2; finalColor.rgb = mix(colorEditMeshMiddle.rgb, finalColor.rgb, facing); - #endif #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/edit_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_normals_vert.glsl index 2e34a132cb0..384d13923f6 100644 --- a/source/blender/draw/modes/shaders/edit_normals_vert.glsl +++ b/source/blender/draw/modes/shaders/edit_normals_vert.glsl @@ -1,8 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat3 NormalMatrix; -uniform mat4 ProjectionMatrix; -uniform mat4 ModelMatrix; uniform float normalSize; in vec3 pos; @@ -25,10 +21,16 @@ flat out vec4 v2; void main() { - v1 = ModelViewProjectionMatrix * vec4(pos, 1.0); - vec3 n = normalize(NormalMatrix * nor); /* viewspace */ - v2 = v1 + ProjectionMatrix * vec4(n * normalSize, 0.0); + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 n = normalize(normal_object_to_world(nor)); + + vec3 world_pos = point_object_to_world(pos); + + v1 = point_world_to_ndc(world_pos); + v2 = point_world_to_ndc(world_pos + n * normalSize); + #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl index 7fd955343fc..43c8e313fc3 100644 --- a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl +++ b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl @@ -1,8 +1,5 @@ uniform mat4 ViewProjectionMatrix; -#ifdef USE_WORLD_CLIP_PLANES -uniform mat4 ModelMatrix; -#endif uniform vec3 screenVecs[3]; @@ -33,6 +30,6 @@ void main() finalColor = vec4(color, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(pos_4d.xyz); #endif } diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl index 386d05636f9..deb82a8904e 100644 --- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl +++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl @@ -14,12 +14,33 @@ uniform sampler2D image; uniform int depthMode; uniform bool useAlphaTest; +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) { + return (c < 0.0) ? 0.0 : c * 12.92; + } + else { + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; + } +} + +vec4 texture_read_as_srgb(sampler2D tex, vec2 co) +{ + /* By convention image textures return scene linear colors, but + * overlays still assume srgb. */ + vec4 color = texture(tex, co); + color.r = linearrgb_to_srgb(color.r); + color.g = linearrgb_to_srgb(color.g); + color.b = linearrgb_to_srgb(color.b); + return color; +} + void main() { #ifdef USE_WIRE fragColor = finalColor; #else - vec4 tex_col = texture(image, texCoord_interp); + vec4 tex_col = texture_read_as_srgb(image, texCoord_interp); fragColor = finalColor * tex_col; if (useAlphaTest) { diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl index 9694c63fef1..36e86290be7 100644 --- a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl +++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl @@ -1,7 +1,5 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; -uniform float aspectX; -uniform float aspectY; + +uniform vec2 aspect; uniform float size; uniform vec2 offset; #ifdef USE_WIRE @@ -21,8 +19,9 @@ out vec2 texCoord_interp; void main() { - vec4 pos_4d = vec4((pos + offset) * (size * vec2(aspectX, aspectY)), 0.0, 1.0); - gl_Position = ModelViewProjectionMatrix * pos_4d; + vec3 pos = vec3((pos + offset) * (size * aspect), 0.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); #ifdef USE_WIRE gl_Position.z -= 1e-5; finalColor = vec4(color, 1.0); @@ -32,6 +31,6 @@ void main() #endif #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl index df2cfe7be82..a20f12efd93 100644 --- a/source/blender/draw/modes/shaders/object_grid_frag.glsl +++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl @@ -8,10 +8,7 @@ in vec3 local_pos; out vec4 FragColor; -uniform mat4 ProjectionMatrix; -uniform vec3 cameraPos; uniform vec3 planeAxes; -uniform vec3 eye; uniform vec4 gridSettings; uniform float meshSize; uniform float lineKernel = 0.0; @@ -23,6 +20,8 @@ uniform sampler2D depthBuffer; #define gridScale gridSettings.z #define gridSubdiv gridSettings.w +#define cameraPos (ViewMatrixInverse[3].xyz) + uniform int gridFlag; #define AXIS_X (1 << 0) @@ -109,7 +108,7 @@ void main() dist = 1.0; /* avoid branch after */ if ((gridFlag & PLANE_XY) != 0) { - float angle = 1.0 - abs(eye.z); + float angle = 1.0 - abs(ViewMatrixInverse[2].z); dist = 1.0 + angle * 2.0; angle *= angle; fade *= 1.0 - angle * angle; diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl index e8f4b089b47..d247967b03a 100644 --- a/source/blender/draw/modes/shaders/object_grid_vert.glsl +++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl @@ -2,9 +2,6 @@ /* Infinite grid * Clément Foucault */ -uniform mat4 ViewProjectionMatrix; -uniform mat4 ProjectionMatrix; -uniform vec3 cameraPos; uniform vec3 planeAxes; uniform vec4 gridSettings; uniform float meshSize; @@ -16,6 +13,8 @@ uniform float meshSize; uniform int gridFlag; +#define cameraPos (ViewMatrixInverse[3].xyz) + #define PLANE_XY (1 << 4) #define PLANE_XZ (1 << 5) #define PLANE_YZ (1 << 6) diff --git a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl index c395ed01bca..9414309570b 100644 --- a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl +++ b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl @@ -4,7 +4,6 @@ * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */ uniform mat4 ViewProjectionMatrix; -uniform mat4 ModelMatrix; uniform vec3 screen_vecs[2]; /* ---- Instantiated Attrs ---- */ @@ -32,6 +31,6 @@ void main() finalColor = vec4(color, 1.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * world_pos).xyz); + world_clip_planes_calc_clip_distance(world_pos.xyz); #endif } diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl index 97d4bdacf07..5a3eb38fb6b 100644 --- a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl +++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl @@ -2,8 +2,6 @@ layout(lines_adjacency) in; layout(line_strip, max_vertices = 2) out; -uniform mat4 ProjectionMatrix; - in vec4 pPos[]; in vec3 vPos[]; diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl index 0b5f4733ebc..e34afe95b5e 100644 --- a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl +++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl @@ -1,8 +1,4 @@ -uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in vec3 pos; out vec4 pPos; @@ -10,12 +6,13 @@ out vec3 vPos; void main() { - vPos = (ModelViewMatrix * vec4(pos, 1.0)).xyz; - pPos = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + vPos = point_world_to_view(world_pos); + pPos = point_world_to_ndc(world_pos); /* Small bias to always be on top of the geom. */ pPos.z -= 1e-3; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl index e51b829adb5..f98ae9a9515 100644 --- a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl +++ b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl @@ -1,6 +1,4 @@ -uniform mat4 ModelViewMatrix; -uniform mat4 ProjectionMatrix; uniform float pixel_size; uniform float size; @@ -12,10 +10,13 @@ flat out float finalVal; void main() { - gl_Position = ModelViewMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); - float psize = (ProjectionMatrix[3][3] == 0.0) ? (size / (-gl_Position.z * pixel_size)) : - (size / pixel_size); + float view_z = dot(ViewMatrixInverse[2].xyz, world_pos - ViewMatrixInverse[3].xyz); + + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float psize = (is_persp) ? (size / (-view_z * pixel_size)) : (size / pixel_size); + gl_Position = point_world_to_ndc(world_pos); gl_PointSize = psize; @@ -31,7 +32,5 @@ void main() // convert to PointCoord units radii /= psize; - gl_Position = ProjectionMatrix * gl_Position; - finalVal = val; } diff --git a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl index 0f626626498..46aceb245f4 100644 --- a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl +++ b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl @@ -1,18 +1,17 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ViewProjectionMatrix; -uniform mat4 ModelViewMatrix; -uniform mat4 ProjectionMatrix; -uniform int screen_space; +uniform bool screen_space; uniform float draw_size; uniform vec3 color; uniform sampler1D ramp; +/* ---- Instantiated Attrs ---- */ +in vec3 inst_pos; +in int axis; + +/* ---- Per instance Attrs ---- */ in vec3 pos; in vec4 rot; in float val; -in vec3 inst_pos; -in int axis; flat out vec4 finalColor; @@ -24,8 +23,9 @@ vec3 rotate(vec3 vec, vec4 quat) void main() { - if (screen_space == 1) { - gl_Position = ModelViewMatrix * vec4(pos, 1.0) + vec4(inst_pos * draw_size, 0.0); + if (screen_space) { + gl_Position = ViewMatrix * (ModelMatrix * vec4(pos, 1.0)); + gl_Position.xyz += inst_pos * draw_size; gl_Position = ProjectionMatrix * gl_Position; } else { @@ -35,7 +35,8 @@ void main() size *= 2; } - gl_Position = ModelViewProjectionMatrix * vec4(pos + rotate(inst_pos * size, rot), 1.0); + vec3 pos_rot = pos + rotate(inst_pos * size, rot); + gl_Position = point_object_to_ndc(pos_rot); } #ifdef USE_AXIS diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl index 659e3cbd5f5..2dd84c0a060 100644 --- a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl @@ -1,13 +1,12 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; in vec3 pos; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl index 96acba71233..23f64e6e49c 100644 --- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl +++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl @@ -1,9 +1,4 @@ -uniform mat4 ProjectionMatrix; -uniform mat4 ModelViewMatrix; -uniform mat4 ModelMatrix; -uniform mat3 NormalMatrix; - uniform float wireStepParam; uniform float ofs; @@ -11,57 +6,41 @@ in vec3 pos; in vec3 nor; in float wd; /* wiredata */ -#ifndef USE_SCULPT float get_edge_sharpness(float wd) { +#ifndef USE_SCULPT return ((wd == 0.0) ? -1.5 : wd) + wireStepParam; -} #else -float get_edge_sharpness(float wd) -{ return 1.0; -} #endif +} /* Geometry shader version */ #if defined(SELECT_EDGES) || defined(USE_GEOM) out float facing_g; out float edgeSharpness_g; -void main() -{ - edgeSharpness_g = get_edge_sharpness(wd); - - mat4 projmat = ProjectionMatrix; - projmat[3][2] -= ofs; - - gl_Position = projmat * (ModelViewMatrix * vec4(pos, 1.0)); - - facing_g = normalize(NormalMatrix * nor).z; - -# ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); -# endif -} - #else /* USE_GEOM */ out float facing; flat out float edgeSharpness; +# define facing_g facing +# define edgeSharpness_g edgeSharpness + +#endif /* SELECT_EDGES */ void main() { - edgeSharpness = get_edge_sharpness(wd); - mat4 projmat = ProjectionMatrix; projmat[3][2] -= ofs; - gl_Position = projmat * (ModelViewMatrix * vec4(pos, 1.0)); + vec4 wpos = ModelMatrix * vec4(pos, 1.0); + gl_Position = projmat * (ViewMatrix * wpos); - facing = normalize(NormalMatrix * nor).z; + vec3 wnor = normalize(normal_object_to_world(nor)); + facing_g = dot(wnor, ViewMatrixInverse[2].xyz); + edgeSharpness_g = get_edge_sharpness(wd); -# ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); -# endif +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(wpos.xyz); +#endif } - -#endif /* SELECT_EDGES */ diff --git a/source/blender/draw/modes/shaders/paint_face_vert.glsl b/source/blender/draw/modes/shaders/paint_face_vert.glsl index 59b88d8d3a7..4b5191ead07 100644 --- a/source/blender/draw/modes/shaders/paint_face_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_face_vert.glsl @@ -1,20 +1,19 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in vec3 pos; in vec4 nor; /* select flag on the 4th component */ void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + /* Don't draw faces that are selected. */ if (nor.w > 0.0) { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); } else { #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } } diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl index c7e110122c5..4a3c5cb430c 100644 --- a/source/blender/draw/modes/shaders/paint_texture_frag.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl @@ -16,6 +16,27 @@ uniform vec3 maskingColor; uniform bool maskingInvertStencil; #endif +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) { + return (c < 0.0) ? 0.0 : c * 12.92; + } + else { + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; + } +} + +vec4 texture_read_as_srgb(sampler2D tex, vec2 co) +{ + /* By convention image textures return scene linear colors, but + * overlays still assume srgb. */ + vec4 color = texture(tex, co); + color.r = linearrgb_to_srgb(color.r); + color.g = linearrgb_to_srgb(color.g); + color.b = linearrgb_to_srgb(color.b); + return color; +} + void main() { vec2 uv = uv_interp; @@ -24,7 +45,7 @@ void main() uv = (floor(uv_interp * tex_size) + 0.5) / tex_size; } - vec4 color = texture(image, uv); + vec4 color = texture_read_as_srgb(image, uv); color.a *= alpha; #ifdef TEXTURE_PAINT_MASK diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl index 03d933b9196..564f988348e 100644 --- a/source/blender/draw/modes/shaders/paint_texture_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl @@ -1,7 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in vec2 u; /* active uv map */ in vec3 pos; @@ -17,7 +14,8 @@ out vec2 masking_uv_interp; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); uv_interp = u; @@ -26,6 +24,6 @@ void main() #endif #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl index 54f6d1a4aea..53e72cc8a20 100644 --- a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl @@ -1,7 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in vec3 pos; in vec3 c; /* active color */ @@ -17,11 +14,12 @@ vec3 srgb_to_linear_attr(vec3 c) void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); finalColor = srgb_to_linear_attr(c); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/paint_weight_vert.glsl b/source/blender/draw/modes/shaders/paint_weight_vert.glsl index e95b116df79..330cc7d19f4 100644 --- a/source/blender/draw/modes/shaders/paint_weight_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_weight_vert.glsl @@ -1,7 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in float weight; in vec3 pos; @@ -9,12 +6,13 @@ out vec2 weight_interp; /* (weight, alert) */ void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); /* Separate actual weight and alerts for independent interpolation */ weight_interp = max(vec2(weight, -weight), 0.0); #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl index a163fd7e8b3..10bf8729f47 100644 --- a/source/blender/draw/modes/shaders/paint_wire_vert.glsl +++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl @@ -1,7 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; - in vec3 pos; in vec4 nor; /* flag stored in w */ @@ -16,7 +13,8 @@ void main() bool is_select = false; bool is_hidden = false; #endif - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); /* Add offset in Z to avoid zfighting and render selected wires on top. */ /* TODO scale this bias using znear and zfar range. */ gl_Position.z -= (is_select ? 2e-4 : 1e-4); @@ -46,6 +44,6 @@ void main() finalColor.a = nor.w; #ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz); + world_clip_planes_calc_clip_distance(world_pos); #endif } diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl index 578a4935b37..49d843b7e0e 100644 --- a/source/blender/draw/modes/shaders/particle_strand_frag.glsl +++ b/source/blender/draw/modes/shaders/particle_strand_frag.glsl @@ -1,4 +1,3 @@ -uniform mat4 ModelViewProjectionMatrix; in vec4 finalColor; #ifdef USE_POINTS diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl index 6dac6d6b980..c3f8fb89c17 100644 --- a/source/blender/draw/modes/shaders/particle_strand_vert.glsl +++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl @@ -1,6 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; - in vec3 pos; in float color; @@ -47,7 +45,8 @@ vec3 weight_to_rgb(float weight) void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); #ifdef USE_WEIGHT finalColor = vec4(weight_to_rgb(color), 1.0); diff --git a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl index e5e34fee57e..7b026836690 100644 --- a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl +++ b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl @@ -1,5 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; uniform float maskOpacity; in vec3 pos; @@ -9,7 +8,8 @@ out vec4 finalColor; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); float mask = 1.0 - (msk * maskOpacity); finalColor = vec4(mask, mask, mask, 1.0); diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl index 32207afa0b1..e96a789b8b1 100644 --- a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl +++ b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl @@ -1,6 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix; - uniform sampler3D velocityX; uniform sampler3D velocityY; uniform sampler3D velocityZ; @@ -109,5 +107,6 @@ void main() pos += (((gl_VertexID % 2) == 1) ? velocity : vec3(0.0)) * displaySize * voxel_size; #endif - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); } diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 978bd772b6f..ce6778a1ff9 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -51,6 +51,7 @@ set(SRC keyframes_general.c keyframing.c keyingsets.c + time_scrub_ui.c anim_intern.h ) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 6d1ee08d5e9..00025112835 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -485,16 +485,10 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) { if (name) { - BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("Summary"), ANIM_CHAN_NAME_SIZE); } } -// FIXME: this is really a temp icon I think -static int acf_summary_icon(bAnimListElem *UNUSED(ale)) -{ - return ICON_BORDERMOVE; -} - /* check if some setting exists for this channel */ static bool acf_summary_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), @@ -557,7 +551,7 @@ static bAnimChannelType ACF_SUMMARY = { acf_summary_name, /* name */ NULL, /* name prop */ - acf_summary_icon, /* icon */ + NULL, /* icon */ acf_summary_setting_valid, /* has setting */ acf_summary_setting_flag, /* flag for setting */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 6e0277d5fff..9e09fc485a6 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -55,6 +55,7 @@ #include "DEG_depsgraph_build.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -2531,17 +2532,6 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ac->ar->v2d; rctf rectf; - float ymin, ymax; - - /* set initial y extents */ - if (ac->datatype == ANIMCONT_NLA) { - ymin = (float)(-NLACHANNEL_HEIGHT(snla)); - ymax = 0.0f; - } - else { - ymin = 0.0f; - ymax = (float)(-ACHANNEL_HEIGHT(ac)); - } /* convert border-region to view coordinates */ UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin); @@ -2551,8 +2541,17 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + float ymax; + if (ac->datatype == ANIMCONT_NLA) { + ymax = NLACHANNEL_FIRST_TOP(ac); + } + else { + ymax = ACHANNEL_FIRST_TOP(ac); + } + /* loop over data, doing box select */ for (ale = anim_data.first; ale; ale = ale->next) { + float ymin; if (ac->datatype == ANIMCONT_NLA) { ymin = ymax - NLACHANNEL_STEP(snla); } @@ -2729,32 +2728,25 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2]) ar = ac->ar; v2d = &ar->v2d; - /* Figure out which channel user clicked in. - * - * Note: although channels technically start at (y = ACHANNEL_FIRST), - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use ACHANNEL_HEIGHT_HALF. - */ + /* Figure out which channel user clicked in. */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); if (ac->datatype == ANIMCONT_NLA) { SpaceNla *snla = (SpaceNla *)ac->sl; - UI_view2d_listview_view_to_cell(v2d, - NLACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), + NLACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); } else { - UI_view2d_listview_view_to_cell(v2d, - ACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, - (float)ACHANNEL_HEIGHT_HALF(ac), + ACHANNEL_FIRST_TOP(ac), x, y, NULL, @@ -3206,19 +3198,12 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE selectmode = SELECT_REPLACE; } - /* figure out which channel user clicked in - * - * Note: - * although channels technically start at (y = ACHANNEL_FIRST), - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use ACHANNEL_HEIGHT_HALF. - */ + /* figure out which channel user clicked in */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - ACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, - (float)ACHANNEL_HEIGHT_HALF(&ac), + ACHANNEL_FIRST_TOP(&ac), x, y, NULL, diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index b94d0e3ada7..a228d819286 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1823,7 +1823,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, } /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { continue; } } @@ -3022,7 +3022,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m } /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { return false; } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 66cdae07a36..876bc9ae3e4 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -481,7 +481,9 @@ static void draw_markers_background(rctf *rect) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - const unsigned char shade[4] = {0, 0, 0, 16}; + unsigned char shade[4]; + UI_GetThemeColor4ubv(TH_SCRUBBING_BACKGROUND, shade); + immUniformColor4ubv(shade); GPU_blend(true); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 2a8702802aa..fe079eb59a0 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -1249,7 +1249,8 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_update_anim_flag(C); DEG_relations_tag_update(CTX_data_main(C)); - DEG_id_tag_update(ptr.id.data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + + DEG_id_tag_update(ptr.id.data, ID_RECALC_ANIMATION); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 5214c5f78fa..be8de66a262 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -315,8 +315,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo clear_fcurve_keys(fcu); /* check if curve is really unused and if it is, return signal for deletion */ - if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && - (fcu->driver == NULL)) { + if (BKE_fcurve_is_empty(fcu)) { AnimData *adt = ale->adt; ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index a0433b49b16..2dc17c5c397 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1307,8 +1307,8 @@ static bool insert_keyframe_fcurve_value(Main *bmain, * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet * but still try to get the F-Curve if it exists... */ - FCurve *fcu = verify_fcurve( - bmain, act, group, ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); + bool can_create_curve = (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) == 0; + FCurve *fcu = verify_fcurve(bmain, act, group, ptr, rna_path, array_index, can_create_curve); /* we may not have a F-Curve when we're replacing only... */ if (fcu) { @@ -1432,7 +1432,7 @@ short insert_keyframe(Main *bmain, /* Key the entire array. */ if (array_index == -1 || force_all) { /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ - if (force_all && (flag & INSERTKEY_REPLACE) != 0) { + if (force_all && (flag & (INSERTKEY_REPLACE | INSERTKEY_AVAILABLE)) != 0) { int exclude = -1; for (array_index = 0; array_index < value_count; array_index++) { @@ -1455,7 +1455,7 @@ short insert_keyframe(Main *bmain, } if (exclude != -1) { - flag &= ~INSERTKEY_REPLACE; + flag &= ~(INSERTKEY_REPLACE | INSERTKEY_AVAILABLE); for (array_index = 0; array_index < value_count; array_index++) { if (array_index != exclude) { @@ -1557,8 +1557,7 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra) delete_fcurve_key(fcu, i, 1); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); } diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c new file mode 100644 index 00000000000..37e7eab74d4 --- /dev/null +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -0,0 +1,214 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edanimation + */ + +#include "BKE_context.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "ED_time_scrub_ui.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_view2d.h" +#include "UI_resources.h" + +#include "DNA_scene_types.h" + +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_timecode.h" + +#include "RNA_access.h" + +static void get_scrubbing_region_rect(const ARegion *ar, rcti *rect) +{ + rect->xmin = 0; + rect->xmax = ar->winx; + rect->ymax = ar->winy; + rect->ymin = rect->ymax - UI_SCRUBBING_MARGIN_Y; +} + +static int get_centered_text_y(const rcti *rect) +{ + return BLI_rcti_cent_y(rect) - UI_DPI_FAC * 4; +} + +static void draw_background(const rcti *rect) +{ + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_SCRUBBING_BACKGROUND); + + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + + GPU_blend(false); + + immUnbindProgram(); +} + +static void get_current_time_str( + const Scene *scene, bool display_seconds, int frame, uint max_len, char *r_str) +{ + if (display_seconds) { + BLI_timecode_string_from_time(r_str, max_len, 0, FRA2TIME(frame), FPS, U.timecode_style); + } + else { + BLI_snprintf(r_str, max_len, "%d", frame); + } +} + +static void draw_current_frame(const Scene *scene, + bool display_seconds, + const View2D *v2d, + const rcti *scrubbing_region_rect, + int current_frame) +{ + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + const unsigned char color[] = {255, 255, 255, 255}; + int frame_x = UI_view2d_view_to_region_x(v2d, current_frame); + + char frame_str[64]; + get_current_time_str(scene, display_seconds, current_frame, sizeof(frame_str), frame_str); + float text_width = UI_fontstyle_string_width(fstyle, frame_str); + float box_width = MAX2(text_width + 8 * UI_DPI_FAC, 24 * UI_DPI_FAC); + float box_padding = 3 * UI_DPI_FAC; + + float bg_color[4]; + UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color); + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + + UI_draw_roundbox_3fvAlpha(true, + frame_x - box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymin + box_padding, + frame_x + box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymax - box_padding, + 4 * UI_DPI_FAC, + bg_color, + 1.0f); + + UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color); + UI_draw_roundbox_aa(false, + frame_x - box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymin + box_padding, + frame_x + box_width / 2 + U.pixelsize / 2, + scrubbing_region_rect->ymax - box_padding, + 4 * UI_DPI_FAC, + bg_color); + + UI_fontstyle_draw_simple(fstyle, + frame_x - text_width / 2 + U.pixelsize / 2, + get_centered_text_y(scrubbing_region_rect), + frame_str, + color); +} + +void ED_scrubbing_draw(const ARegion *ar, + const Scene *scene, + bool display_seconds, + bool discrete_frames) +{ + const View2D *v2d = &ar->v2d; + + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(ar); + + rcti scrubbing_region_rect; + get_scrubbing_region_rect(ar, &scrubbing_region_rect); + + draw_background(&scrubbing_region_rect); + + rcti numbers_rect = scrubbing_region_rect; + numbers_rect.ymin = get_centered_text_y(&scrubbing_region_rect) - 4 * UI_DPI_FAC; + if (discrete_frames) { + UI_view2d_draw_scale_x__discrete_frames_or_seconds( + ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); + } + else { + UI_view2d_draw_scale_x__frames_or_seconds( + ar, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); + } + + draw_current_frame(scene, display_seconds, v2d, &scrubbing_region_rect, scene->r.cfra); + + GPU_matrix_pop_projection(); +} + +bool ED_event_in_scrubbing_region(const ARegion *ar, const wmEvent *event) +{ + rcti rect = ar->winrct; + rect.ymin = rect.ymax - UI_SCRUBBING_MARGIN_Y; + return BLI_rcti_isect_pt(&rect, event->x, event->y); +} + +void ED_channel_search_draw(const bContext *C, ARegion *ar, bDopeSheet *dopesheet) +{ + GPU_matrix_push_projection(); + wmOrtho2_region_pixelspace(ar); + + rcti rect; + rect.xmin = 0; + rect.xmax = ceilf(ar->sizex * UI_DPI_FAC); + rect.ymin = ar->sizey * UI_DPI_FAC - UI_SCRUBBING_MARGIN_Y; + rect.ymax = ceilf(ar->sizey * UI_DPI_FAC); + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_BACK); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); + + uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + + PointerRNA ptr; + RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet, &ptr); + PropertyRNA *prop = RNA_struct_find_property(&ptr, "filter_text"); + + int padding = 2 * UI_DPI_FAC; + uiDefAutoButR(block, + &ptr, + prop, + -1, + "", + ICON_NONE, + rect.xmin + padding, + rect.ymin + padding, + BLI_rcti_size_x(&rect) - 2 * padding, + BLI_rcti_size_y(&rect) - 2 * padding); + + UI_block_end(C, block); + UI_block_draw(C, block); + + GPU_matrix_pop_projection(); +} diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 6c2d9fe8f42..569eb7e2e04 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -210,6 +210,8 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot); void POSE_OT_push(struct wmOperatorType *ot); void POSE_OT_relax(struct wmOperatorType *ot); +void POSE_OT_push_rest(struct wmOperatorType *ot); +void POSE_OT_relax_rest(struct wmOperatorType *ot); void POSE_OT_breakdown(struct wmOperatorType *ot); void POSE_OT_propagate(struct wmOperatorType *ot); diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 083967d5d41..9a1582679a4 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -180,7 +180,17 @@ void ED_armature_bone_rename(Main *bmain, if (bone) { unique_bone_name(arm, newname); + + if (arm->bonehash) { + BLI_assert(BLI_ghash_haskey(arm->bonehash, bone->name)); + BLI_ghash_remove(arm->bonehash, bone->name, NULL, NULL); + } + BLI_strncpy(bone->name, newname, MAXBONENAME); + + if (arm->bonehash) { + BLI_ghash_insert(arm->bonehash, bone->name, bone); + } } else { return; diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index b53ae813f10..a29d0f5f158 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -146,6 +146,8 @@ void ED_operatortypes_armature(void) /* POSE SLIDING */ WM_operatortype_append(POSE_OT_push); WM_operatortype_append(POSE_OT_relax); + WM_operatortype_append(POSE_OT_push_rest); + WM_operatortype_append(POSE_OT_relax_rest); WM_operatortype_append(POSE_OT_breakdown); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index b2ca1d84520..2c61818d902 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -66,10 +66,16 @@ /* *************************************** Join *************************************** */ /* NOTE: no operator define here as this is exported to the Object-level operator */ -static void joined_armature_fix_links_constraints( - Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone, ListBase *lb) +static void joined_armature_fix_links_constraints(Main *bmain, + Object *ob, + Object *tarArm, + Object *srcArm, + bPoseChannel *pchan, + EditBone *curbone, + ListBase *lb) { bConstraint *con; + bool changed = false; for (con = lb->first; con; con = con->next) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); @@ -84,10 +90,12 @@ static void joined_armature_fix_links_constraints( if (ct->tar == srcArm) { if (ct->subtarget[0] == '\0') { ct->tar = tarArm; + changed = true; } else if (STREQ(ct->subtarget, pchan->name)) { ct->tar = tarArm; BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget)); + changed = true; } } } @@ -104,13 +112,21 @@ static void joined_armature_fix_links_constraints( if (data->act) { BKE_action_fix_paths_rename( &tarArm->id, data->act, "pose.bones[", pchan->name, curbone->name, 0, 0, false); + + DEG_id_tag_update_ex(bmain, &data->act->id, ID_RECALC_COPY_ON_WRITE); } } } + + if (changed) { + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE); + } } /* userdata for joined_armature_fix_animdata_cb() */ typedef struct tJoinArmature_AdtFixData { + Main *bmain; + Object *srcArm; Object *tarArm; @@ -129,6 +145,7 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data ID *dst_id = &afd->tarArm->id; GHashIterator gh_iter; + bool changed = false; /* Fix paths - If this is the target object, it will have some "dirty" paths */ if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) { @@ -142,6 +159,8 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data fcu->rna_path = BKE_animsys_fix_rna_path_rename( id, fcu->rna_path, "pose.bones", old_name, new_name, 0, 0, false); + changed = true; + /* we don't want to apply a second remapping on this driver now, * so stop trying names, but keep fixing drivers */ @@ -163,6 +182,8 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data if (dtar->id == src_id) { dtar->id = dst_id; + changed = true; + /* also check on the subtarget... * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own * little twists so that we know that it isn't going to clobber the wrong data @@ -193,6 +214,10 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data DRIVER_TARGETS_LOOPER_END; } } + + if (changed) { + DEG_id_tag_update_ex(afd->bmain, id, ID_RECALC_COPY_ON_WRITE); + } } /* Helper function for armature joining - link fixing */ @@ -210,13 +235,14 @@ static void joined_armature_fix_links( pose = ob->pose; for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) { joined_armature_fix_links_constraints( - tarArm, srcArm, pchan, curbone, &pchant->constraints); + bmain, ob, tarArm, srcArm, pchan, curbone, &pchant->constraints); } } /* fix object-level constraints */ if (ob != srcArm) { - joined_armature_fix_links_constraints(tarArm, srcArm, pchan, curbone, &ob->constraints); + joined_armature_fix_links_constraints( + bmain, ob, tarArm, srcArm, pchan, curbone, &ob->constraints); } /* See if an object is parented to this armature */ @@ -231,6 +257,8 @@ static void joined_armature_fix_links( /* make tar armature be new parent */ ob->parent = tarArm; + + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE); } } } @@ -286,6 +314,7 @@ int join_armature_exec(bContext *C, wmOperator *op) BLI_assert(ob_active->data != ob_iter->data); /* init callback data for fixing up AnimData links later */ + afd.bmain = bmain; afd.srcArm = ob_iter; afd.tarArm = ob_active; afd.names_map = BLI_ghash_str_new("join_armature_adt_fix"); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index fbbb68d2003..23ddf77e63d 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -70,7 +70,7 @@ Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases, EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { + if (bases[base_index]->object->runtime.select_id == hit_object) { base = bases[base_index]; break; } @@ -94,7 +94,7 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects, EditBone *ebone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (objects[ob_index]->select_id == hit_object) { + if (objects[ob_index]->runtime.select_id == hit_object) { ob = objects[ob_index]; break; } @@ -118,7 +118,7 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases, Bone *bone = NULL; /* TODO(campbell): optimize, eg: sort & binary search. */ for (uint base_index = 0; base_index < bases_len; base_index++) { - if (bases[base_index]->object->select_id == hit_object) { + if (bases[base_index]->object->runtime.select_id == hit_object) { base = bases[base_index]; break; } @@ -300,6 +300,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv const bool sel = !RNA_boolean_get(op->ptr, "deselect"); view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); Base *base = NULL; bone = get_nearest_bone(C, event->mval, true, &base); @@ -1817,6 +1818,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const Base *base_dst = NULL; view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); ebone_src = arm->act_edbone; ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index b23081cd6fa..27076f84c7f 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -127,7 +127,6 @@ void bone_free(bArmature *arm, EditBone *bone) if (bone->prop) { IDP_FreeProperty(bone->prop); - MEM_freeN(bone->prop); } /* Clear references from other edit bones. */ @@ -650,6 +649,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) Object *obt; /* armature bones */ + BKE_armature_bone_hash_free(arm); BKE_armature_bonelist_free(&arm->bonebase); arm->act_bone = NULL; @@ -754,6 +754,8 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) /* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */ armature_finalize_restpose(&arm->bonebase, arm->edbo); + BKE_armature_bone_hash_make(arm); + /* so all users of this armature should get rebuilt */ for (obt = bmain->objects.first; obt; obt = obt->id.next) { if (obt->data == arm) { @@ -774,7 +776,6 @@ void ED_armature_edit_free(struct bArmature *arm) for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->prop) { IDP_FreeProperty(eBone->prop); - MEM_freeN(eBone->prop); } } @@ -808,7 +809,6 @@ void ED_armature_ebone_listbase_free(ListBase *lb) if (ebone->prop) { IDP_FreeProperty(ebone->prop); - MEM_freeN(ebone->prop); } MEM_freeN(ebone); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index cf64210ebdb..954beda7777 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -65,7 +65,7 @@ #include "armature_intern.h" -#define DEBUG_TIME +#undef DEBUG_TIME #include "PIL_time.h" #ifdef DEBUG_TIME @@ -197,38 +197,6 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre ListBase targets = {NULL, NULL}; bool free_depsgraph = false; - /* Override depsgraph with a filtered, simpler copy */ - if (!current_frame_only && G.debug_value != -1) { - DEG_FilterQuery query = {{0}}; - - DEG_FilterTarget *dft_ob = MEM_callocN(sizeof(DEG_FilterTarget), "DEG_FilterTarget"); - dft_ob->id = &ob->id; - BLI_addtail(&query.targets, dft_ob); - -#ifdef DEBUG_TIME - TIMEIT_START(filter_pose_depsgraph); -#endif - - depsgraph = DEG_graph_filter(depsgraph, bmain, &query); - -#ifdef DEBUG_TIME - TIMEIT_END(filter_pose_depsgraph); -#endif - - free_depsgraph = true; - MEM_freeN(dft_ob); - -#ifdef DEBUG_TIME - TIMEIT_START(filter_pose_update); -#endif - - BKE_scene_graph_update_tagged(depsgraph, bmain); - -#ifdef DEBUG_TIME - TIMEIT_END(filter_pose_update); -#endif - } - /* set flag to force recalc, then grab the relevant bones to target */ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS; animviz_get_object_motionpaths(ob, &targets); diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 7b31897766d..4bcfdc700b3 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1018,7 +1018,6 @@ static void poselib_backup_free_data(tPoseLib_PreviewData *pld) /* free custom data */ if (plb->oldprops) { IDP_FreeProperty(plb->oldprops); - MEM_freeN(plb->oldprops); } /* free backup element now */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index d683c599f7b..9bc204c9e3b 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -134,6 +134,8 @@ typedef enum ePoseSlide_Modes { POSESLIDE_PUSH = 0, /* exaggerate the pose... */ POSESLIDE_RELAX, /* soften the pose... */ POSESLIDE_BREAKDOWN, /* slide between the endpoint poses, finding a 'soft' spot */ + POSESLIDE_PUSH_REST, + POSESLIDE_RELAX_REST, } ePoseSlide_Modes; /* Transforms/Channels to Affect */ @@ -627,6 +629,103 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) MEM_freeN(path); } +static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value) +{ + /* We only slide to the rest pose. So only use the default rest pose value */ + const int lock = pso->axislock; + for (int idx = 0; idx < 3; idx++) { + if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || + ((lock & PS_LOCK_Z) && (idx == 2))) { + float diff_val = default_value - vec[idx]; + if (pso->mode == POSESLIDE_RELAX_REST) { + vec[idx] += pso->percentage * diff_val; + } + else { + /* Push */ + vec[idx] -= pso->percentage * diff_val; + } + } + } +} + +static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat) +{ + /* We only slide to the rest pose. So only use the default rest pose value */ + float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f}; + if (!quat) { + /* Axis Angle */ + default_values[0] = 0.0f; + default_values[2] = 1.0f; + } + for (int idx = 0; idx < 4; idx++) { + float diff_val = default_values[idx] - vec[idx]; + if (pso->mode == POSESLIDE_RELAX_REST) { + vec[idx] += pso->percentage * diff_val; + } + else { + /* Push */ + vec[idx] -= pso->percentage * diff_val; + } + } +} + +/* apply() - perform the pose sliding between the current pose and the rest pose */ +static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso) +{ + tPChanFCurveLink *pfl; + + /* for each link, handle each set of transforms */ + for (pfl = pso->pfLinks.first; pfl; pfl = pfl->next) { + /* valid transforms for each PoseChannel should have been noted already + * - sliding the pose should be a straightforward exercise for location+rotation, + * but rotations get more complicated since we may want to use quaternion blending + * for quaternions instead... + */ + bPoseChannel *pchan = pfl->pchan; + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_LOC) && (pchan->flag & POSE_LOC)) { + /* calculate these for the 'location' vector, and use location curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->loc, 0.0f); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_SIZE) && (pchan->flag & POSE_SIZE)) { + /* calculate these for the 'scale' vector, and use scale curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->size, 1.0f); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_ROT) && (pchan->flag & POSE_ROT)) { + /* everything depends on the rotation mode */ + if (pchan->rotmode > 0) { + /* eulers - so calculate these for the 'eul' vector, and use euler_rotation curves */ + pose_slide_rest_pose_apply_vec3(pso, pchan->eul, 0.0f); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, false); + } + else { + /* quaternions - use quaternion blending */ + pose_slide_rest_pose_apply_other_rot(pso, pchan->quat, true); + } + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_BBONE_SHAPE) && (pchan->flag & POSE_BBONE_SHAPE)) { + /* bbone properties - they all start a "bbone_" prefix */ + // TODO Not implemented + // pose_slide_apply_props(pso, pfl, "bbone_"); + } + + if (ELEM(pso->channels, PS_TFM_ALL, PS_TFM_PROPS) && (pfl->oldprops)) { + /* Not strictly a transform, but custom properties contribute + * to the pose produced in many rigs (e.g. the facial rigs used in Sintel). */ + // TODO Not implemented + // pose_slide_apply_props(pso, pfl, "[\""); /* dummy " for texteditor bugs */ + } + } + + /* depsgraph updates + redraws */ + pose_slide_refresh(C, pso); +} + /* apply() - perform the pose sliding based on weighting various poses */ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso) { @@ -888,7 +987,12 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p /* initial apply for operator... */ /* TODO: need to calculate percentage for initial round too... */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } /* depsgraph updates + redraws */ pose_slide_refresh(C, pso); @@ -1122,7 +1226,12 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) pose_slide_reset(pso); /* apply... */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } } /* still running... */ @@ -1140,7 +1249,12 @@ static void pose_slide_cancel(bContext *UNUSED(C), wmOperator *op) static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso) { /* settings should have been set up ok for applying, so just apply! */ - pose_slide_apply(C, pso); + if (pso->mode != POSESLIDE_PUSH_REST && pso->mode != POSESLIDE_RELAX_REST) { + pose_slide_apply(C, pso); + } + else { + pose_slide_rest_pose_apply(C, pso); + } /* insert keyframes if needed */ pose_slide_autoKeyframe(C, pso); @@ -1200,7 +1314,7 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) /* ------------------------------------ */ -/* invoke() - for 'push' mode */ +/* invoke() - for 'push from breakdown' mode */ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso; @@ -1242,9 +1356,9 @@ static int pose_slide_push_exec(bContext *C, wmOperator *op) void POSE_OT_push(wmOperatorType *ot) { /* identifiers */ - ot->name = "Push Pose"; + ot->name = "Push Pose from Breakdown"; ot->idname = "POSE_OT_push"; - ot->description = "Exaggerate the current pose"; + ot->description = "Exaggerate the current pose in regards to the breakdown pose"; /* callbacks */ ot->exec = pose_slide_push_exec; @@ -1262,7 +1376,7 @@ void POSE_OT_push(wmOperatorType *ot) /* ........................ */ -/* invoke() - for 'relax' mode */ +/* invoke() - for 'relax to breakdown' mode */ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso; @@ -1304,9 +1418,9 @@ static int pose_slide_relax_exec(bContext *C, wmOperator *op) void POSE_OT_relax(wmOperatorType *ot) { /* identifiers */ - ot->name = "Relax Pose"; + ot->name = "Relax Pose to Breakdown"; ot->idname = "POSE_OT_relax"; - ot->description = "Make the current pose more similar to its surrounding ones"; + ot->description = "Make the current pose more similar to its breakdown pose"; /* callbacks */ ot->exec = pose_slide_relax_exec; @@ -1323,6 +1437,129 @@ void POSE_OT_relax(wmOperatorType *ot) } /* ........................ */ +/* invoke() - for 'push from rest pose' mode */ +static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + tPoseSlideOp *pso; + + /* initialize data */ + if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* initialise percentage so that it won't pop on first mouse move */ + pose_slide_mouse_update_percentage(pso, op, event); + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for push */ +static int pose_slide_push_rest_exec(bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialize data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_push_rest(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Push Pose from Rest Pose"; + ot->idname = "POSE_OT_push_rest"; + ot->description = "Push the current pose further away from the rest pose"; + + /* callbacks */ + ot->exec = pose_slide_push_rest_exec; + ot->invoke = pose_slide_push_rest_invoke; + ot->modal = pose_slide_modal; + ot->cancel = pose_slide_cancel; + ot->poll = ED_operator_posemode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ + +/* invoke() - for 'relax' mode */ +static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + tPoseSlideOp *pso; + + /* initialize data */ + if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* initialise percentage so that it won't pop on first mouse move */ + pose_slide_mouse_update_percentage(pso, op, event); + + /* do common setup work */ + return pose_slide_invoke_common(C, op, pso); +} + +/* exec() - for relax */ +static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op) +{ + tPoseSlideOp *pso; + + /* initialize data (from RNA-props) */ + if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { + pose_slide_exit(op); + return OPERATOR_CANCELLED; + } + else { + pso = op->customdata; + } + + /* do common exec work */ + return pose_slide_exec_common(C, op, pso); +} + +void POSE_OT_relax_rest(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Relax Pose to Rest Pose"; + ot->idname = "POSE_OT_relax_rest"; + ot->description = "Make the current pose more similar to the rest pose"; + + /* callbacks */ + ot->exec = pose_slide_relax_rest_exec; + ot->invoke = pose_slide_relax_rest_invoke; + ot->modal = pose_slide_modal; + ot->cancel = pose_slide_cancel; + ot->poll = ED_operator_posemode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_USE_EVAL_DATA; + + /* Properties */ + pose_slide_opdef_properties(ot); +} + +/* ........................ */ /* invoke() - for 'breakdown' mode */ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 6207d5412cf..ed728714c5b 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -59,6 +59,9 @@ #include "ED_screen.h" #include "ED_util.h" +#include "UI_interface.h" +#include "UI_resources.h" + #include "armature_intern.h" /* ********************************************** */ @@ -87,6 +90,229 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec } } +/* Sets the bone head, tail and roll to match the supplied parameters. */ +static void applyarmature_set_edit_position(EditBone *curbone, + const float pose_mat[4][4], + const float new_tail[3], + float r_new_arm_mat[4][4]) +{ + /* Simply copy the head/tail values from pchan over to curbone. */ + copy_v3_v3(curbone->head, pose_mat[3]); + copy_v3_v3(curbone->tail, new_tail); + + /* Fix roll: + * 1. find auto-calculated roll value for this bone now + * 2. remove this from the 'visual' y-rotation + */ + { + float premat[3][3], pmat[3][3]; + float delta[3]; + + /* Obtain new auto y-rotation. */ + sub_v3_v3v3(delta, curbone->tail, curbone->head); + + copy_m3_m4(pmat, pose_mat); + mat3_vec_to_roll(pmat, delta, &curbone->roll); + + /* Compute new rest pose matrix if requested. */ + if (r_new_arm_mat) { + vec_roll_to_mat3(delta, curbone->roll, premat); + copy_m4_m3(r_new_arm_mat, premat); + copy_v3_v3(r_new_arm_mat[3], pose_mat[3]); + } + } +} + +/* Copy properties over from pchan to curbone and reset channels. */ +static void applyarmature_transfer_properties(EditBone *curbone, + bPoseChannel *pchan, + const bPoseChannel *pchan_eval) +{ + /* Combine pose and rest values for bendy bone settings, + * then clear the pchan values (so we don't get a double-up). + */ + if (pchan->bone->segments > 1) { + /* Combine rest/pose values. */ + curbone->curve_in_x += pchan_eval->curve_in_x; + curbone->curve_in_y += pchan_eval->curve_in_y; + curbone->curve_out_x += pchan_eval->curve_out_x; + curbone->curve_out_y += pchan_eval->curve_out_y; + curbone->roll1 += pchan_eval->roll1; + curbone->roll2 += pchan_eval->roll2; + curbone->ease1 += pchan_eval->ease1; + curbone->ease2 += pchan_eval->ease2; + + curbone->scale_in_x *= pchan_eval->scale_in_x; + curbone->scale_in_y *= pchan_eval->scale_in_y; + curbone->scale_out_x *= pchan_eval->scale_out_x; + curbone->scale_out_y *= pchan_eval->scale_out_y; + + /* Reset pose values. */ + pchan->curve_in_x = pchan->curve_out_x = 0.0f; + pchan->curve_in_y = pchan->curve_out_y = 0.0f; + pchan->roll1 = pchan->roll2 = 0.0f; + pchan->ease1 = pchan->ease2 = 0.0f; + pchan->scale_in_x = pchan->scale_in_y = 1.0f; + pchan->scale_out_x = pchan->scale_out_y = 1.0f; + } + + /* Clear transform values for pchan. */ + zero_v3(pchan->loc); + zero_v3(pchan->eul); + unit_qt(pchan->quat); + unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); + pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; + + /* Set anim lock. */ + curbone->flag |= BONE_UNKEYED; +} + +/* Adjust the current edit position of the bone using the pose space matrix. */ +static void applyarmature_adjust_edit_position(bArmature *arm, + bPoseChannel *pchan, + const float delta_mat[4][4], + float r_new_arm_mat[4][4]) +{ + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); + float delta[3], new_tail[3], premat[3][3], new_pose[4][4]; + + /* Current orientation matrix. */ + sub_v3_v3v3(delta, curbone->tail, curbone->head); + vec_roll_to_mat3(delta, curbone->roll, premat); + + /* New location and orientation. */ + mul_m4_m4m3(new_pose, delta_mat, premat); + mul_v3_m4v3(new_pose[3], delta_mat, curbone->head); + mul_v3_m4v3(new_tail, delta_mat, curbone->tail); + + applyarmature_set_edit_position(curbone, new_pose, new_tail, r_new_arm_mat); +} + +/* Data about parent position for Apply To Selected mode. */ +typedef struct ApplyArmature_ParentState { + Bone *bone; + + /* New rest position of the bone with scale included. */ + float new_rest_mat[4][4]; + /* New arm_mat of the bone == new_rest_mat without scale. */ + float new_arm_mat[4][4]; +} ApplyArmature_ParentState; + +/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */ +static void applyarmature_process_selected_rec(bArmature *arm, + bPose *pose, + bPose *pose_eval, + Bone *bone, + ListBase *selected, + ApplyArmature_ParentState *pstate) +{ + bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name); + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name); + + if (!pchan || !pchan_eval) + return; + + ApplyArmature_ParentState new_pstate = {.bone = bone}; + + if (BLI_findptr(selected, pchan, offsetof(CollectionPointerLink, ptr.data))) { + /* SELECTED BONE: Snap to final pose transform minus unapplied parent effects. + * + * I.e. bone position with accumulated parent effects but no local + * transformation will match the original final pose_mat. + * + * Pose channels are reset as expected. + */ + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); + BoneParentTransform invparent; + float new_tail[3]; + + if (pchan->parent) { + BoneParentTransform old_bpt, new_bpt; + float offs_bone[4][4]; + + /* Parent effects on the bone transform that have to be removed. */ + BKE_bone_offset_matrix_get(bone, offs_bone); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, bone->parent->arm_mat, pchan_eval->parent->pose_mat, &old_bpt); + + /* Applied parent effects that have to be kept, if any. */ + float(*new_parent_pose)[4] = pstate ? pstate->new_rest_mat : bone->parent->arm_mat; + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, bone->parent->arm_mat, new_parent_pose, &new_bpt); + + BKE_bone_parent_transform_invert(&old_bpt); + BKE_bone_parent_transform_combine(&new_bpt, &old_bpt, &invparent); + } + else { + BKE_bone_parent_transform_clear(&invparent); + } + + /* Apply change without inherited unapplied parent transformations. */ + BKE_bone_parent_transform_apply(&invparent, pchan_eval->pose_mat, new_pstate.new_rest_mat); + + copy_v3_fl3(new_tail, 0.0, bone->length, 0.0); + mul_m4_v3(new_pstate.new_rest_mat, new_tail); + + applyarmature_set_edit_position( + curbone, new_pstate.new_rest_mat, new_tail, new_pstate.new_arm_mat); + applyarmature_transfer_properties(curbone, pchan, pchan_eval); + + pstate = &new_pstate; + } + else if (pstate) { + /* UNSELECTED CHILD OF SELECTED: Include applied parent effects. + * + * The inherited transform of applied (selected) bones is baked + * into the rest pose so that the final bone position doesn't + * change. + * + * Pose channels are not changed, with the exception of the inherited + * applied parent scale being baked into the location pose channel. + */ + BoneParentTransform bpt; + float offs_bone[4][4], delta[4][4], old_chan_loc[3]; + + /* Include applied parent effects. */ + BKE_bone_offset_matrix_get(bone, offs_bone); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, pstate->bone->arm_mat, pstate->new_rest_mat, &bpt); + + unit_m4(new_pstate.new_rest_mat); + BKE_bone_parent_transform_apply(&bpt, new_pstate.new_rest_mat, new_pstate.new_rest_mat); + + /* Bone location channel in pose space relative to bone head. */ + mul_v3_mat3_m4v3(old_chan_loc, bpt.loc_mat, pchan_eval->loc); + + /* Apply the change to the rest bone position. */ + invert_m4_m4(delta, bone->arm_mat); + mul_m4_m4m4(delta, new_pstate.new_rest_mat, delta); + + applyarmature_adjust_edit_position(arm, pchan, delta, new_pstate.new_arm_mat); + + /* Location pose channel has to be updated, because it is affected + * by parent scaling, and the rest pose has no scale by definition. */ + if (!(bone->flag & BONE_CONNECTED) && !is_zero_v3(old_chan_loc)) { + float inv_parent_arm[4][4]; + + /* Compute the channel coordinate space matrices for the new rest state. */ + invert_m4_m4(inv_parent_arm, pstate->new_arm_mat); + mul_m4_m4m4(offs_bone, inv_parent_arm, new_pstate.new_arm_mat); + BKE_bone_parent_transform_calc_from_matrices( + bone->flag, offs_bone, pstate->new_arm_mat, pstate->new_arm_mat, &bpt); + + /* Re-apply the location to keep the final effect. */ + invert_m4(bpt.loc_mat); + mul_v3_mat3_m4v3(pchan->loc, bpt.loc_mat, old_chan_loc); + } + + pstate = &new_pstate; + } + + for (Bone *child = bone->childbase.first; child; child = child->next) { + applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate); + } +} + /* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { @@ -99,7 +325,9 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; - EditBone *curbone; + ListBase selected_bones; + + const bool use_selected = RNA_boolean_get(op->ptr, "selected"); /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) { @@ -119,80 +347,37 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) "transforms stored are relative to the old rest pose"); } + /* Find selected bones before switching to edit mode. */ + if (use_selected) { + CTX_data_selected_pose_bones(C, &selected_bones); + + if (!selected_bones.first) { + return OPERATOR_CANCELLED; + } + } + /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); - curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); - - /* simply copy the head/tail values from pchan over to curbone */ - copy_v3_v3(curbone->head, pchan_eval->pose_head); - copy_v3_v3(curbone->tail, pchan_eval->pose_tail); - - /* fix roll: - * 1. find auto-calculated roll value for this bone now - * 2. remove this from the 'visual' y-rotation - */ - { - float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; - float delta[3], eul[3]; - - /* obtain new auto y-rotation */ - sub_v3_v3v3(delta, curbone->tail, curbone->head); - vec_roll_to_mat3(delta, 0.0f, premat); - invert_m3_m3(imat, premat); - - /* get pchan 'visual' matrix */ - copy_m3_m4(pmat, pchan_eval->pose_mat); - - /* remove auto from visual and get euler rotation */ - mul_m3_m3m3(tmat, imat, pmat); - mat3_to_eul(eul, tmat); - - /* just use this euler-y as new roll value */ - curbone->roll = eul[1]; + if (use_selected) { + /* The selected only mode requires a recursive walk to handle parent-child relations. */ + for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) { + applyarmature_process_selected_rec(arm, pose, ob_eval->pose, bone, &selected_bones, NULL); } - /* combine pose and rest values for bendy bone settings, - * then clear the pchan values (so we don't get a double-up) - */ - if (pchan->bone->segments > 1) { - /* combine rest/pose values */ - curbone->curve_in_x += pchan_eval->curve_in_x; - curbone->curve_in_y += pchan_eval->curve_in_y; - curbone->curve_out_x += pchan_eval->curve_out_x; - curbone->curve_out_y += pchan_eval->curve_out_y; - curbone->roll1 += pchan_eval->roll1; - curbone->roll2 += pchan_eval->roll2; - curbone->ease1 += pchan_eval->ease1; - curbone->ease2 += pchan_eval->ease2; - curbone->scale_in_x *= pchan_eval->scale_in_x; - curbone->scale_in_y *= pchan_eval->scale_in_y; - curbone->scale_out_x *= pchan_eval->scale_out_x; - curbone->scale_out_y *= pchan_eval->scale_out_y; - - /* reset pose values */ - pchan->curve_in_x = pchan->curve_out_x = 0.0f; - pchan->curve_in_y = pchan->curve_out_y = 0.0f; - pchan->roll1 = pchan->roll2 = 0.0f; - pchan->ease1 = pchan->ease2 = 0.0f; - pchan->scale_in_x = pchan->scale_in_y = 1.0f; - pchan->scale_out_x = pchan->scale_out_y = 1.0f; - } - - /* clear transform values for pchan */ - zero_v3(pchan->loc); - zero_v3(pchan->eul); - unit_qt(pchan->quat); - unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); - pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; + BLI_freelistN(&selected_bones); + } + else { + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + EditBone *curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name); - /* set anim lock */ - curbone->flag |= BONE_UNKEYED; + applyarmature_set_edit_position(curbone, pchan_eval->pose_mat, pchan_eval->pose_tail, NULL); + applyarmature_transfer_properties(curbone, pchan, pchan_eval); + } } /* convert editbones back to bones, and then free the edit-data */ @@ -212,6 +397,17 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void apply_armature_pose2bones_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + uiItemR(layout, &ptr, "selected", 0, NULL, ICON_NONE); +} + void POSE_OT_armature_apply(wmOperatorType *ot) { /* identifiers */ @@ -222,9 +418,16 @@ void POSE_OT_armature_apply(wmOperatorType *ot) /* callbacks */ ot->exec = apply_armature_pose2bones_exec; ot->poll = ED_operator_posemode; + ot->ui = apply_armature_pose2bones_ui; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; + + RNA_def_boolean(ot->srna, + "selected", + false, + "Selected Only", + "Only apply the selected bones (with propagation to children)"); } /* set the current pose as the restpose */ @@ -1022,7 +1225,6 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op) for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->prop) { IDP_FreeProperty(pchan->prop); - MEM_freeN(pchan->prop); } } diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index a1f763ac57d..fbaf2c896d0 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -203,7 +203,6 @@ void poseAnim_mapping_free(ListBase *pfLinks) /* free custom properties */ if (pfl->oldprops) { IDP_FreeProperty(pfl->oldprops); - MEM_freeN(pfl->oldprops); } /* free list of F-Curve reference links */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index a787b45c13c..1e40ba2f19b 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -2584,33 +2584,42 @@ void CURVE_OT_switch_direction(wmOperatorType *ot) static int set_goal_weight_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - float weight = RNA_float_get(op->ptr, "weight"); - int a; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (bezt->f2 & SELECT) { - bezt->weight = weight; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + float weight = RNA_float_get(op->ptr, "weight"); + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (bezt->f2 & SELECT) { + bezt->weight = weight; + } } } - } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (bp->f1 & SELECT) { - bp->weight = weight; + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (bp->f1 & SELECT) { + bp->weight = weight; + } } } } + + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2638,33 +2647,42 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot) static int set_radius_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - float radius = RNA_float_get(op->ptr, "radius"); - int a; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { - if (bezt->f2 & SELECT) { - bezt->radius = radius; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + float radius = RNA_float_get(op->ptr, "radius"); + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++) { + if (bezt->f2 & SELECT) { + bezt->radius = radius; + } } } - } - else if (nu->bp) { - for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (bp->f1 & SELECT) { - bp->radius = radius; + else if (nu->bp) { + for (bp = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (bp->f1 & SELECT) { + bp->radius = radius; + } } } } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -2743,81 +2761,90 @@ static void smooth_single_bp(BPoint *bp, static int smooth_exec(bContext *C, wmOperator *UNUSED(op)) { const float factor = 1.0f / 6.0f; - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - int a, a_end; - bool changed = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->bezt) { - /* duplicate the curve to use in weight calculation */ - const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt); - BezTriple *bezt; - changed = false; + int a, a_end; + bool changed = false; - /* check whether its cyclic or not, and set initial & final conditions */ - if (nu->flagu & CU_NURB_CYCLIC) { - a = 0; - a_end = nu->pntsu; - } - else { - a = 1; - a_end = nu->pntsu - 1; - } + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->bezt) { + /* duplicate the curve to use in weight calculation */ + const BezTriple *bezt_orig = MEM_dupallocN(nu->bezt); + BezTriple *bezt; + changed = false; - /* for all the curve points */ - for (; a < a_end; a++) { - /* respect selection */ - bezt = &nu->bezt[a]; - if (bezt->f2 & SELECT) { - const BezTriple *bezt_orig_prev, *bezt_orig_next; + /* check whether its cyclic or not, and set initial & final conditions */ + if (nu->flagu & CU_NURB_CYCLIC) { + a = 0; + a_end = nu->pntsu; + } + else { + a = 1; + a_end = nu->pntsu - 1; + } - bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)]; - bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)]; + /* for all the curve points */ + for (; a < a_end; a++) { + /* respect selection */ + bezt = &nu->bezt[a]; + if (bezt->f2 & SELECT) { + const BezTriple *bezt_orig_prev, *bezt_orig_next; - smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor); + bezt_orig_prev = &bezt_orig[mod_i(a - 1, nu->pntsu)]; + bezt_orig_next = &bezt_orig[mod_i(a + 1, nu->pntsu)]; - changed = true; + smooth_single_bezt(bezt, bezt_orig_prev, bezt_orig_next, factor); + + changed = true; + } + } + MEM_freeN((void *)bezt_orig); + if (changed) { + BKE_nurb_handles_calc(nu); } } - MEM_freeN((void *)bezt_orig); - if (changed) { - BKE_nurb_handles_calc(nu); - } - } - else if (nu->bp) { - /* Same as above, keep these the same! */ - const BPoint *bp_orig = MEM_dupallocN(nu->bp); - BPoint *bp; + else if (nu->bp) { + /* Same as above, keep these the same! */ + const BPoint *bp_orig = MEM_dupallocN(nu->bp); + BPoint *bp; - if (nu->flagu & CU_NURB_CYCLIC) { - a = 0; - a_end = nu->pntsu; - } - else { - a = 1; - a_end = nu->pntsu - 1; - } + if (nu->flagu & CU_NURB_CYCLIC) { + a = 0; + a_end = nu->pntsu; + } + else { + a = 1; + a_end = nu->pntsu - 1; + } - for (; a < a_end; a++) { - bp = &nu->bp[a]; - if (bp->f1 & SELECT) { - const BPoint *bp_orig_prev, *bp_orig_next; + for (; a < a_end; a++) { + bp = &nu->bp[a]; + if (bp->f1 & SELECT) { + const BPoint *bp_orig_prev, *bp_orig_next; - bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)]; - bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)]; + bp_orig_prev = &bp_orig[mod_i(a - 1, nu->pntsu)]; + bp_orig_next = &bp_orig[mod_i(a + 1, nu->pntsu)]; - smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor); + smooth_single_bp(bp, bp_orig_prev, bp_orig_next, factor); + } } + MEM_freeN((void *)bp_orig); } - MEM_freeN((void *)bp_orig); } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3023,13 +3050,22 @@ static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, cons static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); - curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight)); + curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight)); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3051,13 +3087,22 @@ void CURVE_OT_smooth_weight(wmOperatorType *ot) static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + + curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius)); - curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius)); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3079,13 +3124,22 @@ void CURVE_OT_smooth_radius(wmOperatorType *ot) static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb = object_editcurve_get(obedit); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); - curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt)); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); + + curve_smooth_value(editnurb, offsetof(BezTriple, tilt), offsetof(BPoint, tilt)); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -3909,54 +3963,63 @@ static void findselectedNurbvert( static int set_spline_type_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Object *obedit = CTX_data_edit_object(C); - View3D *v3d = CTX_wm_view3d(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; - bool changed = false; - bool changed_size = false; - const bool use_handles = RNA_boolean_get(op->ptr, "use_handles"); - const int type = RNA_enum_get(op->ptr, "type"); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + int ret_value = OPERATOR_CANCELLED; - if (type == CU_CARDINAL || type == CU_BSPLINE) { - BKE_report(op->reports, RPT_ERROR, "Not yet implemented"); - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + Main *bmain = CTX_data_main(C); + View3D *v3d = CTX_wm_view3d(C); + ListBase *editnurb = object_editcurve_get(obedit); + Nurb *nu; + bool changed = false; + bool changed_size = false; + const bool use_handles = RNA_boolean_get(op->ptr, "use_handles"); + const int type = RNA_enum_get(op->ptr, "type"); - for (nu = editnurb->first; nu; nu = nu->next) { - if (ED_curve_nurb_select_check(v3d, nu)) { - const int pntsu_prev = nu->pntsu; - if (BKE_nurb_type_convert(nu, type, use_handles)) { - changed = true; - if (pntsu_prev != nu->pntsu) { - changed_size = true; + if (type == CU_CARDINAL || type == CU_BSPLINE) { + BKE_report(op->reports, RPT_ERROR, "Not yet implemented"); + continue; + } + + for (nu = editnurb->first; nu; nu = nu->next) { + if (ED_curve_nurb_select_check(v3d, nu)) { + const int pntsu_prev = nu->pntsu; + if (BKE_nurb_type_convert(nu, type, use_handles)) { + changed = true; + if (pntsu_prev != nu->pntsu) { + changed_size = true; + } + } + else { + BKE_report(op->reports, RPT_ERROR, "No conversion possible"); } - } - else { - BKE_report(op->reports, RPT_ERROR, "No conversion possible"); } } - } - if (changed) { - if (ED_curve_updateAnimPaths(bmain, obedit->data)) { - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - } + if (changed) { + if (ED_curve_updateAnimPaths(bmain, obedit->data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + } - DEG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - if (changed_size) { - Curve *cu = obedit->data; - cu->actvert = CU_ACT_NONE; - } + if (changed_size) { + Curve *cu = obedit->data; + cu->actvert = CU_ACT_NONE; + } - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; + ret_value = OPERATOR_FINISHED; + } } + + MEM_freeN(objects); + + return ret_value; } void CURVE_OT_spline_type_set(wmOperatorType *ot) @@ -5551,6 +5614,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + DEG_id_tag_update(obedit->data, 0); return OPERATOR_FINISHED; @@ -6745,31 +6810,41 @@ void CURVE_OT_decimate(wmOperatorType *ot) static int shade_smooth_exec(bContext *C, wmOperator *op) { - Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); - ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu; + ViewLayer *view_layer = CTX_data_view_layer(C); int clear = (STREQ(op->idname, "CURVE_OT_shade_flat")); + uint objects_len; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + int ret_value = OPERATOR_CANCELLED; - if (obedit->type != OB_CURVE) { - return OPERATOR_CANCELLED; - } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + ListBase *editnurb = object_editcurve_get(obedit); - for (nu = editnurb->first; nu; nu = nu->next) { - if (ED_curve_nurb_select_check(v3d, nu)) { - if (!clear) { - nu->flag |= CU_SMOOTH; - } - else { - nu->flag &= ~CU_SMOOTH; + if (obedit->type != OB_CURVE) { + continue; + } + + for (Nurb *nu = editnurb->first; nu; nu = nu->next) { + if (ED_curve_nurb_select_check(v3d, nu)) { + if (!clear) { + nu->flag |= CU_SMOOTH; + } + else { + nu->flag &= ~CU_SMOOTH; + } } } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DEG_id_tag_update(obedit->data, 0); + ret_value = OPERATOR_FINISHED; } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DEG_id_tag_update(obedit->data, 0); + MEM_freeN(objects); - return OPERATOR_FINISHED; + return ret_value; } void CURVE_OT_shade_smooth(wmOperatorType *ot) @@ -7024,7 +7099,7 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) int a; if (object->runtime.curve_cache == NULL) { - BKE_displist_make_curveTypes(depsgraph, scene, object, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, object, false, false); } INIT_MINMAX(min, max); diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index d1b1f43d8dd..ffbfb692ca9 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -2007,7 +2007,7 @@ static int font_open_exec(bContext *C, wmOperator *op) id_us_min(&font->id); RNA_id_pointer_create(&font->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } @@ -2090,7 +2090,7 @@ static int font_unlink_exec(bContext *C, wmOperator *op) builtin_font = BKE_vfont_builtin_get(); RNA_id_pointer_create(&builtin_font->id, &idptr); - RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr); + RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr, NULL); RNA_property_update(C, &pprop.ptr, pprop.prop); return OPERATOR_FINISHED; diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 316ad3f91d6..d2d0095bdb2 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -569,9 +569,9 @@ set(ICON_NAMES loop_forwards back forward + file_cache file_volume - alembic - volume + file_3d file_hidden file_backup disk_drive diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 463c2144276..9ef0657ae83 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -314,7 +314,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { BKE_brush_gpencil_presets(C); } BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint); diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 96f405fab2f..bf15b846bb6 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -401,7 +401,8 @@ static bool gp_render_offscreen(tGPDfill *tgpf) glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL); + ED_view3d_update_viewmat( + tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL, true); /* set for opengl */ GPU_matrix_projection_set(tgpf->rv3d->winmat); GPU_matrix_set(tgpf->rv3d->viewmat); diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 9d3c2a6e271..93d8555e014 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -110,7 +110,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index b1b29356060..cd1ebc91fbb 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1819,7 +1819,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) Paint *paint = &ts->gp_paint->paint; bool changed = false; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); changed = true; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 08fee2bb393..bff17bf5078 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -314,7 +314,7 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) /* if brush doesn't exist, create a new one */ Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 129bd01574c..93a80f0fcf8 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1387,7 +1387,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob) BKE_paint_ensure(ts, (Paint **)&ts->gp_paint); Paint *paint = &ts->gp_paint->paint; /* if not exist, create a new one */ - if (paint->brush == NULL) { + if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) { /* create new brushes */ BKE_brush_gpencil_presets(C); } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index d947322f708..cd68981dee3 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -403,11 +403,14 @@ typedef enum eAnimFilter_Flags { /* -------------- Channel Defines -------------- */ /* channel heights */ -#define ACHANNEL_FIRST(ac) (-0.8f * (ac)->yscale_fac * U.widget_unit) +#define ACHANNEL_FIRST_TOP(ac) \ + (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - ACHANNEL_SKIP) #define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit) -#define ACHANNEL_HEIGHT_HALF(ac) (0.4f * (ac)->yscale_fac * U.widget_unit) #define ACHANNEL_SKIP (0.1f * U.widget_unit) #define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP) +/* Additional offset to give some room at the end. */ +#define ACHANNEL_TOT_HEIGHT(ac, item_amount) \ + (-ACHANNEL_FIRST_TOP(ac) + ACHANNEL_STEP(ac) * (item_amount + 1)) /* channel widths */ #define ACHANNEL_NAMEWIDTH (10 * U.widget_unit) @@ -418,13 +421,15 @@ typedef enum eAnimFilter_Flags { /* -------------- NLA Channel Defines -------------- */ /* NLA channel heights */ -#define NLACHANNEL_FIRST (-0.8f * U.widget_unit) +#define NLACHANNEL_FIRST_TOP(ac) \ + (UI_view2d_scale_get_y(&(ac)->ar->v2d) * -UI_SCRUBBING_MARGIN_Y - NLACHANNEL_SKIP) #define NLACHANNEL_HEIGHT(snla) \ ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit)) -#define NLACHANNEL_HEIGHT_HALF(snla) \ - ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.4f * U.widget_unit) : (0.6f * U.widget_unit)) #define NLACHANNEL_SKIP (0.1f * U.widget_unit) #define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP) +/* Additional offset to give some room at the end. */ +#define NLACHANNEL_TOT_HEIGHT(ac, item_amount) \ + (-NLACHANNEL_FIRST_TOP(ac) + NLACHANNEL_STEP(((SpaceNla *)(ac)->sl)) * (item_amount + 1)) /* channel widths */ #define NLACHANNEL_NAMEWIDTH (10 * U.widget_unit) diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 5bd806b3dbf..a09e1d579fd 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -28,6 +28,7 @@ struct ARegion; struct ImBuf; struct Image; struct ImageUser; +struct ReportList; struct Scene; struct SpaceImage; struct ToolSettings; @@ -110,4 +111,8 @@ void ED_image_draw_info(struct Scene *scene, bool ED_space_image_show_cache(struct SpaceImage *sima); +bool ED_image_should_save_modified(const struct bContext *C); +int ED_image_save_all_modified_info(const struct bContext *C, struct ReportList *reports); +bool ED_image_save_all_modified(const struct bContext *C, struct ReportList *reports); + #endif /* __ED_IMAGE_H__ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index ce8521a1f6a..0a8304f3f8a 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -142,44 +142,55 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, void ED_mesh_undosys_type(struct UndoType *ut); /* editmesh_select.c */ +struct EDBMSelectID_Context; +struct EDBMSelectID_Context *EDBM_select_id_context_create(struct ViewContext *vc, + struct Base **bases, + const uint bases_len, + short select_mode); +void EDBM_select_id_context_destroy(struct EDBMSelectID_Context *sel_id_ctx); +struct BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ctx, + const uint sel_id, + uint *r_base_index); + +uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx, + int base_index, + char htype); + +uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx); + void EDBM_select_mirrored( struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail); void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag); -bool EDBM_backbuf_border_init( - struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax); -bool EDBM_backbuf_check(unsigned int index); -void EDBM_backbuf_free(void); - -bool EDBM_backbuf_border_mask_init(struct ViewContext *vc, - const int mcords[][2], - short tot, - short xmin, - short ymin, - short xmax, - short ymax); -bool EDBM_backbuf_circle_init(struct ViewContext *vc, short xs, short ys, short rads); - struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc, float *r_dist, const bool use_select_bias, - bool use_cycle); + bool use_cycle, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist); struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - struct BMEdge **r_eed_zbuf); + bool use_cycle, + struct BMEdge **r_eed_zbuf, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist); struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - struct BMFace **r_efa_zbuf); + bool use_cycle, + struct BMFace **r_efa_zbuf, + struct Base **bases, + uint bases_len, + uint *r_base_index); struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist); bool EDBM_unified_findnearest(struct ViewContext *vc, @@ -230,8 +241,6 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len); bool EDBM_mesh_deselect_all_multi(struct bContext *C); -extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; - /* editmesh_preselect_edgering.c */ struct EditMesh_PreSelEdgeRing; struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void); @@ -271,7 +280,6 @@ bool paintface_mouse_select(struct bContext *C, bool extend, bool deselect, bool toggle); -bool do_paintface_box_select(struct ViewContext *vc, const struct rcti *rect, int sel_op); bool paintface_deselect_all_visible(struct bContext *C, struct Object *ob, int action, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 543b2a5781f..a7a95a4a659 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -87,9 +87,12 @@ void ED_region_panels_ex(const struct bContext *C, void ED_region_panels(const struct bContext *C, struct ARegion *ar); void ED_region_panels_layout_ex(const struct bContext *C, struct ARegion *ar, + struct ListBase *paneltypes, const char *contexts[], int contextnr, - const bool vertical); + const bool vertical, + const char *category_override); + void ED_region_panels_layout(const struct bContext *C, struct ARegion *ar); void ED_region_panels_draw(const struct bContext *C, struct ARegion *ar); @@ -142,6 +145,13 @@ void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C, struct ScrArea *sa, struct ARegion *ar, struct wmMsgBus *mbus); +void ED_area_do_mgs_subscribe_for_tool_ui(const struct bContext *C, + struct WorkSpace *workspace, + struct Scene *scene, + struct bScreen *screen, + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus); /* message bus */ void ED_region_message_subscribe(struct bContext *C, @@ -433,8 +443,9 @@ enum { ED_KEYMAP_ANIMATION = (1 << 6), ED_KEYMAP_FRAMES = (1 << 7), ED_KEYMAP_HEADER = (1 << 8), - ED_KEYMAP_GPENCIL = (1 << 9), - ED_KEYMAP_FOOTER = (1 << 10), + ED_KEYMAP_FOOTER = (1 << 9), + ED_KEYMAP_GPENCIL = (1 << 10), + ED_KEYMAP_NAVBAR = (1 << 11), }; /* SCREEN_OT_space_context_cycle direction */ diff --git a/source/blender/editors/include/ED_select_buffer_utils.h b/source/blender/editors/include/ED_select_buffer_utils.h new file mode 100644 index 00000000000..af745cee676 --- /dev/null +++ b/source/blender/editors/include/ED_select_buffer_utils.h @@ -0,0 +1,43 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup editors + */ + +#ifndef __ED_SELECT_BUFFER_UTILS_H__ +#define __ED_SELECT_BUFFER_UTILS_H__ + +struct rcti; + +/* Boolean array from selection ID's. */ +uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const struct rcti *rect); +uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len, + const int center[2], + const int radius); +uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len, + const int poly[][2], + const int poly_len, + const rcti *rect); + +/* Single result from selection ID's. */ +uint ED_select_buffer_sample_point(const int center[2]); +uint ED_select_buffer_find_nearest_to_point(const int center[2], + const uint id_min, + const uint id_max, + uint *dist); + +#endif /* __ED_SELECT_BUFFER_UTILS_H__ */ diff --git a/source/blender/editors/include/ED_time_scrub_ui.h b/source/blender/editors/include/ED_time_scrub_ui.h new file mode 100644 index 00000000000..a2e3098e949 --- /dev/null +++ b/source/blender/editors/include/ED_time_scrub_ui.h @@ -0,0 +1,43 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup editors + */ + +#ifndef __ED_SCRUBBING_H__ +#define __ED_SCRUBBING_H__ + +struct View2DGrid; +struct bContext; +struct bDopeSheet; +struct wmEvent; + +void ED_scrubbing_draw(const struct ARegion *ar, + const struct Scene *scene, + bool display_seconds, + bool discrete_frames); + +bool ED_event_in_scrubbing_region(const struct ARegion *ar, const struct wmEvent *event); + +void ED_channel_search_draw(const struct bContext *C, + struct ARegion *ar, + struct bDopeSheet *dopesheet); + +#endif /* __ED_SCRUBBING_H__ */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index fd51419a3ee..5ce9133a531 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -42,6 +42,7 @@ struct GPUFX; struct GPUFXSettings; struct GPUOffScreen; struct GPUViewport; +struct ID; struct ImBuf; struct MVert; struct Main; @@ -108,8 +109,6 @@ enum eV3DCursorOrient { void ED_view3d_background_color_get(const struct Scene *scene, const struct View3D *v3d, float r_color[3]); -void ED_view3d_cursor3d_calc_mat3(const struct Scene *scene, float mat[3][3]); -void ED_view3d_cursor3d_calc_mat4(const struct Scene *scene, float mat[4][4]); void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], const bool use_depth, @@ -451,16 +450,9 @@ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist); void ED_view3d_select_id_validate(struct ViewContext *vc); -void ED_view3d_select_id_validate_with_select_mode(struct ViewContext *vc, short select_mode); -uint ED_view3d_select_id_sample(struct ViewContext *vc, int x, int y); -uint *ED_view3d_select_id_read( - struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax, uint *r_buf_len); -uint *ED_view3d_select_id_read_rect(struct ViewContext *vc, - const struct rcti *rect, - uint *r_buf_len); -uint ED_view3d_select_id_read_nearest( - struct ViewContext *vc, const int mval[2], const uint min, const uint max, uint *r_dist); +uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len); +uint *ED_view3d_select_id_read_rect(const struct rcti *rect, uint *r_buf_len); bool ED_view3d_autodist(struct Depsgraph *depsgraph, struct ARegion *ar, @@ -572,7 +564,6 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph, bool do_sky, bool is_persp, const char *viewname, - struct GPUFXSettings *fx_settings, const bool do_color_managment, struct GPUOffScreen *ofs, struct GPUViewport *viewport); @@ -593,7 +584,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, int sizex, int sizey, unsigned int flag, - unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, @@ -624,7 +614,8 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph, struct ARegion *ar, float viewmat[4][4], float winmat[4][4], - const struct rcti *rect); + const struct rcti *rect, + bool offscreen); bool ED_view3d_quat_from_axis_view(const char view, float quat[4]); char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon); char ED_view3d_lock_view_from_index(int index); @@ -730,4 +721,9 @@ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C, struct Base **r_base, struct BMElem **r_ele); +/* space_view3d.c */ +void ED_view3d_buttons_region_layout_ex(const struct bContext *C, + struct ARegion *ar, + const char *category_override); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 2f624007c98..048f30bdf26 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -24,6 +24,9 @@ /* Note: this is included multiple times with different #defines for DEF_ICON. */ /* Auto define more specific types for places that do not need the distinction. */ +#ifndef DEF_ICON_SCENE +# define DEF_ICON_SCENE DEF_ICON +#endif #ifndef DEF_ICON_COLLECTION # define DEF_ICON_COLLECTION DEF_ICON #endif @@ -66,7 +69,7 @@ DEF_ICON(COLLAPSEMENU) DEF_ICON(X) DEF_ICON(DUPLICATE) DEF_ICON(TRASH) -DEF_ICON_BLANK(76) +DEF_ICON(COLLECTION_NEW) DEF_ICON_BLANK(77) DEF_ICON(NODE) DEF_ICON(NODE_SEL) @@ -93,8 +96,8 @@ DEF_ICON(PINNED) DEF_ICON(SCREEN_BACK) DEF_ICON(RIGHTARROW) DEF_ICON(DOWNARROW_HLT) -DEF_ICON_BLANK(103) -DEF_ICON_BLANK(104) +DEF_ICON(FCURVE_SNAPSHOT) +DEF_ICON(OBJECT_HIDDEN) DEF_ICON_BLANK(105) DEF_ICON_BLANK(106) DEF_ICON(PLUGIN) @@ -133,18 +136,18 @@ DEF_ICON_SHADING(MATERIAL) DEF_ICON_SHADING(TEXTURE) DEF_ICON(ANIM) DEF_ICON_SHADING(WORLD) -DEF_ICON(SCENE) -DEF_ICON(OUTPUT) +DEF_ICON_SCENE(SCENE) +DEF_ICON_SCENE(OUTPUT) DEF_ICON_BLANK(145) DEF_ICON_BLANK(146) DEF_ICON(SCRIPT) DEF_ICON_MODIFIER(PARTICLES) -DEF_ICON(PHYSICS) -DEF_ICON(SPEAKER) +DEF_ICON_MODIFIER(PHYSICS) +DEF_ICON_OBJECT_DATA(SPEAKER) DEF_ICON_BLANK(151) -DEF_ICON(TOOL_SETTINGS) -DEF_ICON(SHADERFX) -DEF_ICON(MODIFIER) +DEF_ICON_SCENE(TOOL_SETTINGS) +DEF_ICON_MODIFIER(SHADERFX) +DEF_ICON_MODIFIER(MODIFIER) DEF_ICON_BLANK(155) DEF_ICON_BLANK(156) DEF_ICON_BLANK(157) @@ -163,7 +166,7 @@ DEF_ICON(FILEBROWSER) DEF_ICON(IMAGE) DEF_ICON(INFO) DEF_ICON(SEQUENCE) -DEF_ICON(TEXT) +DEF_ICON_OBJECT_DATA(TEXT) DEF_ICON_BLANK(174) DEF_ICON(SOUND) DEF_ICON(ACTION) @@ -211,27 +214,27 @@ DEF_ICON(TRACKING_REFINE_FORWARDS) DEF_ICON_BLANK(77b) /* DATA */ -DEF_ICON(SCENE_DATA) -DEF_ICON(RENDERLAYERS) +DEF_ICON_SCENE(SCENE_DATA) +DEF_ICON_SCENE(RENDERLAYERS) DEF_ICON_SHADING(WORLD_DATA) -DEF_ICON(OBJECT_DATA) -DEF_ICON(MESH_DATA) -DEF_ICON(CURVE_DATA) -DEF_ICON(META_DATA) -DEF_ICON(LATTICE_DATA) -DEF_ICON_SHADING(LIGHT_DATA) +DEF_ICON_OBJECT(OBJECT_DATA) +DEF_ICON_OBJECT_DATA(MESH_DATA) +DEF_ICON_OBJECT_DATA(CURVE_DATA) +DEF_ICON_OBJECT_DATA(META_DATA) +DEF_ICON_OBJECT_DATA(LATTICE_DATA) +DEF_ICON_OBJECT_DATA(LIGHT_DATA) DEF_ICON_SHADING(MATERIAL_DATA) DEF_ICON_SHADING(TEXTURE_DATA) DEF_ICON(ANIM_DATA) -DEF_ICON(CAMERA_DATA) -DEF_ICON(PARTICLE_DATA) +DEF_ICON_OBJECT_DATA(CAMERA_DATA) +DEF_ICON_OBJECT_DATA(PARTICLE_DATA) DEF_ICON(LIBRARY_DATA_DIRECT) DEF_ICON_COLLECTION(GROUP) -DEF_ICON(ARMATURE_DATA) +DEF_ICON_OBJECT_DATA(ARMATURE_DATA) DEF_ICON(COMMUNITY) -DEF_ICON(BONE_DATA) +DEF_ICON_OBJECT_DATA(BONE_DATA) DEF_ICON_MODIFIER(CONSTRAINT) -DEF_ICON(SHAPEKEY_DATA) +DEF_ICON_OBJECT_DATA(SHAPEKEY_DATA) DEF_ICON_MODIFIER(CONSTRAINT_BONE) DEF_ICON(CAMERA_STEREO) DEF_ICON(PACKAGE) @@ -243,10 +246,10 @@ DEF_ICON_SHADING(BRUSH_DATA) DEF_ICON_SHADING(IMAGE_DATA) DEF_ICON(FILE) DEF_ICON(FCURVE) -DEF_ICON(FONT_DATA) -DEF_ICON(RENDER_RESULT) -DEF_ICON(SURFACE_DATA) -DEF_ICON(EMPTY_DATA) +DEF_ICON_OBJECT_DATA(FONT_DATA) +DEF_ICON_SCENE(RENDER_RESULT) +DEF_ICON_OBJECT_DATA(SURFACE_DATA) +DEF_ICON_OBJECT_DATA(EMPTY_DATA) DEF_ICON(PRESET) DEF_ICON(RENDER_ANIMATION) DEF_ICON(RENDER_STILL) @@ -254,7 +257,7 @@ DEF_ICON(LIBRARY_DATA_BROKEN) DEF_ICON(BOIDS) DEF_ICON(STRANDS) DEF_ICON(LIBRARY_DATA_INDIRECT) -DEF_ICON(GREASEPENCIL) +DEF_ICON_OBJECT_DATA(GREASEPENCIL) DEF_ICON_SHADING(LINE_DATA) DEF_ICON(LIBRARY_DATA_OVERRIDE) DEF_ICON(GROUP_BONE) @@ -320,7 +323,7 @@ DEF_ICON(RESTRICT_SELECT_ON) DEF_ICON(RESTRICT_SELECT_OFF) DEF_ICON(RESTRICT_RENDER_ON) DEF_ICON(RESTRICT_RENDER_OFF) -DEF_ICON_BLANK(330) +DEF_ICON(RESTRICT_INSTANCED_OFF) /* OUTLINER */ DEF_ICON_OBJECT_DATA(OUTLINER_DATA_EMPTY) @@ -334,7 +337,7 @@ DEF_ICON_OBJECT_DATA(OUTLINER_DATA_ARMATURE) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_FONT) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SURFACE) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SPEAKER) -DEF_ICON_BLANK(344) +DEF_ICON_OBJECT_DATA(OUTLINER_DATA_LIGHTPROBE) DEF_ICON_BLANK(345) DEF_ICON_OBJECT_DATA(OUTLINER_DATA_GREASEPENCIL) DEF_ICON(GP_SELECT_POINTS) @@ -348,7 +351,7 @@ DEF_ICON(ONIONSKIN_OFF) DEF_ICON(ONIONSKIN_ON) DEF_ICON(RESTRICT_VIEW_ON) DEF_ICON(RESTRICT_VIEW_OFF) -DEF_ICON_BLANK(353) +DEF_ICON(RESTRICT_INSTANCED_ON) /* PRIMITIVES */ DEF_ICON(MESH_PLANE) @@ -363,11 +366,11 @@ DEF_ICON(MESH_TORUS) DEF_ICON(MESH_CONE) DEF_ICON(MESH_CAPSULE) DEF_ICON(EMPTY_SINGLE_ARROW) -DEF_ICON_SHADING(LIGHT_POINT) -DEF_ICON_SHADING(LIGHT_SUN) -DEF_ICON_SHADING(LIGHT_SPOT) -DEF_ICON_SHADING(LIGHT_HEMI) -DEF_ICON_SHADING(LIGHT_AREA) +DEF_ICON_OBJECT_DATA(LIGHT_POINT) +DEF_ICON_OBJECT_DATA(LIGHT_SUN) +DEF_ICON_OBJECT_DATA(LIGHT_SPOT) +DEF_ICON_OBJECT_DATA(LIGHT_HEMI) +DEF_ICON_OBJECT_DATA(LIGHT_AREA) DEF_ICON(CUBE) DEF_ICON(SPHERE) DEF_ICON(CONE) @@ -393,9 +396,9 @@ DEF_ICON(CURVE_BEZCIRCLE) DEF_ICON(CURVE_NCURVE) DEF_ICON(CURVE_NCIRCLE) DEF_ICON(CURVE_PATH) -DEF_ICON_SHADING(LIGHTPROBE_CUBEMAP) -DEF_ICON_SHADING(LIGHTPROBE_PLANAR) -DEF_ICON_SHADING(LIGHTPROBE_GRID) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_CUBEMAP) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_PLANAR) +DEF_ICON_OBJECT_DATA(LIGHTPROBE_GRID) DEF_ICON_BLANK(406) DEF_ICON_BLANK(407) DEF_ICON(COLOR_RED) @@ -422,8 +425,8 @@ DEF_ICON(FORCE_DRAG) DEF_ICON(FORCE_SMOKEFLOW) DEF_ICON_BLANK(673) DEF_ICON_BLANK(674) -DEF_ICON_BLANK(675) -DEF_ICON_BLANK(676) +DEF_ICON(RIGID_BODY) +DEF_ICON(RIGID_BODY_CONSTRAINT) DEF_ICON_BLANK(677) DEF_ICON_BLANK(678) DEF_ICON_BLANK(679) @@ -456,11 +459,11 @@ DEF_ICON_BLANK(707) DEF_ICON_BLANK(708) DEF_ICON_BLANK(709) DEF_ICON_BLANK(710) -DEF_ICON_BLANK(711) -DEF_ICON_BLANK(712) -DEF_ICON_BLANK(713) -DEF_ICON_BLANK(714) -DEF_ICON_BLANK(715) +DEF_ICON(SELECT_SET) +DEF_ICON(SELECT_EXTEND) +DEF_ICON(SELECT_SUBTRACT) +DEF_ICON(SELECT_INTERSECT) +DEF_ICON(SELECT_DIFFERENCE) /* EMPTY */ DEF_ICON(ALIGN_LEFT) @@ -485,10 +488,10 @@ DEF_ICON_BLANK(748) DEF_ICON_BLANK(749) DEF_ICON_BLANK(750) DEF_ICON_BLANK(751) -DEF_ICON_BLANK(752) -DEF_ICON_BLANK(753) -DEF_ICON_BLANK(754) -DEF_ICON_BLANK(755) +DEF_ICON(HOLDOUT_OFF) +DEF_ICON(HOLDOUT_ON) +DEF_ICON(INDIRECT_ONLY_OFF) +DEF_ICON(INDIRECT_ONLY_ON) /* EMPTY */ DEF_ICON_BLANK(501) @@ -635,7 +638,7 @@ DEF_ICON(VERTEXSEL) DEF_ICON(EDGESEL) DEF_ICON(FACESEL) DEF_ICON_BLANK(209) -DEF_ICON_BLANK(210) +DEF_ICON(CURSOR) DEF_ICON(PIVOT_BOUNDBOX) DEF_ICON(PIVOT_CURSOR) DEF_ICON(PIVOT_INDIVIDUAL) @@ -696,8 +699,8 @@ DEF_ICON(VIS_SEL_10) DEF_ICON(VIS_SEL_01) DEF_ICON(VIS_SEL_00) DEF_ICON_BLANK(231) -DEF_ICON(AUTOMERGE_ON) DEF_ICON(AUTOMERGE_OFF) +DEF_ICON(AUTOMERGE_ON) DEF_ICON_BLANK(234) DEF_ICON(UV_VERTEXSEL) DEF_ICON(UV_EDGESEL) @@ -708,7 +711,7 @@ DEF_ICON_BLANK(240) DEF_ICON_BLANK(241) DEF_ICON_BLANK(242) DEF_ICON_BLANK(243) -DEF_ICON_BLANK(244) +DEF_ICON(GIZMO) DEF_ICON(ORIENTATION_CURSOR) DEF_ICON(NORMALS_VERTEX) DEF_ICON(NORMALS_FACE) @@ -818,9 +821,9 @@ DEF_ICON(FORWARD) DEF_ICON_BLANK(825) DEF_ICON_BLANK(826) DEF_ICON_BLANK(827) +DEF_ICON(FILE_CACHE) DEF_ICON(FILE_VOLUME) -DEF_ICON(ALEMBIC) -DEF_ICON(VOLUME) +DEF_ICON(FILE_3D) DEF_ICON(FILE_HIDDEN) DEF_ICON(FILE_BACKUP) DEF_ICON(DISK_DRIVE) @@ -1022,6 +1025,7 @@ DEF_ICON_COLOR(EVENT_RETURN) #undef DEF_ICON #undef DEF_ICON_ERROR +#undef DEF_ICON_SCENE #undef DEF_ICON_COLLECTION #undef DEF_ICON_OBJECT #undef DEF_ICON_OBJECT_DATA diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 18960853011..fddd8f09b87 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -228,6 +228,7 @@ enum { #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 +#define UI_SIDEBAR_PANEL_WIDTH 220 #define UI_NAVIGATION_REGION_WIDTH UI_COMPACT_PANEL_WIDTH #define UI_NARROW_NAVIGATION_REGION_WIDTH 100 @@ -280,6 +281,9 @@ enum { /** Value is animated, but the current value differs from the animated one. */ UI_BUT_ANIMATED_CHANGED = 1 << 25, + + /* Draw the checkbox buttons inverted. */ + UI_BUT_CHECKBOX_INVERT = 1 << 26, }; /* scale fixed button widths by this to account for DPI */ @@ -594,9 +598,16 @@ struct uiLayout *UI_pie_menu_layout(struct uiPieMenu *pie); typedef uiBlock *(*uiBlockCreateFunc)(struct bContext *C, struct ARegion *ar, void *arg1); typedef void (*uiBlockCancelFunc)(struct bContext *C, void *arg1); -void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg); -void UI_popup_block_invoke_ex( - struct bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext); +void UI_popup_block_invoke(struct bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg)); +void UI_popup_block_invoke_ex(struct bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg), + const char *opname, + int opcontext); void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, @@ -641,6 +652,7 @@ enum { UI_BLOCK_THEME_STYLE_POPUP = 1, }; void UI_block_theme_style_set(uiBlock *block, char theme_style); +char UI_block_emboss_get(uiBlock *block); void UI_block_emboss_set(uiBlock *block, char dt); void UI_block_free(const struct bContext *C, uiBlock *block); @@ -1618,7 +1630,7 @@ struct Panel *UI_panel_begin(struct ScrArea *sa, struct PanelType *pt, struct Panel *pa, bool *r_open); -void UI_panel_end(uiBlock *block, int width, int height); +void UI_panel_end(uiBlock *block, int width, int height, bool open); void UI_panels_scale(struct ARegion *ar, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *pa); @@ -1629,6 +1641,7 @@ struct PanelCategoryDyn *UI_panel_category_find(struct ARegion *ar, const char * struct PanelCategoryStack *UI_panel_category_active_find(struct ARegion *ar, const char *idname); const char *UI_panel_category_active_get(struct ARegion *ar, bool set_fallback); void UI_panel_category_active_set(struct ARegion *ar, const char *idname); +void UI_panel_category_active_set_default(struct ARegion *ar, const char *idname); struct PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(struct ARegion *ar, const int x, const int y); @@ -1702,14 +1715,28 @@ enum { UI_ITEM_O_RETURN_PROPS = 1 << 0, UI_ITEM_R_EXPAND = 1 << 1, UI_ITEM_R_SLIDER = 1 << 2, + /** + * Use for booleans, causes the button to draw with an outline (emboss), + * instead of text with a checkbox. + * This is implied when toggle buttons have an icon + * unless #UI_ITEM_R_ICON_NEVER flag is set. + */ UI_ITEM_R_TOGGLE = 1 << 3, - UI_ITEM_R_ICON_ONLY = 1 << 4, - UI_ITEM_R_EVENT = 1 << 5, - UI_ITEM_R_FULL_EVENT = 1 << 6, - UI_ITEM_R_NO_BG = 1 << 7, - UI_ITEM_R_IMMEDIATE = 1 << 8, - UI_ITEM_O_DEPRESS = 1 << 9, - UI_ITEM_R_COMPACT = 1 << 10, + /** + * Don't attempt to use an icon when the icon is set to #ICON_NONE. + * + * Use for boolean's, causes the buttons to always show as a checkbox + * even when there is an icon (which would normally show the button as a toggle). + */ + UI_ITEM_R_ICON_NEVER = 1 << 4, + UI_ITEM_R_ICON_ONLY = 1 << 5, + UI_ITEM_R_EVENT = 1 << 6, + UI_ITEM_R_FULL_EVENT = 1 << 7, + UI_ITEM_R_NO_BG = 1 << 8, + UI_ITEM_R_IMMEDIATE = 1 << 9, + UI_ITEM_O_DEPRESS = 1 << 10, + UI_ITEM_R_COMPACT = 1 << 11, + UI_ITEM_R_CHECKBOX_INVERT = 1 << 12, }; #define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X) diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 5666421c27f..1f15fa3bd4d 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -52,8 +52,11 @@ typedef struct IconFile { * Resizable Icons for Blender */ void UI_icons_init(void); +void UI_icons_reload_internal_textures(void); + int UI_icon_get_width(int icon_id); int UI_icon_get_height(int icon_id); +bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]); void UI_id_icon_render(const struct bContext *C, struct Scene *scene, @@ -64,16 +67,17 @@ int UI_preview_render_size(enum eIconSizes size); void UI_icon_draw(float x, float y, int icon_id); void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha); -void UI_icon_draw_preview(float x, float y, int icon_id); -void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect); -void UI_icon_draw_preview_aspect_size( - float x, float y, int icon_id, float aspect, float alpha, int size); - -void UI_icon_draw_aspect( - float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4]); -void UI_icon_draw_aspect_color( - float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4]); -void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha); +void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size); + +void UI_icon_draw_ex(float x, + float y, + int icon_id, + float aspect, + float alpha, + float desaturate, + const char mono_color[4], + const bool mono_border); + void UI_icon_draw_desaturate(float x, float y, int icon_id, @@ -81,6 +85,7 @@ void UI_icon_draw_desaturate(float x, float alpha, float desaturate, const char mono_color[4]); + void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index af94889a1bb..6dc632921ad 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -105,6 +105,7 @@ typedef enum ThemeColorID { TH_FACE_DOT, TH_FACEDOT_SIZE, TH_CFRAME, + TH_SCRUBBING_BACKGROUND, TH_TIME_KEYFRAME, TH_TIME_GP_KEYFRAME, TH_NURB_ULINE, @@ -254,6 +255,10 @@ typedef enum ThemeColorID { TH_MATCH, /* highlight color for search matches */ TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */ + TH_SELECTED_OBJECT, /* selected object color for outliner */ + TH_ACTIVE_OBJECT, /* active object color for outliner */ + TH_EDITED_OBJECT, /* edited object color for outliner */ + TH_ROW_ALTERNATE, /* overlay on every other row */ TH_SKIN_ROOT, @@ -261,12 +266,15 @@ typedef enum ThemeColorID { TH_ANIM_INACTIVE, /* no active action */ TH_ANIM_PREVIEW_RANGE, /* preview range overlay */ + TH_ICON_SCENE, TH_ICON_COLLECTION, TH_ICON_OBJECT, TH_ICON_OBJECT_DATA, TH_ICON_MODIFIER, TH_ICON_SHADING, + TH_SCROLL_TEXT, + TH_NLA_TWEAK, /* 'tweaking' track in NLA */ TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */ @@ -380,7 +388,7 @@ void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3]); void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4]); // get theme color for coloring monochrome icons -bool UI_GetIconThemeColor4fv(int colorid, float col[4]); +bool UI_GetIconThemeColor4ubv(int colorid, unsigned char col[4]); // shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor) void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 07dbb49ac07..d03d4b1b4f5 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -63,9 +63,9 @@ enum eView2D_CommonViewTypes { /* scroller area */ #define V2D_SCROLL_HEIGHT (0.45f * U.widget_unit) #define V2D_SCROLL_WIDTH (0.45f * U.widget_unit) -/* For scrollers with scale markings (text written onto them) */ -#define V2D_SCROLL_HEIGHT_TEXT (0.79f * U.widget_unit) -#define V2D_SCROLL_WIDTH_TEXT (0.79f * U.widget_unit) +/* For scrollers with scale handlers */ +#define V2D_SCROLL_HEIGHT_HANDLES (0.6f * U.widget_unit) +#define V2D_SCROLL_WIDTH_HANDLES (0.6f * U.widget_unit) /* scroller 'handles' hotspot radius for mouse */ #define V2D_SCROLLER_HANDLE_SIZE (0.6f * U.widget_unit) @@ -152,30 +152,24 @@ float UI_view2d_grid_resolution_y__values(const struct View2D *v2d); /* scale indicator text drawing */ void UI_view2d_draw_scale_y__values(const struct ARegion *ar, const struct View2D *v2d, - const struct rcti *rect); + const struct rcti *rect, + int colorid); void UI_view2d_draw_scale_y__block(const struct ARegion *ar, const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__values(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__discrete_values(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect); -void UI_view2d_draw_scale_x__discrete_time(const struct ARegion *ar, - const struct View2D *v2d, - const struct rcti *rect, - const struct Scene *scene); + const struct rcti *rect, + int colorid); void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds); + bool display_seconds, + int colorid); void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds); + bool display_seconds, + int colorid); /* scrollbar drawing */ View2DScrollers *UI_view2d_scrollers_calc(struct View2D *v2d, const struct rcti *mask_custom); @@ -183,16 +177,7 @@ void UI_view2d_scrollers_draw(struct View2D *v2d, View2DScrollers *scrollers); void UI_view2d_scrollers_free(View2DScrollers *scrollers); /* list view tools */ -void UI_view2d_listview_cell_to_view(struct View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int column, - int row, - struct rctf *rect); -void UI_view2d_listview_view_to_cell(struct View2D *v2d, - float columnwidth, +void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, @@ -200,15 +185,6 @@ void UI_view2d_listview_view_to_cell(struct View2D *v2d, float viewy, int *column, int *row); -void UI_view2d_listview_visible_cells(struct View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int *column_min, - int *column_max, - int *row_min, - int *row_max); /* coordinate conversion */ float UI_view2d_region_to_view_x(const struct View2D *v2d, float x); @@ -282,6 +258,8 @@ void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar, const struct rctf *cur, const int smooth_viewtx); + #define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC) +#define UI_SCRUBBING_MARGIN_Y (23 * UI_DPI_FAC) #endif /* __UI_VIEW2D_H__ */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 42f4b4495c3..931a4faa1c0 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1086,7 +1086,6 @@ static bool ui_but_event_operator_string_from_menu(const bContext *C, } IDP_FreeProperty(prop_menu); - MEM_freeN(prop_menu); return found; } @@ -1135,7 +1134,6 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C, } IDP_FreeProperty(prop_panel); - MEM_freeN(prop_panel); return found; } @@ -1356,7 +1354,6 @@ static bool ui_but_event_property_operator_string(const bContext *C, /* cleanup */ IDP_FreeProperty(prop_path); - MEM_freeN(prop_path); if (data_path) { MEM_freeN(data_path); } @@ -1687,6 +1684,18 @@ void UI_block_draw(const bContext *C, uiBlock *block) } else if (block->panel) { bool show_background = ar->alignment != RGN_ALIGN_FLOAT; + if (show_background) { + if (block->panel->type && (block->panel->type->flag & PNL_NO_HEADER)) { + if (ar->regiontype == RGN_TYPE_TOOLS) { + /* We never want a background around active tools. */ + show_background = false; + } + else { + /* Without a header there is no background except for region overlap. */ + show_background = ar->overlap != 0; + } + } + } ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar), show_background); } @@ -1836,6 +1845,9 @@ int ui_but_is_pushed_ex(uiBut *but, double *value) } } + if ((but->drawflag & UI_BUT_CHECKBOX_INVERT) && (is_push != -1)) { + is_push = !((bool)is_push); + } return is_push; } int ui_but_is_pushed(uiBut *but) @@ -2763,7 +2775,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) } else if (type == PROP_POINTER) { if (str[0] == '\0') { - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL, NULL); return true; } else { @@ -2779,14 +2791,14 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) * Fact remains, using editstr as main 'reference' over whole search button thingy * is utterly weak and should be redesigned imho, but that's not a simple task. */ if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) { - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } else if (but->func_arg2 != NULL) { RNA_pointer_create(NULL, RNA_property_pointer_type(&but->rnapoin, but->rnaprop), but->func_arg2, &rptr); - RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); + RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } return true; @@ -3235,6 +3247,11 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh return block; } +char UI_block_emboss_get(uiBlock *block) +{ + return block->dt; +} + void UI_block_emboss_set(uiBlock *block, char dt) { block->dt = dt; @@ -3721,6 +3738,16 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag) } } +/** + * Avoid using this where possible since it's better not to ask for an icon in the first place. + */ +void ui_def_but_icon_clear(uiBut *but) +{ + but->icon = ICON_NONE; + but->flag &= ~UI_HAS_ICON; + but->drawflag &= ~UI_BUT_ICON_LEFT; +} + static void ui_def_but_rna__disable(uiBut *but, const char *info) { but->flag |= UI_BUT_DISABLED; diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index b9de504f3b2..4a0a19f57cf 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -82,6 +82,11 @@ void ui_but_anim_flag(uiBut *but, float cfra) if (fcu) { if (!driven) { + /* Empty curves are ignored by the animation evaluation system. */ + if (BKE_fcurve_is_empty(fcu)) { + return; + } + but->flag |= UI_BUT_ANIMATED; /* T41525 - When the active action is a NLA strip being edited, diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 748d6e6c183..d1f72519046 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -58,30 +58,89 @@ /** \name Button Context Menu * \{ */ -static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) +static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) { - uiBut *but = (uiBut *)arg1; + /* Compute data path from context to property. */ + const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); + const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); + const char *member_id_data_path = member_id; + + if (data_path) { + member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path); + MEM_freeN((void *)data_path); + } - if (but->optype) { - char shortcut_str[128]; + const char *prop_id = RNA_property_identifier(but->rnaprop); + const char *final_data_path = BLI_sprintfN("%s.%s", member_id_data_path, prop_id); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + if (member_id != member_id_data_path) { + MEM_freeN((void *)member_id_data_path); + } + + /* Create ID property of data path, to pass to the operator. */ + IDProperty *prop; + IDPropertyTemplate val = {0}; + prop = IDP_New(IDP_GROUP, &val, __func__); + IDP_AddToGroup(prop, IDP_NewString(final_data_path, "data_path", strlen(final_data_path) + 1)); + + MEM_freeN((void *)final_data_path); + + return prop; +} - /* complex code to change name of button */ - if (WM_key_event_operator_string(C, - but->optype->idname, - but->opcontext, - prop, - true, - shortcut_str, - sizeof(shortcut_str))) { - ui_but_add_shortcut(but, shortcut_str, true); +static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **prop) +{ + if (but->optype) { + /* Operator */ + *prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL; + return but->optype->idname; + } + else if (but->rnaprop) { + if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) { + /* Boolean */ + *prop = shortcut_property_from_rna(C, but); + return "WM_OT_context_toggle"; } - else { - /* simply strip the shortcut */ - ui_but_add_shortcut(but, NULL, true); + else if (RNA_property_type(but->rnaprop) == PROP_ENUM) { + /* Enum */ + *prop = shortcut_property_from_rna(C, but); + return "WM_OT_context_menu_enum"; } } + + *prop = NULL; + return NULL; +} + +static void shortcut_free_operator_property(IDProperty *prop) +{ + if (prop) { + IDP_FreeProperty(prop); + } +} + +static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) +{ + uiBut *but = (uiBut *)arg1; + char shortcut_str[128]; + + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + if (idname == NULL) { + return; + } + + /* complex code to change name of button */ + if (WM_key_event_operator_string( + C, idname, but->opcontext, prop, true, shortcut_str, sizeof(shortcut_str))) { + ui_but_add_shortcut(but, shortcut_str, true); + } + else { + /* simply strip the shortcut */ + ui_but_add_shortcut(but, NULL, true); + } + + shortcut_free_operator_property(prop); } static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) @@ -94,15 +153,18 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) PointerRNA ptr; uiLayout *layout; uiStyle *style = UI_style_get_dpi(); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); kmi = WM_key_event_operator(C, - but->optype->idname, + idname, but->opcontext, prop, EVT_TYPE_MASK_HOTKEY_INCLUDE, EVT_TYPE_MASK_HOTKEY_EXCLUDE, &km); + U.runtime.is_dirty = true; + BLI_assert(kmi != NULL); RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); @@ -118,6 +180,8 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) UI_block_bounds_set_popup(block, 6, (const int[2]){-50, 26}); + shortcut_free_operator_property(prop); + return block; } @@ -135,25 +199,24 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) PointerRNA ptr; uiLayout *layout; uiStyle *style = UI_style_get_dpi(); - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int kmi_id; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); /* XXX this guess_opname can potentially return a different keymap * than being found on adding later... */ - km = WM_keymap_guess_opname(C, but->optype->idname); - kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0); + km = WM_keymap_guess_opname(C, idname); + kmi = WM_keymap_add_item(km, idname, AKEY, KM_PRESS, 0, 0); kmi_id = kmi->id; - /* copy properties, prop can be NULL for reset */ - if (prop) { - prop = IDP_CopyProperty(prop); - } + /* This takes ownership of prop, or prop can be NULL for reset. */ WM_keymap_item_properties_reset(kmi, prop); /* update and get pointers again */ WM_keyconfig_update(wm); + U.runtime.is_dirty = true; - km = WM_keymap_guess_opname(C, but->optype->idname); + km = WM_keymap_guess_opname(C, idname); kmi = WM_keymap_item_find_id(km, kmi_id); RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); @@ -171,6 +234,7 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) #ifdef USE_KEYMAP_ADD_HACK g_kmi_id_hack = kmi_id; #endif + return block; } @@ -179,20 +243,21 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) uiBut *but = (uiBut *)arg1; wmKeyMap *km; wmKeyMapItem *kmi; -#ifndef USE_KEYMAP_ADD_HACK - IDProperty *prop; -#endif int kmi_id; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + #ifdef USE_KEYMAP_ADD_HACK - km = WM_keymap_guess_opname(C, but->optype->idname); + km = WM_keymap_guess_opname(C, idname); kmi_id = g_kmi_id_hack; UNUSED_VARS(but); #else - prop = (but->opptr) ? but->opptr->data : NULL; - kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); + kmi_id = WM_key_event_operator_id(C, idname, but->opcontext, prop, true, &km); #endif + shortcut_free_operator_property(prop); + kmi = WM_keymap_item_find_id(km, kmi_id); WM_keymap_remove_item(km, kmi); } @@ -200,7 +265,7 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1) static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) { uiBut *but = (uiBut *)arg1; - UI_popup_block_invoke(C, menu_change_shortcut, but); + UI_popup_block_invoke(C, menu_change_shortcut, but, NULL); } static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) @@ -208,10 +273,11 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) uiBut *but = (uiBut *)arg1; wmKeyMap *km; wmKeyMapItem *kmi; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); kmi = WM_key_event_operator(C, - but->optype->idname, + idname, but->opcontext, prop, EVT_TYPE_MASK_HOTKEY_INCLUDE, @@ -220,7 +286,9 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) BLI_assert(kmi != NULL); WM_keymap_remove_item(km, kmi); + U.runtime.is_dirty = true; + shortcut_free_operator_property(prop); but_shortcut_name_func(C, but, 0); } @@ -323,6 +391,7 @@ static void popup_user_menu_add_or_replace_func(bContext *C, void *arg1, void *U { uiBut *but = arg1; bUserMenu *um = ED_screen_user_menu_ensure(C); + U.runtime.is_dirty = true; ui_but_user_menu_add(C, but, um); } @@ -330,6 +399,7 @@ static void popup_user_menu_remove_func(bContext *UNUSED(C), void *arg1, void *a { bUserMenu *um = arg1; bUserMenuItem *umi = arg2; + U.runtime.is_dirty = true; ED_screen_user_menu_item_remove(&um->items, umi); } @@ -890,16 +960,18 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) uiItemS(layout); } - /* Operator buttons */ - if (but->optype) { + /* Shortcut menu */ + IDProperty *prop; + const char *idname = shortcut_get_operator_property(C, but, &prop); + if (idname != NULL) { uiBlock *block = uiLayoutGetBlock(layout); uiBut *but2; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int w = uiLayoutGetWidth(layout); wmKeyMap *km; + /* We want to know if this op has a shortcut, be it hotkey or not. */ wmKeyMapItem *kmi = WM_key_event_operator( - C, but->optype->idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km); + C, idname, but->opcontext, prop, EVT_TYPE_MASK_ALL, 0, &km); /* We do have a shortcut, but only keyboard ones are editable that way... */ if (kmi) { @@ -971,7 +1043,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } } /* only show 'assign' if there's a suitable key map for it to go in */ - else if (WM_keymap_guess_opname(C, but->optype->idname)) { + else if (WM_keymap_guess_opname(C, idname)) { but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, @@ -990,6 +1062,8 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); } + shortcut_free_operator_property(prop); + /* Set the operator pointer for python access */ uiLayoutSetContextFromBut(layout, but); @@ -1108,6 +1182,9 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *ar, Panel *pa) if (!any_item_visible) { return; } + if (pa->type->parent != NULL) { + return; + } RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr); diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index 1d90139eade..658aa4f67f9 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -207,7 +207,7 @@ static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) RNA_id_pointer_create(id, &ptr_value); - RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); + RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, NULL); RNA_property_update(C, &ddr->ptr, ddr->prop); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 8f19f40d1c0..b9c77b13401 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -551,6 +551,23 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) return true; } +static void ui_but_update_preferences_dirty(uiBut *but) +{ + /* Not very elegant, but ensures preference changes force re-save. */ + bool tag = false; + if (but->rnaprop) { + StructRNA *base = RNA_struct_base(but->rnapoin.type); + if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { + tag = true; + } + } + + if (tag) { + U.runtime.is_dirty = true; + WM_main_add_notifier(NC_WINDOW, NULL); + } +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1334,6 +1351,9 @@ static bool ui_drag_toggle_set_xy_xy( if (do_check) { ui_but_update_edited(but); } + if (U.runtime.is_dirty == false) { + ui_but_update_preferences_dirty(but); + } changed = true; } } @@ -1715,7 +1735,7 @@ static void ui_selectcontext_apply(bContext *C, } else if (rna_type == PROP_POINTER) { const PointerRNA other_value = delta.p; - RNA_property_pointer_set(&lptr, lprop, other_value); + RNA_property_pointer_set(&lptr, lprop, other_value, NULL); } RNA_property_update(C, &lptr, prop); @@ -3769,7 +3789,7 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat } if (func || handlefunc) { - data->menu = ui_popup_block_create(C, data->region, but, func, handlefunc, arg); + data->menu = ui_popup_block_create(C, data->region, but, func, handlefunc, arg, NULL); if (but->block->handle) { data->menu->popup = but->block->handle->popup; } @@ -3949,6 +3969,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { return WM_UI_HANDLER_CONTINUE; } + else if (event->type == UNKNOWNKEY) { + return WM_UI_HANDLER_CONTINUE; + } if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* only cancel if click outside the button */ @@ -5619,6 +5642,13 @@ static int ui_do_but_UNITVEC( } } } + else if (event->type == ESCKEY || event->type == RIGHTMOUSE) { + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -6491,7 +6521,7 @@ static int ui_do_but_CURVE( CurveMap *cuma = cumap->cm + cumap->cur; CurveMapPoint *cmp; const float m_xy[2] = {mx, my}; - float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */ + float dist_min_sq = SQUARE(U.dpi_fac * 14.0f); /* 14 pixels radius */ int sel = -1; if (event->ctrl) { @@ -6526,7 +6556,7 @@ static int ui_do_but_CURVE( BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x); /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */ - dist_min_sq = SQUARE(8.0f); + dist_min_sq = SQUARE(U.dpi_fac * 8.0f); /* loop through the curve segment table and find what's near the mouse. */ for (i = 1; i <= CM_TABLE; i++) { @@ -7563,6 +7593,10 @@ static void button_activate_exit( if (block->flag & UI_BLOCK_POPUP_MEMORY) { ui_popup_menu_memory_set(block, but); } + + if (U.runtime.is_dirty == false) { + ui_but_update_preferences_dirty(but); + } } /* disable tooltips until mousemove + last active flag */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 7e295f83390..fa3605269ff 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -37,6 +37,7 @@ #include "BLI_utildefines.h" #include "BLI_fileops_types.h" #include "BLI_math_vector.h" +#include "BLI_math_color_blend.h" #include "DNA_brush_types.h" #include "DNA_curve_types.h" @@ -83,6 +84,7 @@ # define ICON_GRID_COLS 26 # define ICON_GRID_ROWS 30 +# define ICON_MONO_BORDER_OUTSET 2 # define ICON_GRID_MARGIN 10 # define ICON_GRID_W 32 # define ICON_GRID_H 32 @@ -138,7 +140,8 @@ typedef struct DrawInfo { } DrawInfo; typedef struct IconTexture { - GLuint id; + GLuint id[2]; + int num_textures; int w; int h; float invw; @@ -154,12 +157,13 @@ typedef struct IconType { /* static here to cache results of icon directory scan, so it's not * scanning the filesystem each time the menu is drawn */ static struct ListBase iconfilelist = {NULL, NULL}; -static IconTexture icongltex = {0, 0, 0, 0.0f, 0.0f}; +static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f}; #ifndef WITH_HEADLESS static const IconType icontypes[] = { # define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0}, +# define DEF_ICON_SCENE(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SCENE}, # define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION}, # define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT}, # define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA}, @@ -713,38 +717,146 @@ static void icon_verify_datatoc(IconImage *iimg) } } -static void init_internal_icons(void) +static ImBuf *create_mono_icon_with_border(ImBuf *buf, + int resolution_divider, + float border_intensity) { - // bTheme *btheme = UI_GetTheme(); - ImBuf *b16buf = NULL, *b32buf = NULL; - int x, y; + ImBuf *result = IMB_dupImBuf(buf); + const float border_sharpness = 16.0 / (resolution_divider * resolution_divider); -# if 0 // temp disabled - if ((btheme != NULL) && btheme->tui.iconfile[0]) { - char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); - char iconfilestr[FILE_MAX]; + float blurred_alpha_buffer[(ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) * + (ICON_GRID_H + 2 * ICON_MONO_BORDER_OUTSET)]; + const int icon_width = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; + const int icon_height = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; - if (icondir) { - BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); + for (int y = 0; y < ICON_GRID_ROWS; y++) { + for (int x = 0; x < ICON_GRID_COLS; x++) { + IconType icontype = icontypes[y * ICON_GRID_COLS + x]; + if (icontype.type != ICON_TYPE_MONO_TEXTURE) { + continue; + } - /* if the image is missing bbuf will just be NULL */ - bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); + int sx = x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; + int sy = y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; + sx = sx / resolution_divider; + sy = sy / resolution_divider; + + /* blur the alpha channel and store it in blurred_alpha_buffer */ + int blur_size = 2 / resolution_divider; + for (int bx = 0; bx < icon_width; bx++) { + const int asx = MAX2(bx - blur_size, 0); + const int aex = MIN2(bx + blur_size + 1, icon_width); + for (int by = 0; by < icon_height; by++) { + const int asy = MAX2(by - blur_size, 0); + const int aey = MIN2(by + blur_size + 1, icon_height); + + // blur alpha channel + const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; + float alpha_accum = 0.0; + unsigned int alpha_samples = 0; + for (int ax = asx; ax < aex; ax++) { + for (int ay = asy; ay < aey; ay++) { + const int offset_read = (sy + ay) * buf->x + (sx + ax); + unsigned int color_read = buf->rect[offset_read]; + const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0; + alpha_accum += alpha_read; + alpha_samples += 1; + } + } + blurred_alpha_buffer[write_offset] = alpha_accum / alpha_samples; + } + } - if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { - printf( - "\n***WARNING***\n" - "Icons file '%s' too small.\n" - "Using built-in Icons instead\n", - iconfilestr); - IMB_freeImBuf(bbuf); - bbuf = NULL; + /* apply blurred alpha */ + for (int bx = 0; bx < icon_width; bx++) { + for (int by = 0; by < icon_height; by++) { + const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; + const int offset_write = (sy + by) * buf->x + (sx + bx); + const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset]; + float border_srgb[4] = { + 0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity}; + + const unsigned int color_read = buf->rect[offset_write]; + const unsigned char *orig_color = (unsigned char *)&color_read; + + float border_rgba[4]; + float orig_rgba[4]; + float dest_rgba[4]; + float dest_srgb[4]; + + srgb_to_linearrgb_v4(border_rgba, border_srgb); + srgb_to_linearrgb_uchar4(orig_rgba, orig_color); + blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]); + linearrgb_to_srgb_v4(dest_srgb, dest_rgba); + + unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24; + unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask; + result->rect[offset_write] = cpack; + } } } - else { - printf("%s: 'icons' data path not found, continuing\n", __func__); + } + return result; +} + +/* Generate the mipmap levels for the icon textures + * During creation the source16 ImBuf will be freed to reduce memory overhead + * A new ImBuf will be returned that needs is owned by the caller. + * + * FIXME: Mipmap levels are generated until the width of the image is 1, which + * are too many levels than that are needed.*/ +static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level) +{ + if (level == 0) { + glTexImage2D(GL_TEXTURE_2D, + level, + GL_RGBA8, + source32->x, + source32->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + source32->rect); + return create_mono_icon_mipmaps(source32, source16, level + 1); + } + else { + glTexImage2D(GL_TEXTURE_2D, + level, + GL_RGBA8, + source16->x, + source16->y, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + source16->rect); + if (source16->x > 1) { + ImBuf *nbuf = IMB_onehalf(source16); + IMB_freeImBuf(source16); + source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1); } + return source16; } -# endif +} + +static void free_icons_textures(void) +{ + if (icongltex.num_textures > 0) { + glDeleteTextures(icongltex.num_textures, icongltex.id); + icongltex.id[0] = 0; + icongltex.id[1] = 0; + icongltex.num_textures = 0; + } +} + +/* Reload the textures for internal icons. + * This function will release the previous textures. */ +void UI_icons_reload_internal_textures(void) +{ + bTheme *btheme = UI_GetTheme(); + ImBuf *b16buf = NULL, *b32buf = NULL, *b16buf_border = NULL, *b32buf_border = NULL; + const float icon_border_intensity = btheme->tui.icon_border_intensity; + bool need_icons_with_border = icon_border_intensity > 0.0f; + if (b16buf == NULL) { b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png, datatoc_blender_icons16_png_size, @@ -753,6 +865,10 @@ static void init_internal_icons(void) "<blender icons>"); } if (b16buf) { + if (need_icons_with_border) { + b16buf_border = create_mono_icon_with_border(b16buf, 2, icon_border_intensity); + IMB_premultiply_alpha(b16buf_border); + } IMB_premultiply_alpha(b16buf); } @@ -764,88 +880,97 @@ static void init_internal_icons(void) "<blender icons>"); } if (b32buf) { + if (need_icons_with_border) { + b32buf_border = create_mono_icon_with_border(b32buf, 1, icon_border_intensity); + IMB_premultiply_alpha(b32buf_border); + } IMB_premultiply_alpha(b32buf); } if (b16buf && b32buf) { /* Free existing texture if any. */ - if (icongltex.id) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } + free_icons_textures(); /* Allocate OpenGL texture. */ - glGenTextures(1, &icongltex.id); - - if (icongltex.id) { - int level = 2; + icongltex.num_textures = need_icons_with_border ? 2 : 1; + glGenTextures(icongltex.num_textures, icongltex.id); + if (icongltex.id[0]) { icongltex.w = b32buf->x; icongltex.h = b32buf->y; icongltex.invw = 1.0f / b32buf->x; icongltex.invh = 1.0f / b32buf->y; - glBindTexture(GL_TEXTURE_2D, icongltex.id); - - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - b32buf->x, - b32buf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - b32buf->rect); - glTexImage2D(GL_TEXTURE_2D, - 1, - GL_RGBA8, - b16buf->x, - b16buf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - b16buf->rect); - - while (b16buf->x > 1) { - ImBuf *nbuf = IMB_onehalf(b16buf); - glTexImage2D(GL_TEXTURE_2D, - level, - GL_RGBA8, - nbuf->x, - nbuf->y, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - nbuf->rect); - level++; - IMB_freeImBuf(b16buf); - b16buf = nbuf; - } - + glBindTexture(GL_TEXTURE_2D, icongltex.id[0]); + b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + } + if (need_icons_with_border && icongltex.id[1]) { + glBindTexture(GL_TEXTURE_2D, icongltex.id[1]); + b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } + } - /* Define icons. */ - for (y = 0; y < ICON_GRID_ROWS; y++) { - /* Row W has monochrome icons. */ - for (x = 0; x < ICON_GRID_COLS; x++) { - IconType icontype = icontypes[y * ICON_GRID_COLS + x]; - if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { - continue; - } + IMB_freeImBuf(b16buf); + IMB_freeImBuf(b32buf); + IMB_freeImBuf(b16buf_border); + IMB_freeImBuf(b32buf_border); +} - def_internal_icon(b32buf, - BIFICONID_FIRST + y * ICON_GRID_COLS + x, - x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, - y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, - ICON_GRID_W, - icontype.type, - icontype.theme_color); +static void init_internal_icons(void) +{ + int x, y; + +# if 0 // temp disabled + if ((btheme != NULL) && btheme->tui.iconfile[0]) { + char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); + char iconfilestr[FILE_MAX]; + + if (icondir) { + BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); + + /* if the image is missing bbuf will just be NULL */ + bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); + + if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { + printf( + "\n***WARNING***\n" + "Icons file '%s' too small.\n" + "Using built-in Icons instead\n", + iconfilestr); + IMB_freeImBuf(bbuf); + bbuf = NULL; } } + else { + printf("%s: 'icons' data path not found, continuing\n", __func__); + } + } +# endif + + /* Define icons. */ + for (y = 0; y < ICON_GRID_ROWS; y++) { + /* Row W has monochrome icons. */ + for (x = 0; x < ICON_GRID_COLS; x++) { + IconType icontype = icontypes[y * ICON_GRID_COLS + x]; + if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { + continue; + } + + def_internal_icon(NULL, + BIFICONID_FIRST + y * ICON_GRID_COLS + x, + x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, + y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, + ICON_GRID_W, + icontype.type, + icontype.theme_color); + } } def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); @@ -882,9 +1007,6 @@ static void init_internal_icons(void) def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18); def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19); def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20); - - IMB_freeImBuf(b16buf); - IMB_freeImBuf(b32buf); } # endif /* WITH_HEADLESS */ @@ -964,6 +1086,12 @@ static void free_iconfile_list(struct ListBase *list) } } +#else + +void UI_icons_reload_internal_textures(void) +{ +} + #endif /* WITH_HEADLESS */ int UI_iconfile_get_index(const char *filename) @@ -990,11 +1118,7 @@ ListBase *UI_iconfile_list(void) void UI_icons_free(void) { #ifndef WITH_HEADLESS - if (icongltex.id) { - glDeleteTextures(1, &icongltex.id); - icongltex.id = 0; - } - + free_icons_textures(); free_iconfile_list(&iconfilelist); BKE_icons_free(); #endif @@ -1104,10 +1228,22 @@ int UI_icon_get_height(int icon_id) return 0; } +bool UI_icon_get_theme_color(int icon_id, uchar color[4]) +{ + Icon *icon = BKE_icon_get(icon_id); + if (icon == NULL) { + return false; + } + + DrawInfo *di = icon_ensure_drawinfo(icon); + return UI_GetIconThemeColor4ubv(di->data.texture.theme_color, color); +} + void UI_icons_init() { #ifndef WITH_HEADLESS init_iconfile_list(&iconfilelist); + UI_icons_reload_internal_textures(); init_internal_icons(); init_brush_icons(); init_event_icons(); @@ -1348,7 +1484,6 @@ static void icon_draw_rect(float x, int rh, uint *rect, float alpha, - const float rgb[3], const float desaturate) { ImBuf *ima = NULL; @@ -1366,12 +1501,6 @@ static void icon_draw_rect(float x, /* modulate color */ float col[4] = {1.0f, 1.0f, 1.0f, alpha}; - if (rgb) { - col[0] = rgb[0]; - col[1] = rgb[1]; - col[2] = rgb[2]; - } - /* rect contains image in 'rendersize', we only scale if needed */ if (rw != w || rh != h) { /* preserve aspect ratio and center */ @@ -1439,12 +1568,17 @@ typedef struct IconDrawCall { float color[4]; } IconDrawCall; -static struct { +typedef struct IconTextureDrawCall { IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE]; int calls; /* Number of calls batched together */ +} IconTextureDrawCall; + +static struct { + IconTextureDrawCall normal; + IconTextureDrawCall border; bool enabled; float mat[4][4]; -} g_icon_draw_cache = {{{{0}}}}; +} g_icon_draw_cache = {{{{{0}}}}}; void UI_icon_draw_cache_begin(void) { @@ -1452,19 +1586,15 @@ void UI_icon_draw_cache_begin(void) g_icon_draw_cache.enabled = true; } -static void icon_draw_cache_flush_ex(void) +static void icon_draw_cache_texture_flush_ex(GLuint texture, + IconTextureDrawCall *texture_draw_calls) { - if (g_icon_draw_cache.calls == 0) { + if (texture_draw_calls->calls == 0) { return; } - /* We need to flush widget base first to ensure correct ordering. */ - UI_widgetbase_draw_cache_flush(); - - GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, icongltex.id); + glBindTexture(GL_TEXTURE_2D, texture); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); GPU_shader_bind(shader); @@ -1473,16 +1603,43 @@ static void icon_draw_cache_flush_ex(void) int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]"); glUniform1i(img_loc, 0); - glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache); + glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); - GPU_draw_primitive(GPU_PRIM_TRIS, 6 * g_icon_draw_cache.calls); + GPU_draw_primitive(GPU_PRIM_TRIS, 6 * texture_draw_calls->calls); glBindTexture(GL_TEXTURE_2D, 0); - g_icon_draw_cache.calls = 0; + texture_draw_calls->calls = 0; +} + +static void icon_draw_cache_flush_ex(bool only_full_caches) +{ + bool should_draw = false; + if (only_full_caches) { + should_draw = g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE || + g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE; + } + else { + should_draw = g_icon_draw_cache.normal.calls || g_icon_draw_cache.border.calls; + } - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + if (should_draw) { + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + + GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + if (!only_full_caches || g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_texture_flush_ex(icongltex.id[0], &g_icon_draw_cache.normal); + } + + if (!only_full_caches || g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_texture_flush_ex(icongltex.id[1], &g_icon_draw_cache.border); + } + + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + } } void UI_icon_draw_cache_end(void) @@ -1491,12 +1648,12 @@ void UI_icon_draw_cache_end(void) g_icon_draw_cache.enabled = false; /* Don't change blend state if it's not needed. */ - if (g_icon_draw_cache.calls == 0) { + if (g_icon_draw_cache.border.calls == 0 && g_icon_draw_cache.normal.calls == 0) { return; } GPU_blend(true); - icon_draw_cache_flush_ex(); + icon_draw_cache_flush_ex(false); GPU_blend(false); } @@ -1509,14 +1666,18 @@ static void icon_draw_texture_cached(float x, int UNUSED(iw), int ih, float alpha, - const float rgb[3]) + const float rgb[3], + bool with_border) { float mvp[4][4]; GPU_matrix_model_view_projection_get(mvp); - IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls]; - g_icon_draw_cache.calls++; + IconTextureDrawCall *texture_call = with_border ? &g_icon_draw_cache.border : + &g_icon_draw_cache.normal; + + IconDrawCall *call = &texture_call->drawcall_cache[texture_call->calls]; + texture_call->calls++; /* Manual mat4*vec2 */ call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0]; @@ -1536,8 +1697,8 @@ static void icon_draw_texture_cached(float x, copy_v4_fl(call->color, alpha); } - if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) { - icon_draw_cache_flush_ex(); + if (texture_call->calls == ICON_DRAW_CACHE_SIZE) { + icon_draw_cache_flush_ex(true); } } @@ -1550,10 +1711,11 @@ static void icon_draw_texture(float x, int iw, int ih, float alpha, - const float rgb[3]) + const float rgb[3], + bool with_border) { if (g_icon_draw_cache.enabled) { - icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb); + icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); return; } @@ -1570,7 +1732,7 @@ static void icon_draw_texture(float x, y2 = (iy + ih) * icongltex.invh; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, icongltex.id); + glBindTexture(GL_TEXTURE_2D, with_border ? icongltex.id[1] : icongltex.id[0]); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); GPU_shader_bind(shader); @@ -1614,11 +1776,11 @@ static void icon_draw_size(float x, int icon_id, float aspect, float alpha, - const float rgb[3], enum eIconSizes size, int draw_size, const float desaturate, - const char mono_rgba[4]) + const char mono_rgba[4], + const bool mono_border) { bTheme *btheme = UI_GetTheme(); Icon *icon = NULL; @@ -1675,7 +1837,7 @@ static void icon_draw_size(float x, GPU_blend_set_func_separate( GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, rgb, desaturate); + icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, desaturate); GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } @@ -1695,36 +1857,42 @@ static void icon_draw_size(float x, di->data.texture.w, di->data.texture.h, alpha, - rgb); + NULL, + false); } else if (di->type == ICON_TYPE_MONO_TEXTURE) { - /* icon that matches text color, assumed to be white */ + /* Monochrome icon that uses text or theme color. */ + bool with_border = mono_border && (btheme->tui.icon_border_intensity > 0.0f); float color[4]; - if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) { - if (mono_rgba) { - rgba_uchar_to_float(color, (const uchar *)mono_rgba); - } - else { - UI_GetThemeColor4fv(TH_TEXT, color); - } + if (mono_rgba) { + rgba_uchar_to_float(color, (const uchar *)mono_rgba); } - - if (rgb) { - mul_v3_v3(color, rgb); + else { + UI_GetThemeColor4fv(TH_TEXT, color); } mul_v4_fl(color, alpha); - icon_draw_texture(x, - y, - (float)w, - (float)h, - di->data.texture.x, - di->data.texture.y, - di->data.texture.w, - di->data.texture.h, + float border_outset = 0.0; + unsigned int border_texel = 0; +#ifndef WITH_HEADLESS + if (with_border) { + const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH; + border_texel = ICON_MONO_BORDER_OUTSET; + border_outset = ICON_MONO_BORDER_OUTSET / (scale * aspect); + } +#endif + icon_draw_texture(x - border_outset, + y - border_outset, + (float)w + 2 * border_outset, + (float)h + 2 * border_outset, + di->data.texture.x - border_texel, + di->data.texture.y - border_texel, + di->data.texture.w + 2 * border_texel, + di->data.texture.h + 2 * border_texel, color[3], - color); + color, + with_border); } else if (di->type == ICON_TYPE_BUFFER) { @@ -1738,7 +1906,7 @@ static void icon_draw_size(float x, return; } - icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, desaturate); + icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate); } else if (di->type == ICON_TYPE_PREVIEW) { PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : @@ -1755,7 +1923,7 @@ static void icon_draw_size(float x, GPU_blend_set_func_separate( GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); icon_draw_rect( - x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, desaturate); + x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, desaturate); GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } @@ -2057,7 +2225,7 @@ int UI_idcode_icon_get(const int idcode) case ID_PC: return ICON_CURVE_BEZCURVE; /* TODO! this would need its own icon! */ case ID_LP: - return ICON_LIGHTPROBE_CUBEMAP; + return ICON_OUTLINER_DATA_LIGHTPROBE; case ID_SCE: return ICON_SCENE_DATA; case ID_SPK: @@ -2077,71 +2245,40 @@ int UI_idcode_icon_get(const int idcode) } } -static void icon_draw_at_size(float x, - float y, - int icon_id, - float aspect, - float alpha, - enum eIconSizes size, - const float desaturate, - const char mono_color[4]) -{ - int draw_size = get_draw_size(size); - icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, desaturate, mono_color); -} - -void UI_icon_draw_aspect( - float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4]) -{ - icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, 0.0f, mono_color); -} - -void UI_icon_draw_aspect_color( - float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4]) -{ - int draw_size = get_draw_size(ICON_SIZE_ICON); - icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, ICON_SIZE_ICON, draw_size, false, mono_color); -} - -void UI_icon_draw_desaturate(float x, - float y, - int icon_id, - float aspect, - float alpha, - float desaturate, - const char mono_color[4]) -{ - icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, desaturate, mono_color); -} - /* draws icon with dpi scale factor */ void UI_icon_draw(float x, float y, int icon_id) { - UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, 1.0f, NULL); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { - UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, alpha, NULL); + UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false); } -void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha) +void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) { - icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, ICON_SIZE_ICON, size, false, NULL); + icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false); } -void UI_icon_draw_preview(float x, float y, int icon_id) +void UI_icon_draw_ex(float x, + float y, + int icon_id, + float aspect, + float alpha, + float desaturate, + const char mono_color[4], + const bool mono_border) { - icon_draw_at_size(x, y, icon_id, 1.0f, 1.0f, ICON_SIZE_PREVIEW, false, NULL); -} - -void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect) -{ - icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, false, NULL); -} - -void UI_icon_draw_preview_aspect_size( - float x, float y, int icon_id, float aspect, float alpha, int size) -{ - icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, NULL); + int draw_size = get_draw_size(ICON_SIZE_ICON); + icon_draw_size(x, + y, + icon_id, + aspect, + alpha, + ICON_SIZE_ICON, + draw_size, + desaturate, + mono_color, + mono_border); } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 4af7fdd779f..8a2b28ee2d4 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -500,6 +500,7 @@ extern int ui_but_string_get_max_length(uiBut *but); extern uiBut *ui_but_drag_multi_edit_get(uiBut *but); void ui_def_but_icon(uiBut *but, const int icon, const int flag); +void ui_def_but_icon_clear(uiBut *but); extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but); extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc); @@ -539,13 +540,12 @@ struct uiKeyNavLock { typedef uiBlock *(*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1); -typedef void (*uiBlockHandleFreeFunc)(struct uiPopupBlockHandle *handle, void *arg1); struct uiPopupBlockCreate { uiBlockCreateFunc create_func; uiBlockHandleCreateFunc handle_create_func; - uiBlockHandleFreeFunc free_func; void *arg; + void (*arg_free)(void *arg); int event_xy[2]; @@ -662,7 +662,8 @@ uiPopupBlockHandle *ui_popup_block_create(struct bContext *C, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, - void *arg); + void *arg, + void (*arg_free)(void *arg)); uiPopupBlockHandle *ui_popup_menu_create(struct bContext *C, struct ARegion *butregion, uiBut *but, diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 41001ff6d14..a3906879fd7 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -304,10 +304,14 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool layout->item.flag |= UI_ITEM_MIN; } const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - /* it may seem odd that the icon only adds (unit_x / 4) - * but taking margins into account its fine */ - return (UI_fontstyle_string_width(fstyle, name) + - (unit_x * ((compact ? 1.25f : 1.50f) + (icon ? 0.25f : 0.0f)))); + float margin = compact ? 1.25 : 1.50; + if (icon) { + /* It may seem odd that the icon only adds (unit_x / 4) + * but taking margins into account its fine, except + * in compact mode a bit more margin is required. */ + margin += compact ? 0.35 : 0.25; + } + return UI_fontstyle_string_width(fstyle, name) + (unit_x * margin); } else { return unit_x * 10; @@ -480,7 +484,7 @@ static void ui_item_array(uiLayout *layout, int UNUSED(h), bool expand, bool slider, - bool toggle, + int toggle, bool icon_only, bool compact, bool show_text) @@ -687,7 +691,7 @@ static void ui_item_array(uiLayout *layout, if (slider && but->type == UI_BTYPE_NUM) { but->type = UI_BTYPE_NUM_SLIDER; } - if (toggle && but->type == UI_BTYPE_CHECKBOX) { + if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) { but->type = UI_BTYPE_TOGGLE; } if ((a == 0) && (subtype == PROP_AXISANGLE)) { @@ -760,7 +764,8 @@ static void ui_item_enum_expand_elem_exec(uiLayout *layout, if (RNA_property_flag(prop) & PROP_ENUM_FLAG) { /* If this is set, assert since we're clobbering someone elses callback. */ - BLI_assert(but->func == NULL); + /* Buttons get their block's func by default, so we cannot assert in that case either. */ + BLI_assert(ELEM(but->func, NULL, block->func)); UI_but_func_set(but, ui_item_enum_expand_handle, but, POINTER_FROM_INT(value)); } @@ -1450,7 +1455,6 @@ void uiItemsFullEnumO_items(uiLayout *layout, if (properties) { if (tptr.data) { IDP_FreeProperty(tptr.data); - MEM_freeN(tptr.data); } tptr.data = IDP_CopyProperty(properties); } @@ -1854,12 +1858,7 @@ void uiItemFullR(uiLayout *layout, int icon) { uiBlock *block = layout->root->block; - uiBut *but = NULL; - PropertyType type; char namestr[UI_MAX_NAME_STR]; - int len, w, h; - bool slider, toggle, expand, icon_only, no_bg, compact; - bool is_array; const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); /* By default 'use_prop_sep' uses a separate column for labels. @@ -1884,11 +1883,15 @@ void uiItemFullR(uiLayout *layout, UI_block_layout_set_current(block, layout); /* retrieve info */ - type = RNA_property_type(prop); - is_array = RNA_property_array_check(prop); - len = (is_array) ? RNA_property_array_length(ptr, prop) : 0; + const PropertyType type = RNA_property_type(prop); + const bool is_array = RNA_property_array_check(prop); + const int len = (is_array) ? RNA_property_array_length(ptr, prop) : 0; + + const bool icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0; - icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0; + /* Boolean with -1 to signify that the value depends on the presence of an icon. */ + const int toggle = ((flag & UI_ITEM_R_TOGGLE) ? 1 : ((flag & UI_ITEM_R_ICON_NEVER) ? 0 : -1)); + const bool no_icon = (toggle == 0); /* set name and icon */ if (!name) { @@ -1900,8 +1903,8 @@ void uiItemFullR(uiLayout *layout, } } - if (icon == ICON_NONE) { - icon = RNA_property_ui_icon(prop); + if (type != PROP_BOOLEAN) { + flag &= ~UI_ITEM_R_CHECKBOX_INVERT; } if (flag & UI_ITEM_R_ICON_ONLY) { @@ -1928,56 +1931,66 @@ void uiItemFullR(uiLayout *layout, } } -#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION - if (use_prop_sep) { - if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) { - use_prop_sep_split_label = false; + if (no_icon == false) { + if (icon == ICON_NONE) { + icon = RNA_property_ui_icon(prop); } - } -#endif - /* menus and pie-menus don't show checkbox without this */ - if ((layout->root->type == UI_LAYOUT_MENU) || - /* use checkboxes only as a fallback in pie-menu's, when no icon is defined */ - ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) { - int prop_flag = RNA_property_flag(prop); - if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) { - if (prop_flag & PROP_ICONS_CONSECUTIVE) { - icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ - } - else if (is_array) { - icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : - ICON_CHECKBOX_DEHLT; + /* Menus and pie-menus don't show checkbox without this. */ + if ((layout->root->type == UI_LAYOUT_MENU) || + /* Use checkboxes only as a fallback in pie-menu's, when no icon is defined. */ + ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) { + int prop_flag = RNA_property_flag(prop); + if (type == PROP_BOOLEAN) { + if ((is_array == false) || (index != RNA_NO_INDEX)) { + if (prop_flag & PROP_ICONS_CONSECUTIVE) { + icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ + } + else if (is_array) { + icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : + ICON_CHECKBOX_DEHLT; + } + else { + icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + } } - else { - icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + else if (type == PROP_ENUM) { + if (index == RNA_ENUM_VALUE) { + int enum_value = RNA_property_enum_get(ptr, prop); + if (prop_flag & PROP_ICONS_CONSECUTIVE) { + icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ + } + else if (prop_flag & PROP_ENUM_FLAG) { + icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + else { + icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; + } + } } } - else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) { - int enum_value = RNA_property_enum_get(ptr, prop); - if (prop_flag & PROP_ICONS_CONSECUTIVE) { - icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */ - } - else if (prop_flag & PROP_ENUM_FLAG) { - icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; - } - else { - icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; - } + } + +#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION + if (use_prop_sep) { + if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) { + use_prop_sep_split_label = false; } } +#endif if ((type == PROP_ENUM) && (RNA_property_flag(prop) & PROP_ENUM_FLAG)) { flag |= UI_ITEM_R_EXPAND; } - slider = (flag & UI_ITEM_R_SLIDER) != 0; - toggle = (flag & UI_ITEM_R_TOGGLE) != 0; - expand = (flag & UI_ITEM_R_EXPAND) != 0; - no_bg = (flag & UI_ITEM_R_NO_BG) != 0; - compact = (flag & UI_ITEM_R_COMPACT) != 0; + const bool slider = (flag & UI_ITEM_R_SLIDER) != 0; + const bool expand = (flag & UI_ITEM_R_EXPAND) != 0; + const bool no_bg = (flag & UI_ITEM_R_NO_BG) != 0; + const bool compact = (flag & UI_ITEM_R_COMPACT) != 0; /* get size */ + int w, h; ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h); int prev_emboss = layout->emboss; @@ -1985,6 +1998,8 @@ void uiItemFullR(uiLayout *layout, layout->emboss = UI_EMBOSS_NONE; } + uiBut *but = NULL; + /* Split the label / property. */ uiLayout *layout_parent = layout; if (use_prop_sep) { @@ -2152,7 +2167,13 @@ void uiItemFullR(uiLayout *layout, but->type = UI_BTYPE_NUM_SLIDER; } - if (toggle && but->type == UI_BTYPE_CHECKBOX) { + if (flag & UI_ITEM_R_CHECKBOX_INVERT) { + if (ELEM(but->type, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N)) { + but->drawflag |= UI_BUT_CHECKBOX_INVERT; + } + } + + if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) { but->type = UI_BTYPE_TOGGLE; } @@ -2171,6 +2192,18 @@ void uiItemFullR(uiLayout *layout, } } + /* The resulting button may have the icon set since boolean button drawing + * is being 'helpful' and adding an icon for us. + * In this case we want the ability not to have an icon. + * + * We could pass an argument not to set the icon to begin with however this is the one case + * the functionality is needed. */ + if (but && no_icon) { + if ((icon == ICON_NONE) && (but->icon != ICON_NONE)) { + ui_def_but_icon_clear(but); + } + } + /* Mark non-embossed textfields inside a listbox. */ if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) && (but->dt & UI_EMBOSS_NONE)) { diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 87e58a4b3b5..9c5ce0c9d2c 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -258,43 +258,16 @@ static void panels_collapse_all(ScrArea *sa, ARegion *ar, const Panel *from_pa) } } -static void ui_panel_copy_offset(Panel *pa, Panel *papar) -{ - /* with respect to sizes... papar is parent */ - - pa->ofsx = papar->ofsx; - pa->ofsy = papar->ofsy + papar->sizey - pa->sizey; -} - -/** - * XXX Disabled paneltab handling for now. Old 2.4x feature, - * *DO NOT* confuse it with new tool tabs in 2.70. ;) - * See also T41704. - */ -/* #define UI_USE_PANELTAB */ - Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt) { Panel *pa; const char *idname = pt->idname; -#ifdef UI_USE_PANELTAB - const char *tabname = pt->idname; - for (pa = lb->first; pa; pa = pa->next) { - if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { - if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) { - return pa; - } - } - } -#else for (pa = lb->first; pa; pa = pa->next) { if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { return pa; } } -#endif - return NULL; } @@ -307,10 +280,6 @@ Panel *UI_panel_begin( Panel *palast, *panext; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; -#ifdef UI_USE_PANELTAB - const char *tabname = pt->idname; - const char *hookname = NULL; -#endif const bool newpanel = (pa == NULL); int align = panel_aligned(sa, ar); @@ -341,28 +310,6 @@ Panel *UI_panel_begin( pa->runtime_flag |= PNL_NEW_ADDED; BLI_addtail(lb, pa); - -#ifdef UI_USE_PANELTAB - BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname)); - - /* make new Panel tabbed? */ - if (hookname) { - Panel *patab; - for (patab = lb->first; patab; patab = patab->next) { - if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) { - if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) { - if (STREQLEN(tabname, patab->tabname, sizeof(patab->tabname))) { - pa->paneltab = patab; - ui_panel_copy_offset(pa, patab); - break; - } - } - } - } - } -#else - BLI_strncpy(pa->tabname, idname, sizeof(pa->tabname)); -#endif } /* Do not allow closed panels without headers! Else user could get "disappeared" UI! */ @@ -411,9 +358,6 @@ Panel *UI_panel_begin( *r_open = false; - if (pa->paneltab) { - return pa; - } if (pa->flag & PNL_CLOSED) { return pa; } @@ -423,7 +367,7 @@ Panel *UI_panel_begin( return pa; } -void UI_panel_end(uiBlock *block, int width, int height) +void UI_panel_end(uiBlock *block, int width, int height, bool open) { Panel *pa = block->panel; @@ -446,21 +390,21 @@ void UI_panel_end(uiBlock *block, int width, int height) pa->sizey = height; } else { - /* check if we need to do an animation */ - if (!ELEM(width, 0, pa->sizex) || !ELEM(height, 0, pa->sizey)) { - pa->runtime_flag |= PNL_ANIM_ALIGN; - if (height != 0) { - pa->ofsy += pa->sizey - height; - } - } + int old_sizex = pa->sizex, old_sizey = pa->sizey; /* update width/height if non-zero */ if (width != 0) { pa->sizex = width; } - if (height != 0) { + if (height != 0 || open) { pa->sizey = height; } + + /* check if we need to do an animation */ + if (pa->sizex != old_sizex || pa->sizey != old_sizey) { + pa->runtime_flag |= PNL_ANIM_ALIGN; + pa->ofsy += old_sizey - pa->sizey; + } } } @@ -705,11 +649,17 @@ void ui_draw_aligned_panel(uiStyle *style, /* FIXME(campbell): currently no background means floating panel which * can't be dragged. This may be changed in future. */ show_background); + const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; - if (panel->paneltab) { - return; - } if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { + if (show_background) { + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(panel_col); + immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + immUnbindProgram(); + } return; } @@ -765,12 +715,14 @@ void ui_draw_aligned_panel(uiStyle *style, panel_title_color_get(show_background, col_title); GPU_blend(true); - UI_icon_draw_aspect(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), - headrect.ymin + (5.0f / block->aspect), - (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, - (block->aspect / UI_DPI_FAC), - 1.0f, - (const char *)col_title); + UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), + headrect.ymin + (5.0f / block->aspect), + (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, + (block->aspect * U.inv_dpi_fac), + 1.0f, + 0.0f, + (const char *)col_title, + false); GPU_blend(false); } @@ -838,8 +790,6 @@ void ui_draw_aligned_panel(uiStyle *style, if (show_background) { /* panel backdrop */ - int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; - immUniformThemeColor(panel_col); immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); } @@ -934,12 +884,6 @@ static int get_panel_real_ofsy(Panel *pa) if (pa->flag & PNL_CLOSEDY) { return pa->ofsy + pa->sizey; } - else if (pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDY)) { - return pa->ofsy + pa->sizey; - } - else if (pa->paneltab) { - return pa->paneltab->ofsy; - } else { return pa->ofsy; } @@ -950,9 +894,6 @@ static int get_panel_real_ofsx(Panel *pa) if (pa->flag & PNL_CLOSEDX) { return pa->ofsx + get_panel_header(pa); } - else if (pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDX)) { - return pa->ofsx + get_panel_header(pa); - } else { return pa->ofsx + pa->sizex; } @@ -1067,7 +1008,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* count active, not tabbed panels */ for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { tot++; } } @@ -1078,7 +1019,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* extra; change close direction? */ for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { if ((pa->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { pa->flag ^= PNL_CLOSED; } @@ -1093,7 +1034,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo ps = panelsort; for (pa = ar->panels.first; pa; pa = pa->next) { - if ((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab == NULL) { + if (pa->runtime_flag & PNL_ACTIVE) { ps->pa = MEM_dupallocN(pa); ps->orig = pa; ps++; @@ -1160,9 +1101,6 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* set locations for tabbed and sub panels */ for (pa = ar->panels.first; pa; pa = pa->next) { if (pa->runtime_flag & PNL_ACTIVE) { - if (pa->paneltab) { - ui_panel_copy_offset(pa, pa->paneltab); - } if (pa->children.first) { align_sub_panels(pa); } @@ -1265,7 +1203,7 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *r_x, int *r_y) { ScrArea *sa = CTX_wm_area(C); uiBlock *block; - Panel *panot, *panew, *patest, *pa, *firstpa; + Panel *pa, *firstpa; /* offset contents */ for (block = ar->uiblocks.first; block; block = block->next) { @@ -1274,31 +1212,6 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *r_x, int *r_y) } } - /* consistency; are panels not made, whilst they have tabs */ - for (panot = ar->panels.first; panot; panot = panot->next) { - if ((panot->runtime_flag & PNL_ACTIVE) == 0) { /* not made */ - - for (panew = ar->panels.first; panew; panew = panew->next) { - if ((panew->runtime_flag & PNL_ACTIVE)) { - if (panew->paneltab == panot) { /* panew is tab in notmade pa */ - break; - } - } - } - /* now panew can become the new parent, check all other tabs */ - if (panew) { - for (patest = ar->panels.first; patest; patest = patest->next) { - if (patest->paneltab == panot) { - patest->paneltab = panew; - } - } - panot->paneltab = panew; - panew->paneltab = NULL; - ED_region_tag_redraw(ar); /* the buttons panew were not made */ - } - } - } - /* re-align, possibly with animation */ if (panels_need_realign(sa, ar, &pa)) { if (pa) { @@ -1380,7 +1293,7 @@ static void check_panel_overlap(ARegion *ar, Panel *panel) for (pa = ar->panels.first; pa; pa = pa->next) { pa->flag &= ~PNL_OVERLAP; if (panel && (pa != panel)) { - if (pa->paneltab == NULL && (pa->runtime_flag & PNL_ACTIVE)) { + if (pa->runtime_flag & PNL_ACTIVE) { float safex = 0.2, safey = 0.2; if (pa->flag & PNL_CLOSEDX) { @@ -1623,11 +1536,11 @@ static void ui_handle_panel_header( { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - Panel *pa; #ifdef USE_PIN_HIDDEN - const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->flag & PNL_PIN); + const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->type->parent == NULL) && + (block->panel->flag & PNL_PIN); #else - const bool show_pin = UI_panel_category_is_visible(ar); + const bool show_pin = UI_panel_category_is_visible(ar) && (block->panel->type->parent == NULL); #endif const bool is_subpanel = (block->panel->type && block->panel->type->parent); const bool show_drag = !is_subpanel; @@ -1658,8 +1571,10 @@ static void ui_handle_panel_header( button = 1; } else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) { - block->panel->flag ^= PNL_PIN; - button = 2; + if (block->panel->type->parent == NULL) { + block->panel->flag ^= PNL_PIN; + button = 2; + } } else if (block->panel->flag & PNL_CLOSEDX) { if (my >= block->rect.ymax) { @@ -1720,17 +1635,6 @@ static void ui_handle_panel_header( ui_panel_drag_collapse_handler_add(C, true); } } - - for (pa = ar->panels.first; pa; pa = pa->next) { - if (pa->paneltab == block->panel) { - if (block->panel->flag & PNL_CLOSED) { - pa->flag |= PNL_CLOSED; - } - else { - pa->flag &= ~PNL_CLOSED; - } - } - } } if (align) { @@ -1772,28 +1676,7 @@ PanelCategoryStack *UI_panel_category_active_find(ARegion *ar, const char *idnam return BLI_findstring(&ar->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); } -const char *UI_panel_category_active_get(ARegion *ar, bool set_fallback) -{ - PanelCategoryStack *pc_act; - - for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { - if (UI_panel_category_find(ar, pc_act->idname)) { - return pc_act->idname; - } - } - - if (set_fallback) { - PanelCategoryDyn *pc_dyn = ar->panels_category.first; - if (pc_dyn) { - UI_panel_category_active_set(ar, pc_dyn->idname); - return pc_dyn->idname; - } - } - - return NULL; -} - -void UI_panel_category_active_set(ARegion *ar, const char *idname) +static void ui_panel_category_active_set(ARegion *ar, const char *idname, bool fallback) { ListBase *lb = &ar->panels_category_active; PanelCategoryStack *pc_act = UI_panel_category_active_find(ar, idname); @@ -1806,7 +1689,13 @@ void UI_panel_category_active_set(ARegion *ar, const char *idname) BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); } - BLI_addhead(lb, pc_act); + if (fallback) { + /* For fallbacks, add at the end so explicitly chosen categories have priority. */ + BLI_addtail(lb, pc_act); + } + else { + BLI_addhead(lb, pc_act); + } /* validate all active panels, we could do this on load, * they are harmless - but we should remove somewhere. @@ -1825,6 +1714,39 @@ void UI_panel_category_active_set(ARegion *ar, const char *idname) } } +void UI_panel_category_active_set(ARegion *ar, const char *idname) +{ + ui_panel_category_active_set(ar, idname, false); +} + +void UI_panel_category_active_set_default(ARegion *ar, const char *idname) +{ + if (!UI_panel_category_active_find(ar, idname)) { + ui_panel_category_active_set(ar, idname, true); + } +} + +const char *UI_panel_category_active_get(ARegion *ar, bool set_fallback) +{ + PanelCategoryStack *pc_act; + + for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { + if (UI_panel_category_find(ar, pc_act->idname)) { + return pc_act->idname; + } + } + + if (set_fallback) { + PanelCategoryDyn *pc_dyn = ar->panels_category.first; + if (pc_dyn) { + ui_panel_category_active_set(ar, pc_dyn->idname, true); + return pc_dyn->idname; + } + } + + return NULL; +} + PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *ar, const int x, const int y) { PanelCategoryDyn *ptd; @@ -2067,7 +1989,11 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f)); BLF_size(fontid, fstyle_points, U.dpi); - BLI_assert(UI_panel_category_is_visible(ar)); + /* Check the region type supports categories to avoid an assert + * for showing 3D view panels in the properties space. */ + if ((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) { + BLI_assert(UI_panel_category_is_visible(ar)); + } /* calculate tab rect's and check if we need to scale down */ for (pc_dyn = ar->panels_category.first; pc_dyn; pc_dyn = pc_dyn->next) { @@ -2378,7 +2304,7 @@ int ui_handler_panel_region(bContext *C, /* checks for mouse position inside */ pa = block->panel; - if (!pa || pa->paneltab != NULL) { + if (!pa) { continue; } /* XXX - accessed freed panels when scripts reload, need to fix. */ diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index dcbbde259f2..330a9d48ff4 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -208,7 +208,7 @@ void UI_pie_menu_end(bContext *C, uiPieMenu *pie) wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *menu; - menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie); + menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie, NULL); menu->popup = true; menu->towardstime = PIL_check_seconds_timer(); diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index b97cbcdfef5..ab3a86ec9e1 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -351,7 +351,7 @@ uiPopupBlockHandle *ui_popup_menu_create( pup->menu_func = menu_func; pup->menu_arg = arg; - handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup); + handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup, NULL); if (!but) { handle->popup = true; @@ -463,7 +463,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup) butregion = pup->butregion; } - menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup); + menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup, NULL); menu->popup = true; UI_popup_handlers_add(C, &window->modalhandlers, menu, 0); @@ -581,13 +581,17 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) /** \name Popup Block API * \{ */ -void UI_popup_block_invoke_ex( - bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext) +void UI_popup_block_invoke_ex(bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg), + const char *opname, + int opcontext) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, arg_free); handle->popup = true; handle->can_refresh = true; handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL; @@ -598,9 +602,12 @@ void UI_popup_block_invoke_ex( WM_event_add_mousemove(C); } -void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg) +void UI_popup_block_invoke(bContext *C, + uiBlockCreateFunc func, + void *arg, + void (*arg_free)(void *arg)) { - UI_popup_block_invoke_ex(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT); + UI_popup_block_invoke_ex(C, func, arg, arg_free, NULL, WM_OP_INVOKE_DEFAULT); } void UI_popup_block_ex(bContext *C, @@ -613,7 +620,7 @@ void UI_popup_block_ex(bContext *C, wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, NULL); handle->popup = true; handle->retvalue = 1; handle->can_refresh = true; @@ -635,7 +642,7 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, NULL, NULL, func, NULL, op); + handle = ui_popup_block_create(C, NULL, NULL, func, NULL, op, NULL); handle->popup = 1; handle->retvalue = 1; handle->can_refresh = true; diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index f149ccd626c..22c62ecd6f7 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -244,7 +244,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v return block; } -static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup) +static void ui_block_free_func_POPOVER(void *arg_pup) { uiPopover *pup = arg_pup; if (pup->keymap != NULL) { @@ -282,8 +282,8 @@ uiPopupBlockHandle *ui_popover_panel_create( /* Create popup block. */ uiPopupBlockHandle *handle; - handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup); - handle->popup_create_vars.free_func = ui_block_free_func_POPOVER; + handle = ui_popup_block_create( + C, butregion, but, NULL, ui_block_func_POPOVER, pup, ui_block_free_func_POPOVER); handle->can_refresh = true; /* Add handlers. If attached to a button, the button will already @@ -386,8 +386,8 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap) WM_event_set_keymap_handler_post_callback(pup->keymap_handler, popover_keymap_fn, pup); } - handle = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPOVER, pup); - handle->popup_create_vars.free_func = ui_block_free_func_POPOVER; + handle = ui_popup_block_create( + C, NULL, NULL, NULL, ui_block_func_POPOVER, pup, ui_block_free_func_POPOVER); /* Add handlers. */ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index c4bcd7074d8..bd87439ca9e 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -748,7 +748,8 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, - void *arg) + void *arg, + void (*arg_free)(void *arg)) { wmWindow *window = CTX_wm_window(C); uiBut *activebut = UI_context_active_but_get(C); @@ -775,6 +776,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, handle->popup_create_vars.create_func = create_func; handle->popup_create_vars.handle_create_func = handle_create_func; handle->popup_create_vars.arg = arg; + handle->popup_create_vars.arg_free = arg_free; handle->popup_create_vars.but = but; handle->popup_create_vars.butregion = but ? butregion : NULL; copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x); @@ -820,8 +822,8 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle) } } - if (handle->popup_create_vars.free_func) { - handle->popup_create_vars.free_func(handle, handle->popup_create_vars.arg); + if (handle->popup_create_vars.arg_free) { + handle->popup_create_vars.arg_free(handle->popup_create_vars.arg); } ui_popup_block_remove(C, handle); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 4a9c7b689c1..5b205de21b8 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -891,11 +891,11 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) } gzop_actions[] = { { .part = gz->highlight_part, - .prefix = use_drag ? TIP_("Click") : NULL, + .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Click") : NULL, }, { .part = use_drag ? gz->drag_part : -1, - .prefix = use_drag ? TIP_("Drag") : NULL, + .prefix = use_drag ? CTX_TIP_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Drag") : NULL, }, }; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index e96141eaa05..33602818fd4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -298,7 +298,7 @@ static void template_ID_set_property_cb(bContext *C, void *arg_template, void *i PointerRNA idptr; RNA_id_pointer_create(item, &idptr); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } } @@ -489,7 +489,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_DELETE: memset(&idptr, 0, sizeof(idptr)); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); if (id && CTX_wm_window(C)->eventstate->shift) { @@ -532,7 +532,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); } } - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; @@ -541,7 +541,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) BKE_override_static_free(&id->override_static); /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; @@ -1455,7 +1455,7 @@ static void template_search_handle_cb(bContext *C, void *arg_template, void *ite PointerRNA item_ptr; RNA_pointer_create(NULL, type, item, &item_ptr); - RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr); + RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr, NULL); RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop); } @@ -4042,6 +4042,11 @@ static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_ return curvemap_tools_func(C, ar, cumap_v, false, UICURVE_FUNC_RESET_NEG); } +static uiBlock *curvemap_brush_tools_negslope_func(bContext *C, ARegion *ar, void *cumap_v) +{ + return curvemap_tools_func(C, ar, cumap_v, false, UICURVE_FUNC_RESET_POS); +} + static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) { ED_region_tag_redraw(CTX_wm_region(C)); @@ -4217,7 +4222,19 @@ static void curvemap_buttons_layout(uiLayout *layout, TIP_("Zoom out")); UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL); - if (brush) { + if (brush && neg_slope) { + bt = uiDefIconBlockBut(block, + curvemap_brush_tools_negslope_func, + cumap, + 0, + ICON_DOWNARROW_HLT, + 0, + 0, + dx, + dx, + TIP_("Tools")); + } + else if (brush) { bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, @@ -6744,12 +6761,17 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows) for (recent = G.recent_files.first, i = 0; (i < rows) && (recent); recent = recent->next, i++) { const char *filename = BLI_path_basename(recent->filepath); - uiItemStringO(layout, - filename, - BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, - "WM_OT_open_mainfile", - "filepath", - recent->filepath); + PointerRNA ptr; + uiItemFullO(layout, + "WM_OT_open_mainfile", + filename, + BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &ptr); + RNA_string_set(&ptr, "filepath", recent->filepath); + RNA_boolean_set(&ptr, "display_file_selector", false); } return i; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a9cd2f9cee1..e31646f9fdb 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1261,7 +1261,9 @@ void UI_widgetbase_draw_cache_flush(void) (float *)g_widget_base_batch.params); GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); GPU_matrix_bind(batch->interface); - GPU_batch_draw_range_ex(batch, 0, g_widget_base_batch.count, true); + GPU_batch_bind(batch); + GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count); + GPU_batch_program_use_end(batch); } g_widget_base_batch.count = 0; @@ -1421,7 +1423,7 @@ static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect) int x = rect->xmin + w / 2 - size / 2; int y = rect->ymin + h / 2 - size / 2; - UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size); + UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size); } } @@ -1450,7 +1452,7 @@ static void widget_draw_icon( return; } - aspect = but->block->aspect / UI_DPI_FAC; + aspect = but->block->aspect * U.inv_dpi_fac; height = ICON_DEFAULT_HEIGHT / aspect; /* calculate blend color */ @@ -1506,18 +1508,27 @@ static void widget_draw_icon( ys = (int)(ys + 0.1f); } + /* Get theme color. */ + char color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]}; + bool has_theme = UI_icon_get_theme_color(icon, (uchar *)color); + /* to indicate draggable */ if (but->dragpoin && (but->flag & UI_ACTIVE)) { - float rgb[3] = {1.25f, 1.25f, 1.25f}; - UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb, mono_color); + UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme); } - else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) || !UI_but_is_tool(but)) { - UI_icon_draw_aspect(xs, ys, icon, aspect, alpha, mono_color); + else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) { + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); + } + else if (!UI_but_is_tool(but)) { + if (has_theme) { + alpha *= 0.8f; + } + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme); } else { const bTheme *btheme = UI_GetTheme(); - UI_icon_draw_desaturate( - xs, ys, icon, aspect, alpha, 1.0 - btheme->tui.icon_saturation, mono_color); + const float desaturate = 1.0 - btheme->tui.icon_saturation; + UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme); } } @@ -1528,7 +1539,7 @@ static void widget_draw_submenu_tria(const uiBut *but, const rcti *rect, const uiWidgetColors *wcol) { - const float aspect = but->block->aspect / UI_DPI_FAC; + const float aspect = but->block->aspect * U.inv_dpi_fac; const int tria_height = (int)(ICON_DEFAULT_HEIGHT / aspect); const int tria_width = (int)(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize; const int xs = rect->xmax - tria_width; @@ -1584,7 +1595,8 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle, BLI_assert(str[0]); /* If the trailing ellipsis takes more than 20% of all available width, just cut the string - * (as using the ellipsis would remove even more useful chars, and we cannot show much already!). + * (as using the ellipsis would remove even more useful chars, and we cannot show much + * already!). */ if (sep_strwidth / okwidth > 0.2f) { l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp); @@ -1699,7 +1711,8 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle, /* Corner case, the str already takes all available mem, * and the ellipsis chars would actually add more chars. * Better to just trim one or two letters to the right in this case... - * Note: with a single-char ellipsis, this should never happen! But better be safe here... + * Note: with a single-char ellipsis, this should never happen! But better be safe + * here... */ ui_text_clip_right_ex( fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len); @@ -2346,7 +2359,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, const BIFIconID icon = widget_icon_id(but); int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT; - const float icon_size = icon_size_init / (but->block->aspect / UI_DPI_FAC); + const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac); const float icon_padding = 2 * UI_DPI_FAC; #ifdef USE_UI_TOOLBAR_HACK @@ -3494,8 +3507,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s wcol->item[3] = 255; if (horizontal) { - shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'l'); - shape_preset_init_scroll_circle(&wtb.tria2, slider, 0.6f, 'r'); + rcti slider_inset = *slider; + slider_inset.xmin += 0.05 * U.widget_unit; + slider_inset.xmax -= 0.05 * U.widget_unit; + shape_preset_init_scroll_circle(&wtb.tria1, &slider_inset, 0.6f, 'l'); + shape_preset_init_scroll_circle(&wtb.tria2, &slider_inset, 0.6f, 'r'); } else { shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'b'); @@ -4631,6 +4647,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct break; case UI_BTYPE_COLORBAND: + /* do not draw right to edge of rect */ + rect->xmin += (0.25f * UI_UNIT_X); + rect->xmax -= (0.3f * UI_UNIT_X); ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect); break; @@ -4655,6 +4674,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct break; case UI_BTYPE_CURVE: + /* do not draw right to edge of rect */ + rect->xmin += (0.2f * UI_UNIT_X); + rect->xmax -= (0.2f * UI_UNIT_X); ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect); break; @@ -5198,7 +5220,7 @@ void ui_draw_menu_item( GPU_blend(true); /* XXX scale weak get from fstyle? */ - UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f, wt->wcol.text); + UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); GPU_blend(false); } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 587cccf516c..06acf59e07c 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -309,6 +309,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_GRID: cp = ts->grid; break; + case TH_SCRUBBING_BACKGROUND: + cp = ts->scrubbing_background; + break; case TH_VIEW_OVERLAY: cp = ts->view_overlay; break; @@ -792,6 +795,22 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = ts->selected_highlight; break; + case TH_SELECTED_OBJECT: + cp = ts->selected_object; + break; + + case TH_ACTIVE_OBJECT: + cp = ts->active_object; + break; + + case TH_EDITED_OBJECT: + cp = ts->edited_object; + break; + + case TH_ROW_ALTERNATE: + cp = ts->row_alternate; + break; + case TH_SKIN_ROOT: cp = ts->skin_root; break; @@ -865,6 +884,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = btheme->tui.gizmo_b; break; + case TH_ICON_SCENE: + cp = btheme->tui.icon_scene; + break; case TH_ICON_COLLECTION: cp = btheme->tui.icon_collection; break; @@ -881,6 +903,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) cp = btheme->tui.icon_shading; break; + case TH_SCROLL_TEXT: + cp = btheme->tui.wcol_scroll.text; + break; + case TH_INFO_SELECTED: cp = ts->info_selected; break; @@ -1347,7 +1373,7 @@ void UI_GetThemeColorType4ubv(int colorid, int spacetype, uchar col[4]) col[3] = cp[3]; } -bool UI_GetIconThemeColor4fv(int colorid, float col[4]) +bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4]) { if (colorid == 0) { return false; @@ -1356,16 +1382,16 @@ bool UI_GetIconThemeColor4fv(int colorid, float col[4]) /* Only colored icons in outliner and popups, overall UI is intended * to stay monochrome and out of the way except a few places where it * is important to communicate different data types. */ - if (!((theme_spacetype == SPACE_OUTLINER) || (theme_regionid == RGN_TYPE_TEMPORARY))) { + if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || + (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { return false; } - const uchar *cp; - cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); - col[0] = ((float)cp[0]) / 255.0f; - col[1] = ((float)cp[1]) / 255.0f; - col[2] = ((float)cp[2]) / 255.0f; - col[3] = ((float)cp[3]) / 255.0f; + const uchar *cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + col[0] = cp[0]; + col[1] = cp[1]; + col[2] = cp[2]; + col[3] = cp[3]; return true; } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 58d26c4a840..f2d4faff479 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -138,7 +138,7 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr if (check_scrollers) { /* check size if hiding flag is set: */ if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) { + if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) { if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) { v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; } @@ -148,7 +148,7 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr } } if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) { + if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) { if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) { v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; } @@ -166,10 +166,11 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr * - if they overlap, they must not occupy the corners (which are reserved for other widgets) */ if (scroll) { - const int scroll_width = (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) ? V2D_SCROLL_WIDTH_TEXT : - V2D_SCROLL_WIDTH; - const int scroll_height = (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) ? - V2D_SCROLL_HEIGHT_TEXT : + const int scroll_width = (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) ? + V2D_SCROLL_WIDTH_HANDLES : + V2D_SCROLL_WIDTH; + const int scroll_height = (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ? + V2D_SCROLL_HEIGHT_HANDLES : V2D_SCROLL_HEIGHT; /* vertical scroller */ @@ -185,6 +186,13 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr v2d->vert.xmin = v2d->vert.xmax - scroll_width; } + /* Currently, all regions that have vertical scale handles, + * also have the scrubbing area at the top. + * So the scrollbar has to move down a bit. */ + if (scroll & V2D_SCROLL_VERTICAL_HANDLES) { + v2d->vert.ymax -= UI_SCRUBBING_MARGIN_Y; + } + /* horizontal scroller */ if (scroll & (V2D_SCROLL_BOTTOM)) { /* on bottom edge of region */ @@ -1589,7 +1597,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) * (workaround to make sure that button windows don't show these, * and only the time-grids with their zoomability can do so) */ - if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && + if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) && (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) { state |= UI_SCROLL_ARROWS; } @@ -1623,7 +1631,7 @@ void UI_view2d_scrollers_draw(View2D *v2d, View2DScrollers *vs) * (workaround to make sure that button windows don't show these, * and only the time-grids with their zoomability can do so) */ - if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && + if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) && (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) { state |= UI_SCROLL_ARROWS; } @@ -1644,59 +1652,6 @@ void UI_view2d_scrollers_free(View2DScrollers *scrollers) /* *********************************************************************** */ /* List View Utilities */ -/** Get the view-coordinates of the nominated cell - * - * \param columnwidth, rowheight: size of each 'cell' - * \param startx, starty: coordinates (in 'tot' rect space) that the list starts from. - * This should be (0,0) for most views. However, for those where the starting row was offsetted - * (like for Animation Editor channel lists, to make the first entry more visible), these will be - * the min-coordinates of the first item. - * \param column, row: The 2d-coordinates - * (in 2D-view / 'tot' rect space) the cell exists at - * \param rect: coordinates of the cell - * (passed as single var instead of 4 separate, as it's more useful this way) - */ -void UI_view2d_listview_cell_to_view(View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int column, - int row, - rctf *rect) -{ - /* sanity checks */ - if (ELEM(NULL, v2d, rect)) { - return; - } - - if ((columnwidth <= 0) && (rowheight <= 0)) { - rect->xmin = rect->xmax = 0.0f; - rect->ymin = rect->ymax = 0.0f; - return; - } - - /* x-coordinates */ - rect->xmin = startx + (float)(columnwidth * column); - rect->xmax = startx + (float)(columnwidth * (column + 1)); - - if ((v2d->align & V2D_ALIGN_NO_POS_X) && !(v2d->align & V2D_ALIGN_NO_NEG_X)) { - /* simply negate the values for the coordinates if in negative half */ - rect->xmin = -rect->xmin; - rect->xmax = -rect->xmax; - } - - /* y-coordinates */ - rect->ymin = starty + (float)(rowheight * row); - rect->ymax = starty + (float)(rowheight * (row + 1)); - - if ((v2d->align & V2D_ALIGN_NO_POS_Y) && !(v2d->align & V2D_ALIGN_NO_NEG_Y)) { - /* simply negate the values for the coordinates if in negative half */ - rect->ymin = -rect->ymin; - rect->ymax = -rect->ymax; - } -} - /** * Get the 'cell' (row, column) that the given 2D-view coordinates * (i.e. in 'tot' rect space) lie in. @@ -1709,8 +1664,7 @@ void UI_view2d_listview_cell_to_view(View2D *v2d, * \param viewx, viewy: 2D-coordinates (in 2D-view / 'tot' rect space) to get the cell for * \param r_column, r_row: the 'coordinates' of the relevant 'cell' */ -void UI_view2d_listview_view_to_cell(View2D *v2d, - float columnwidth, +void UI_view2d_listview_view_to_cell(float columnwidth, float rowheight, float startx, float starty, @@ -1719,80 +1673,24 @@ void UI_view2d_listview_view_to_cell(View2D *v2d, int *r_column, int *r_row) { - /* adjust view coordinates to be all positive ints, corrected for the start offset */ - const int x = (int)(floorf(fabsf(viewx) + 0.5f) - startx); - const int y = (int)(floorf(fabsf(viewy) + 0.5f) - starty); - - /* sizes must not be negative */ - if ((v2d == NULL) || ((columnwidth <= 0) && (rowheight <= 0))) { - if (r_column) { - *r_column = 0; + if (r_column) { + if (columnwidth > 0) { + /* Columns go from left to right (x increases). */ + *r_column = floorf((viewx - startx) / columnwidth); } - if (r_row) { - *r_row = 0; + else { + *r_column = 0; } - - return; - } - - /* get column */ - if ((r_column) && (columnwidth > 0)) { - *r_column = x / columnwidth; - } - else if (r_column) { - *r_column = 0; } - /* get row */ - if ((r_row) && (rowheight > 0)) { - *r_row = y / rowheight; - } - else if (r_row) { - *r_row = 0; - } -} - -/** - * Get the 'extreme' (min/max) column and row indices which are visible within the 'cur' rect - * - * \param columnwidth, rowheight: Size of each 'cell' - * \param startx, starty: Coordinates that the list starts from, - * which should be (0,0) for most views. - * \param column_min, column_max, row_min, row_max: The starting and ending column/row indices - */ -void UI_view2d_listview_visible_cells(View2D *v2d, - float columnwidth, - float rowheight, - float startx, - float starty, - int *column_min, - int *column_max, - int *row_min, - int *row_max) -{ - /* using 'cur' rect coordinates, call the cell-getting function to get the cells for this */ - if (v2d) { - /* min */ - UI_view2d_listview_view_to_cell(v2d, - columnwidth, - rowheight, - startx, - starty, - v2d->cur.xmin, - v2d->cur.ymin, - column_min, - row_min); - - /* max*/ - UI_view2d_listview_view_to_cell(v2d, - columnwidth, - rowheight, - startx, - starty, - v2d->cur.xmax, - v2d->cur.ymax, - column_max, - row_max); + if (r_row) { + if (rowheight > 0) { + /* Rows got from top to bottom (y decreases). */ + *r_row = floorf((starty - viewy) / rowheight); + } + else { + *r_row = 0; + } } } diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c index 91128e49a60..2009bbecebc 100644 --- a/source/blender/editors/interface/view2d_draw.c +++ b/source/blender/editors/interface/view2d_draw.c @@ -53,7 +53,7 @@ /* Compute display grid resolution ********************************************************/ -#define MIN_MAJOR_LINE_DISTANCE (UI_DPI_FAC * 50) +#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_DPI_FAC) static float select_major_distance(const float *possible_distances, uint amount, @@ -153,6 +153,12 @@ static void get_parallel_lines_draw_steps(const ParallelLinesSet *lines, float *r_first, uint *r_steps) { + if (region_start >= region_end) { + *r_first = 0; + *r_steps = 0; + return; + } + BLI_assert(lines->distance > 0); BLI_assert(region_start <= region_end); @@ -258,7 +264,8 @@ static void draw_horizontal_scale_indicators(const ARegion *ar, float distance, const rcti *rect, PositionToString to_string, - void *to_string_data) + void *to_string_data, + int colorid) { GPU_matrix_push_projection(); wmOrtho2_region_pixelspace(ar); @@ -277,7 +284,7 @@ static void draw_horizontal_scale_indicators(const ARegion *ar, } const int font_id = BLF_default(); - UI_FontThemeColor(font_id, TH_TEXT); + UI_FontThemeColor(font_id, colorid); BLF_batch_draw_begin(); @@ -308,7 +315,8 @@ static void draw_vertical_scale_indicators(const ARegion *ar, float display_offset, const rcti *rect, PositionToString to_string, - void *to_string_data) + void *to_string_data, + int colorid) { GPU_matrix_push_projection(); wmOrtho2_region_pixelspace(ar); @@ -327,7 +335,7 @@ static void draw_vertical_scale_indicators(const ARegion *ar, } const int font_id = BLF_default(); - UI_FontThemeColor(font_id, TH_TEXT); + UI_FontThemeColor(font_id, colorid); BLF_enable(font_id, BLF_ROTATION); BLF_rotation(font_id, M_PI_2); @@ -463,51 +471,62 @@ void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d, /* Scale indicator text drawing API **************************************************/ -void UI_view2d_draw_scale_x__discrete_values(const ARegion *ar, - const View2D *v2d, - const rcti *rect) +static void UI_view2d_draw_scale_x__discrete_values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float number_step = view2d_major_step_x__discrete(v2d); - draw_horizontal_scale_indicators(ar, v2d, number_step, rect, view_to_string__frame_number, NULL); + draw_horizontal_scale_indicators( + ar, v2d, number_step, rect, view_to_string__frame_number, NULL, colorid); } -void UI_view2d_draw_scale_x__discrete_time(const ARegion *ar, - const View2D *v2d, - const rcti *rect, - const Scene *scene) +static void UI_view2d_draw_scale_x__discrete_time( + const ARegion *ar, const View2D *v2d, const rcti *rect, const Scene *scene, int colorid) { float step = view2d_major_step_x__time(v2d, scene); - draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__time, (void *)scene); + draw_horizontal_scale_indicators( + ar, v2d, step, rect, view_to_string__time, (void *)scene, colorid); } -void UI_view2d_draw_scale_x__values(const ARegion *ar, const View2D *v2d, const rcti *rect) +static void UI_view2d_draw_scale_x__values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float step = view2d_major_step_x__continuous(v2d); - draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__value, NULL); + draw_horizontal_scale_indicators(ar, v2d, step, rect, view_to_string__value, NULL, colorid); } -void UI_view2d_draw_scale_y__values(const ARegion *ar, const View2D *v2d, const rcti *rect) +void UI_view2d_draw_scale_y__values(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { float step = view2d_major_step_y__continuous(v2d); - draw_vertical_scale_indicators(ar, v2d, step, 0.0f, rect, view_to_string__value, NULL); + draw_vertical_scale_indicators(ar, v2d, step, 0.0f, rect, view_to_string__value, NULL, colorid); } -void UI_view2d_draw_scale_y__block(const ARegion *ar, const View2D *v2d, const rcti *rect) +void UI_view2d_draw_scale_y__block(const ARegion *ar, + const View2D *v2d, + const rcti *rect, + int colorid) { - draw_vertical_scale_indicators(ar, v2d, 1.0f, 0.5f, rect, view_to_string__value, NULL); + draw_vertical_scale_indicators(ar, v2d, 1.0f, 0.5f, rect, view_to_string__value, NULL, colorid); } void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds) + bool display_seconds, + int colorid) { if (display_seconds) { - UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene); + UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene, colorid); } else { - UI_view2d_draw_scale_x__discrete_values(ar, v2d, rect); + UI_view2d_draw_scale_x__discrete_values(ar, v2d, rect, colorid); } } @@ -515,12 +534,13 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *ar, const struct View2D *v2d, const struct rcti *rect, const struct Scene *scene, - bool display_seconds) + bool display_seconds, + int colorid) { if (display_seconds) { - UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene); + UI_view2d_draw_scale_x__discrete_time(ar, v2d, rect, scene, colorid); } else { - UI_view2d_draw_scale_x__values(ar, v2d, rect); + UI_view2d_draw_scale_x__values(ar, v2d, rect, colorid); } } diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index ab8d1cf9bf6..68ee38bc99f 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -2032,8 +2032,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * * NOTE: see view2d.c for latest conditions, and keep this in sync with that */ if (ELEM(vsm->zone, SCROLLHANDLE_MIN, SCROLLHANDLE_MAX)) { - if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0) || - ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) { + if (((vsm->scroller == 'h') && (v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0) || + ((vsm->scroller == 'v') && (v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) { /* switch to bar (i.e. no scaling gets handled) */ vsm->zone = SCROLLHANDLE_BAR; } diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 3dd3b20bda3..9fdcec71cfd 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -108,7 +108,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op) PointerRNA idptr; RNA_id_pointer_create(&cache_file->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index c0f3b1f8338..1f825c0bb31 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -1992,9 +1992,9 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *op) for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - if (masklay->restrictflag & OB_RESTRICT_VIEW) { + if (masklay->restrictflag & OB_RESTRICT_VIEWPORT) { ED_mask_layer_select_set(masklay, select); - masklay->restrictflag &= ~OB_RESTRICT_VIEW; + masklay->restrictflag &= ~OB_RESTRICT_VIEWPORT; changed = true; } } @@ -2045,7 +2045,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op) if (ED_mask_layer_select_check(masklay)) { ED_mask_layer_select_set(masklay, false); - masklay->restrictflag |= OB_RESTRICT_VIEW; + masklay->restrictflag |= OB_RESTRICT_VIEWPORT; changed = true; if (masklay == BKE_mask_layer_active(mask)) { BKE_mask_layer_active_set(mask, NULL); @@ -2054,7 +2054,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op) } else { if (!ED_mask_layer_select_check(masklay)) { - masklay->restrictflag |= OB_RESTRICT_VIEW; + masklay->restrictflag |= OB_RESTRICT_VIEWPORT; changed = true; if (masklay == BKE_mask_layer_active(mask)) { BKE_mask_layer_active_set(mask, NULL); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 57bf67e825e..9a779db4812 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../../blentranslation ../../bmesh ../../depsgraph + ../../draw ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 990250792a1..d61c340f7a2 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -441,74 +441,6 @@ bool paintface_mouse_select( return true; } -bool do_paintface_box_select(ViewContext *vc, const rcti *rect, int sel_op) -{ - Object *ob = vc->obact; - Mesh *me; - - me = BKE_mesh_from_object(ob); - if ((me == NULL) || (me->totpoly == 0)) { - return false; - } - - bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); - } - - if (BLI_rcti_is_empty(rect)) { - /* pass */ - } - else { - MPoly *mpoly; - uint *rt; - int a, index; - - char *selar = MEM_callocN(me->totpoly + 1, "selar"); - - uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); - - rt = buf; - - a = buf_len; - while (a--) { - if (*rt) { - index = *rt; - if (index <= me->totpoly) { - selar[index] = 1; - } - } - rt++; - } - - mpoly = me->mpoly; - for (a = 1; a <= me->totpoly; a++, mpoly++) { - if ((mpoly->flag & ME_HIDE) == 0) { - const bool is_select = mpoly->flag & ME_FACE_SEL; - const bool is_inside = (selar[a] != 0); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); - changed = true; - } - } - } - - MEM_freeN(buf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif - } - - if (changed) { - paintface_flush_flags(vc->C, vc->obact, SELECT); - } - return changed; -} - /* (similar to void paintface_flush_flags(Object *ob)) * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting vertices (while painting) */ diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index 839ee186016..f6729fb56e1 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -29,6 +29,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_scene.h" #include "ED_gizmo_library.h" #include "ED_gizmo_utils.h" @@ -75,7 +76,7 @@ static void calc_initial_placement_point_from_view(bContext *C, float cursor_matrix[4][4]; float orient_matrix[3][3]; - ED_view3d_cursor3d_calc_mat4(scene, cursor_matrix); + BKE_scene_cursor_to_mat4(&scene->cursor, cursor_matrix); float dots[3] = { dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index f6940cae953..1cd4e95314b 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -907,7 +907,8 @@ void MESH_OT_bevel(wmOperatorType *ot) /* identifiers */ ot->name = "Bevel"; - ot->description = "Edge Bevel"; + ot->description = + "Cut into selected items at an angle to create flat or rounded bevel or chamfer"; ot->idname = "MESH_OT_bevel"; /* api callbacks */ diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index bc60ff9274f..1d173d8e396 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -148,7 +148,7 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) BisectData *opdata; opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); - gesture->userdata = opdata; + gesture->user_data.data = opdata; opdata->backup_len = objects_len; opdata->backup = MEM_callocN(sizeof(*opdata->backup) * objects_len, __func__); @@ -193,7 +193,7 @@ static void edbm_bisect_exit(bContext *C, BisectData *opdata) static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; - BisectData *opdata = gesture->userdata; + BisectData *opdata = gesture->user_data.data; BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ int ret; @@ -276,7 +276,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) } wmGesture *gesture = op->customdata; - BisectData *opdata = (gesture != NULL) ? gesture->userdata : NULL; + BisectData *opdata = (gesture != NULL) ? gesture->user_data.data : NULL; /* -------------------------------------------------------------------- */ /* Modal support */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 82cff8363f8..0da4d20c6b5 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -36,6 +36,7 @@ #include "RNA_access.h" #include "WM_types.h" +#include "WM_api.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -860,6 +861,9 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w EDBM_mesh_normals_update(vc.em); EDBM_update_generic(vc.em, true, true); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index cc0c2f5bbe4..976dbe01a22 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1156,19 +1156,20 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + GPU_batch_bind(batch); /* draw any snapped verts first */ rgba_uchar_to_float(fcol, kcd->colors.point_a); GPU_batch_uniform_4fv(batch, "color", fcol); GPU_matrix_bind(batch->interface); GPU_point_size(11); - GPU_batch_draw_range_ex(batch, 0, v - 1, false); + GPU_batch_draw_advanced(batch, 0, v - 1, 0, 0); /* now draw the rest */ rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); GPU_batch_uniform_4fv(batch, "color", fcol); GPU_point_size(7); - GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); + GPU_batch_draw_advanced(batch, vs + 1, kcd->totlinehit - (vs + 1), 0, 0); GPU_batch_program_use_end(batch); GPU_batch_discard(batch); @@ -2811,6 +2812,7 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, + {KNF_MODAL_ADD_CUT_CLOSED, "ADD_CUT_CLOSED", 0, "Add Cut Closed", ""}, {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 528235e693a..59355890428 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -79,11 +79,11 @@ typedef struct RingSelOpData { Depsgraph *depsgraph; - Object **objects; - uint objects_len; + Base **bases; + uint bases_len; /* These values switch objects based on the object under the cursor. */ - uint ob_index; + uint base_index; Object *ob; BMEditMesh *em; BMEdge *eed; @@ -111,8 +111,8 @@ static void edgering_select(RingSelOpData *lcd) } if (!lcd->extend) { - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; + for (uint base_index = 0; base_index < lcd->bases_len; base_index++) { + Object *ob_iter = lcd->bases[base_index]->object; BMEditMesh *em = BKE_editmesh_from_object(ob_iter); EDBM_flag_disable_all(em, BM_ELEM_SELECT); DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); @@ -252,7 +252,7 @@ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) EDBM_preselect_edgering_destroy(lcd->presel_edgering); - MEM_freeN(lcd->objects); + MEM_freeN(lcd->bases); ED_region_tag_redraw(lcd->ar); @@ -307,21 +307,21 @@ static void ringcut_cancel(bContext *C, wmOperator *op) } static void loopcut_update_edge(RingSelOpData *lcd, - uint ob_index, + uint base_index, BMEdge *e, const int previewlines) { if (e != lcd->eed) { lcd->eed = e; lcd->ob = lcd->vc.obedit; - lcd->ob_index = ob_index; + lcd->base_index = base_index; lcd->em = lcd->vc.em; ringsel_find_edge(lcd, previewlines); } else if (e == NULL) { lcd->ob = NULL; lcd->em = NULL; - lcd->ob_index = UINT_MAX; + lcd->base_index = UINT_MAX; } } @@ -331,27 +331,26 @@ static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) Object *ob; BMEdge *eed; float dist; - int ob_index; + int base_index; } best = { .dist = ED_view3d_select_dist_px(), }; - for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { - Object *ob_iter = lcd->objects[ob_index]; - ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); - BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL); - if (eed_test) { - best.ob = ob_iter; - best.eed = eed_test; - best.ob_index = ob_index; - } + uint base_index; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + &lcd->vc, &best.dist, NULL, false, false, NULL, lcd->bases, lcd->bases_len, &base_index); + + if (eed_test) { + best.ob = lcd->bases[base_index]->object; + best.eed = eed_test; + best.base_index = base_index; } if (best.eed) { ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); } - loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines); + loopcut_update_edge(lcd, best.base_index, best.eed, previewlines); } /* called by both init() and exec() */ @@ -361,22 +360,22 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) /* Use for redo - intentionally wrap int to uint. */ const struct { - uint ob_index; + uint base_index; uint e_index; } exec_data = { - .ob_index = (uint)RNA_int_get(op->ptr, "object_index"), + .base_index = (uint)RNA_int_get(op->ptr, "object_index"), .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), }; ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( - view_layer, CTX_wm_view3d(C), &objects_len); + uint bases_len; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( + view_layer, CTX_wm_view3d(C), &bases_len); if (is_interactive) { - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; + for (uint base_index = 0; base_index < bases_len; base_index++) { + Object *ob_iter = bases[base_index]->object; if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { BKE_report( op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); @@ -390,12 +389,12 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) /* for re-execution, check edge index is in range before we setup ringsel */ bool ok = true; if (is_interactive == false) { - if (exec_data.ob_index >= objects_len) { + if (exec_data.base_index >= bases_len) { return OPERATOR_CANCELLED; ok = false; } else { - Object *ob_iter = objects[exec_data.ob_index]; + Object *ob_iter = bases[exec_data.base_index]->object; BMEditMesh *em = BKE_editmesh_from_object(ob_iter); if (exec_data.e_index >= em->bm->totedge) { ok = false; @@ -404,7 +403,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) } if (!ok || !ringsel_init(C, op, true)) { - MEM_freeN(objects); + MEM_freeN(bases); return OPERATOR_CANCELLED; } @@ -416,8 +415,8 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) RingSelOpData *lcd = op->customdata; - lcd->objects = objects; - lcd->objects_len = objects_len; + lcd->bases = bases; + lcd->bases_len = bases_len; if (is_interactive) { copy_v2_v2_int(lcd->vc.mval, event->mval); @@ -425,13 +424,13 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) } else { - Object *ob_iter = objects[exec_data.ob_index]; + Object *ob_iter = bases[exec_data.base_index]->object; ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); BMEdge *e; BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); - loopcut_update_edge(lcd, exec_data.ob_index, e, 0); + loopcut_update_edge(lcd, exec_data.base_index, e, 0); } #ifdef USE_LOOPSLIDE_HACK @@ -503,7 +502,7 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op) if (lcd->eed) { /* set for redo */ BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); - RNA_int_set(op->ptr, "object_index", lcd->ob_index); + RNA_int_set(op->ptr, "object_index", lcd->base_index); RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); /* execute */ diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index f8ec4334427..6fd0ee83b6c 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -63,6 +63,15 @@ /** \name Path Select Struct & Properties * \{ */ +enum { + EDGE_MODE_SELECT = 0, + EDGE_MODE_TAG_SEAM = 1, + EDGE_MODE_TAG_SHARP = 2, + EDGE_MODE_TAG_CREASE = 3, + EDGE_MODE_TAG_BEVEL = 4, + EDGE_MODE_TAG_FREESTYLE = 5, +}; + struct PathSelectParams { /** ensure the active element is the last selected item (handy for picking) */ bool track_active; @@ -75,6 +84,23 @@ struct PathSelectParams { static void path_select_properties(wmOperatorType *ot) { + static const EnumPropertyItem edge_tag_items[] = { + {EDGE_MODE_SELECT, "SELECT", 0, "Select", ""}, + {EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""}, + {EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""}, + {EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""}, + {EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""}, + {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_enum(ot->srna, + "edge_mode", + edge_tag_items, + EDGE_MODE_SELECT, + "Edge Tag", + "The edge flag to tag when selecting the shortest path"); + RNA_def_boolean(ot->srna, "use_face_step", false, @@ -93,9 +119,24 @@ static void path_select_properties(wmOperatorType *ot) WM_operator_properties_checker_interval(ot, true); } -static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params) +static void path_select_params_from_op(wmOperator *op, + ToolSettings *ts, + struct PathSelectParams *op_params) { - op_params->edge_mode = EDGE_MODE_SELECT; + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "edge_mode"); + if (RNA_property_is_set(op->ptr, prop)) { + op_params->edge_mode = RNA_property_enum_get(op->ptr, prop); + if (op->flag & OP_IS_INVOKE) { + ts->edge_mode = op_params->edge_mode; + } + } + else { + op_params->edge_mode = ts->edge_mode; + RNA_property_enum_set(op->ptr, prop, op_params->edge_mode); + } + } + op_params->track_active = false; op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step"); op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill"); @@ -103,6 +144,21 @@ static void path_select_params_from_op(wmOperator *op, struct PathSelectParams * WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params); } +static bool path_select_poll_property(const bContext *C, + wmOperator *UNUSED(op), + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + if (STREQ(prop_id, "edge_mode")) { + const Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + if ((ts->selectmode & SCE_SELECT_EDGE) == 0) { + return false; + } + } + return true; +} + struct UserData { BMesh *bm; Mesh *me; @@ -319,7 +375,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) /* mesh shortest path select, uses prev-selected edge */ /* since you want to create paths with multiple selects, it doesn't have extend option */ -static void mouse_mesh_shortest_path_edge(Scene *UNUSED(scene), +static void mouse_mesh_shortest_path_edge(Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMEdge *e_act, @@ -421,6 +477,10 @@ static void mouse_mesh_shortest_path_edge(Scene *UNUSED(scene), } EDBM_update_generic(em, false, false); + + if (op_params->edge_mode == EDGE_MODE_TAG_SEAM) { + ED_uvedit_live_unwrap(scene, &obedit, 1); + } } /** \} */ @@ -649,12 +709,14 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE return OPERATOR_FINISHED; } + struct PathSelectParams op_params; + path_select_params_from_op(op, vc.scene->toolsettings, &op_params); + BMElem *ele_src, *ele_dst; if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) || !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) { /* special case, toggle edge tags even when we don't have a path */ - if (((em->selectmode & SCE_SELECT_EDGE) && - (vc.scene->toolsettings->edge_mode != EDGE_MODE_SELECT)) && + if (((em->selectmode & SCE_SELECT_EDGE) && (op_params.edge_mode != EDGE_MODE_SELECT)) && /* check if we only have a destination edge */ ((ele_src == NULL) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) { ele_src = ele_dst; @@ -665,11 +727,7 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE } } - struct PathSelectParams op_params; - - path_select_params_from_op(op, &op_params); op_params.track_active = track_active; - op_params.edge_mode = vc.scene->toolsettings->edge_mode; if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_PASS_THROUGH; @@ -707,9 +765,8 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op) } struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); + path_select_params_from_op(op, scene->toolsettings, &op_params); op_params.track_active = true; - op_params.edge_mode = scene->toolsettings->edge_mode; if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) { return OPERATOR_CANCELLED; @@ -731,6 +788,7 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) ot->invoke = edbm_shortest_path_pick_invoke; ot->exec = edbm_shortest_path_pick_exec; ot->poll = ED_operator_editmesh_region_view3d; + ot->poll_property = path_select_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -832,7 +890,7 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) if (ele_src && ele_dst) { struct PathSelectParams op_params; - path_select_params_from_op(op, &op_params); + path_select_params_from_op(op, scene->toolsettings, &op_params); edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst); @@ -860,6 +918,7 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_shortest_path_select_exec; ot->poll = ED_operator_editmesh; + ot->poll_property = path_select_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 9df03a81762..dc94219cb9a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -53,6 +53,7 @@ #include "ED_mesh.h" #include "ED_screen.h" #include "ED_transform.h" +#include "ED_select_buffer_utils.h" #include "ED_select_utils.h" #include "ED_view3d.h" @@ -67,6 +68,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "DRW_engine.h" + #include "mesh_intern.h" /* own include */ /* use bmesh operator flags for a few operators */ @@ -196,186 +199,171 @@ void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag) /** \name Back-Buffer OpenGL Selection * \{ */ -/* set in drawobject.c ... for colorindices */ -unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; - -/* facilities for box select and circle select */ -static BLI_bitmap *selbuf = NULL; +struct EDBMBaseOffset { + /* For convenience only. */ + union { + uint offset; + uint face_start; + }; + union { + uint face; + uint edge_start; + }; + union { + uint edge; + uint vert_start; + }; + uint vert; +}; -static BLI_bitmap *edbm_backbuf_alloc(const int size) -{ - return BLI_BITMAP_NEW(size, "selbuf"); -} +struct EDBMSelectID_Context { + struct EDBMBaseOffset *base_array_index_offsets; + /** Borrow from caller (not freed). */ + struct Base **bases; + uint bases_len; + /** Total number of items `base_array_index_offsets[bases_len - 1].vert`. */ + uint base_array_index_len; +}; -/* reads rect, and builds selection array for quick lookup */ -/* returns if all is OK */ -bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) +static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, char dt) { - uint *buf, *dr, buf_len; - - if (vc->obedit == NULL || XRAY_FLAG_ENABLED(vc->v3d)) { - return false; - } - - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; - } - - dr = buf; - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); + if (select_mode & SCE_SELECT_FACE) { + if (dt < OB_SOLID) { + return true; + } + if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) { + return true; + } + if (XRAY_FLAG_ENABLED(v3d)) { + return true; } - dr++; } - MEM_freeN(buf); - return true; + return false; } -bool EDBM_backbuf_check(unsigned int index) +static void edbm_select_pick_draw_bases(struct EDBMSelectID_Context *sel_id_ctx, + ViewContext *vc, + short select_mode) { - /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled - * and just ignore the depth buffer, this is error prone since its possible - * code doesn't set the depth buffer by accident, but leave for now. - Campbell */ - if (selbuf == NULL) { - return true; - } + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(vc->depsgraph, &vc->scene->id); + DRW_framebuffer_select_id_setup(vc->ar, true); - if (index > 0 && index <= bm_vertoffs) { - return BLI_BITMAP_TEST_BOOL(selbuf, index); - } + uint offset = 1; + for (uint base_index = 0; base_index < sel_id_ctx->bases_len; base_index++) { + Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, + sel_id_ctx->bases[base_index]->object); - return false; -} + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + bool draw_facedot = check_ob_drawface_dot(select_mode, vc->v3d, ob_eval->dt); -void EDBM_backbuf_free(void) -{ - if (selbuf) { - MEM_freeN(selbuf); + DRW_draw_select_id_object(scene_eval, + vc->rv3d, + ob_eval, + select_mode, + draw_facedot, + offset, + &base_ofs->vert, + &base_ofs->edge, + &base_ofs->face); + + base_ofs->offset = offset; + offset = base_ofs->vert; } - selbuf = NULL; -} -struct LassoMaskData { - unsigned int *px; - int width; -}; + sel_id_ctx->base_array_index_len = offset; -static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data) -{ - struct LassoMaskData *data = user_data; - unsigned int *px = &data->px[(y * data->width) + x]; - do { - *px = true; - px++; - } while (++x != x_end); + DRW_framebuffer_select_id_release(vc->ar); } -/* mcords is a polygon mask - * - grab backbuffer, - * - draw with black in backbuffer, - * - grab again and compare - * returns 'OK' - */ -bool EDBM_backbuf_border_mask_init(ViewContext *vc, - const int mcords[][2], - short tot, - short xmin, - short ymin, - short xmax, - short ymax) +BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ctx, + const uint sel_id, + uint *r_base_index) { - uint *buf, *dr, *dr_mask, *dr_mask_arr, buf_len; - struct LassoMaskData lasso_mask_data; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; + char elem_type; + uint elem_id; + uint base_index = 0; + for (; base_index < sel_id_ctx->bases_len; base_index++) { + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + if (base_ofs->face > sel_id) { + elem_id = sel_id - base_ofs->face_start; + elem_type = BM_FACE; + break; + } + if (base_ofs->edge > sel_id) { + elem_id = sel_id - base_ofs->edge_start; + elem_type = BM_EDGE; + break; + } + if (base_ofs->vert > sel_id) { + elem_id = sel_id - base_ofs->vert_start; + elem_type = BM_VERT; + break; } - } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; } - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, &buf_len); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; + if (r_base_index) { + *r_base_index = base_index; } - dr = buf; - - dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf_len, __func__); - lasso_mask_data.px = dr_mask; - lasso_mask_data.width = (xmax - xmin) + 1; - - BLI_bitmap_draw_2d_poly_v2i_n( - xmin, ymin, xmax + 1, ymax + 1, mcords, tot, edbm_mask_lasso_px_cb, &lasso_mask_data); - - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); + Object *obedit = sel_id_ctx->bases[base_index]->object; + BMEditMesh *em = BKE_editmesh_from_object(obedit); - while (buf_len--) { - if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - dr++; - dr_mask++; + switch (elem_type) { + case BM_FACE: + return (BMElem *)BM_face_at_index_find_or_table(em->bm, elem_id); + case BM_EDGE: + return (BMElem *)BM_edge_at_index_find_or_table(em->bm, elem_id); + case BM_VERT: + return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id); + default: + BLI_assert(0); + return NULL; } - MEM_freeN(buf); - MEM_freeN(dr_mask_arr); - - return true; } -/* circle shaped sample area */ -bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) +uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx, + int base_index, + char htype) { - uint *buf, *dr; - short xmin, ymin, xmax, ymax, xc, yc; - int radsq; - - /* method in use for face selecting too */ - if (vc->obedit == NULL) { - if (!BKE_paint_select_elem_test(vc->obact)) { - return false; - } + struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index]; + if (htype == BM_VERT) { + return base_ofs->vert_start - 1; } - else if (XRAY_FLAG_ENABLED(vc->v3d)) { - return false; + if (htype == BM_EDGE) { + return base_ofs->edge_start - 1; } - - xmin = xs - rads; - xmax = xs + rads; - ymin = ys - rads; - ymax = ys + rads; - buf = ED_view3d_select_id_read(vc, xmin, ymin, xmax, ymax, NULL); - if ((buf == NULL) || (bm_vertoffs == 0)) { - return false; + if (htype == BM_FACE) { + return base_ofs->face_start - 1; } + BLI_assert(0); + return 0; +} - dr = buf; +uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx) +{ + return sel_id_ctx->base_array_index_len; +} - /* build selection lookup */ - selbuf = edbm_backbuf_alloc(bm_vertoffs + 1); - radsq = rads * rads; - for (yc = -rads; yc <= rads; yc++) { - for (xc = -rads; xc <= rads; xc++, dr++) { - if (xc * xc + yc * yc < radsq) { - if (*dr > 0 && *dr <= bm_vertoffs) { - BLI_BITMAP_ENABLE(selbuf, *dr); - } - } - } - } +struct EDBMSelectID_Context *EDBM_select_id_context_create(ViewContext *vc, + Base **bases, + uint bases_len, + short select_mode) +{ + struct EDBMSelectID_Context *sel_id_ctx = MEM_mallocN(sizeof(*sel_id_ctx), __func__); + sel_id_ctx->base_array_index_offsets = MEM_mallocN(sizeof(struct EDBMBaseOffset) * bases_len, + __func__); + sel_id_ctx->bases = bases; + sel_id_ctx->bases_len = bases_len; - MEM_freeN(buf); - return true; + edbm_select_pick_draw_bases(sel_id_ctx, vc, select_mode); + + return sel_id_ctx; +} + +void EDBM_select_id_context_destroy(struct EDBMSelectID_Context *sel_id_ctx) +{ + MEM_freeN(sel_id_ctx->base_array_index_offsets); + MEM_freeN(sel_id_ctx); } /** \} */ @@ -470,29 +458,44 @@ static void findnearestvert__doClosest(void *userData, BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, float *r_dist, const bool use_select_bias, - bool use_cycle) + bool use_cycle, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; + uint index; BMVert *eve; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px); + + if (index) { + eve = (BMVert *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + eve = NULL; + } - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_wireoffs, 0xFFFFFF, &dist_px); - eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } if (eve) { if (dist_px < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_px; return eve; } @@ -503,32 +506,52 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, struct NearestVertUserData data = {{0}}; const struct NearestVertUserData_Hit *hit; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMVert *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_vert_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMVert *elem; + const BMesh *bm; + } prev_select = {0}; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_vert_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } - hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; - prev_select_elem = hit->vert; - prev_select_index = hit->index; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } + + prev_select.index = hit->index; + prev_select.elem = hit->vert; + prev_select.bm = prev_select_bm; return hit->vert; } @@ -536,7 +559,8 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_vert_find_nearest_ex(vc, r_dist, false, false); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_vert_find_nearest_ex(vc, r_dist, false, false, &base, 1, NULL); } /* find the distance to the edge we already have */ @@ -658,24 +682,36 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - BMEdge **r_eed_zbuf) + bool use_cycle, + BMEdge **r_eed_zbuf, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->ar, *r_dist); - unsigned int index; + uint index; BMEdge *eed; /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_EDGE) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_find_nearest_to_point(vc->mval, 1, UINT_MAX, &dist_px); + + if (index) { + eed = (BMEdge *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + eed = NULL; + } - index = ED_view3d_select_id_read_nearest(vc, vc->mval, bm_solidoffs, bm_wireoffs, &dist_px); - eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } @@ -704,6 +740,9 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, if (eed) { if (dist_px < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_px; return eed; } @@ -715,36 +754,57 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, const struct NearestEdgeUserData_Hit *hit; /* interpolate along the edge before doing a clipping plane test */ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMEdge *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_edge_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMEdge *elem; + const BMesh *bm; + } prev_select = {0}; data.vc = *vc; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_edge_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } + + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } - hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; if (r_dist_center) { *r_dist_center = hit->dist_center; } - prev_select_elem = hit->edge; - prev_select_index = hit->index; + prev_select.index = hit->index; + prev_select.elem = hit->edge; + prev_select.bm = prev_select_bm; return hit->edge; } @@ -752,7 +812,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); } /* find the distance to the face we already have */ @@ -831,23 +892,35 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, float *r_dist, float *r_dist_center, const bool use_select_bias, - const bool use_cycle, - BMFace **r_efa_zbuf) + bool use_cycle, + BMFace **r_efa_zbuf, + Base **bases, + uint bases_len, + uint *r_base_index) { - BMesh *bm = vc->em->bm; + uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { float dist_test = 0.0f; - unsigned int index; + uint index; BMFace *efa; { - FAKE_SELECT_MODE_BEGIN (vc, fake_select_mode, select_mode, SCE_SELECT_FACE) - ; - ED_view3d_select_id_validate_with_select_mode(vc, select_mode); + FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE); + + struct EDBMSelectID_Context *sel_id_ctx = EDBM_select_id_context_create( + vc, bases, bases_len, select_mode); + + index = ED_select_buffer_sample_point(vc->mval); + + if (index) { + efa = (BMFace *)EDBM_select_id_bm_elem_get(sel_id_ctx, index, &base_index); + } + else { + efa = NULL; + } - index = ED_view3d_select_id_sample(vc, vc->mval[0], vc->mval[1]); - efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL; + EDBM_select_id_context_destroy(sel_id_ctx); FAKE_SELECT_MODE_END(vc, fake_select_mode); } @@ -876,6 +949,9 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, if (efa) { if (dist_test < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } *r_dist = dist_test; return efa; } @@ -886,35 +962,56 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, struct NearestFaceUserData data = {{0}}; const struct NearestFaceUserData_Hit *hit; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; + BMesh *prev_select_bm = NULL; - static int prev_select_index = 0; - static const BMFace *prev_select_elem = NULL; - - if ((use_cycle == false) || - (prev_select_elem && - (prev_select_elem != BM_face_at_index_find_or_table(bm, prev_select_index)))) { - prev_select_index = 0; - prev_select_elem = NULL; - } + static struct { + int index; + const BMFace *elem; + const BMesh *bm; + } prev_select = {0}; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; data.use_select_bias = use_select_bias; data.use_cycle = use_cycle; - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; - data.cycle_index_prev = prev_select_index; - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + for (; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + ED_view3d_viewcontext_init_object(vc, base_iter->object); + if (use_cycle && prev_select.bm == vc->em->bm && + prev_select.elem == BM_face_at_index_find_or_table(vc->em->bm, prev_select.index)) { + data.cycle_index_prev = prev_select.index; + /* No need to compare in the rest of the loop. */ + use_cycle = false; + } + else { + data.cycle_index_prev = 0; + } + + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *r_dist; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + + hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; + + if (hit->dist < *r_dist) { + if (r_base_index) { + *r_base_index = base_index; + } + *r_dist = hit->dist; + prev_select_bm = vc->em->bm; + } + } - hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; - *r_dist = hit->dist; if (r_dist_center) { *r_dist_center = hit->dist; } - prev_select_elem = hit->face; - prev_select_index = hit->index; + prev_select.index = hit->index; + prev_select.elem = hit->face; + prev_select.bm = prev_select_bm; return hit->face; } @@ -922,7 +1019,8 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) { - return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL); + Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); + return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); } #undef FIND_NEAR_SELECT_BIAS @@ -965,75 +1063,63 @@ static bool unified_findnearest(ViewContext *vc, } f, f_zbuf; } hit = {{NULL}}; - /* TODO(campbell): perform selection as one pass - * instead of many smaller passes (which doesn't work for zbuf occlusion). */ - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) { + if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BLI_assert(vc->em->selectmode == em->selectmode); - BMFace *efa_zbuf = NULL; - BMFace *efa_test = EDBM_face_find_nearest_ex( - vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf); - if (efa_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (efa_test) { - hit.f.base_index = base_index; - hit.f.ele = efa_test; - } - if (efa_zbuf) { - hit.f_zbuf.base_index = base_index; - hit.f_zbuf.ele = efa_zbuf; - } - } /* bases */ + uint base_index = 0; + BMFace *efa_zbuf = NULL; + BMFace *efa_test = EDBM_face_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); + + if (efa_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (efa_test) { + hit.f.base_index = base_index; + hit.f.ele = efa_test; + } + if (efa_zbuf) { + hit.f_zbuf.base_index = base_index; + hit.f_zbuf.ele = efa_zbuf; + } } if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMEdge *eed_zbuf = NULL; - BMEdge *eed_test = EDBM_edge_find_nearest_ex( - vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf); - if (eed_test && dist_center_p) { - dist = min_ff(dist_margin, dist_center); - } - if (eed_test) { - hit.e.base_index = base_index; - hit.e.ele = eed_test; - } - if (eed_zbuf) { - hit.e_zbuf.base_index = base_index; - hit.e_zbuf.ele = eed_zbuf; - } - } /* bases */ + uint base_index = 0; + BMEdge *eed_zbuf = NULL; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index); + + if (eed_test && dist_center_p) { + dist = min_ff(dist_margin, dist_center); + } + if (eed_test) { + hit.e.base_index = base_index; + hit.e.ele = eed_test; + } + if (eed_zbuf) { + hit.e_zbuf.base_index = base_index; + hit.e_zbuf.ele = eed_zbuf; + } } - if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *obedit = base_iter->object; - ED_view3d_viewcontext_init_object(vc, obedit); - BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle); - if (eve_test) { - hit.v.base_index = base_index; - hit.v.ele = eve_test; - } - } /* bases */ + if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_VERTEX)) { + uint base_index = 0; + BMVert *eve_test = EDBM_vert_find_nearest_ex( + vc, &dist, true, use_cycle, bases, bases_len, &base_index); + + if (eve_test) { + hit.v.base_index = base_index; + hit.v.ele = eve_test; + } } /* return only one of 3 pointers, for frontbuffer redraws */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index cd9d046ae04..a1ebcff31aa 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -336,6 +336,7 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot) { /* identifiers */ ot->name = "Subdivide Edge-Ring"; + ot->description = "Subdivide perpendicular edges to the selected edge ring"; ot->idname = "MESH_OT_subdivide_edgering"; /* api callbacks */ @@ -1123,7 +1124,7 @@ static int edbm_mark_sharp_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - if (bm->totedgesel == 0) { + if ((use_verts && bm->totvertsel == 0) || (!use_verts && bm->totedgesel == 0)) { continue; } @@ -6793,7 +6794,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot) /* identifiers */ ot->name = "Bridge Edge Loops"; - ot->description = "Make faces between two or more edge loops"; + ot->description = "Create a bridge of faces between two or more selected edge loops"; ot->idname = "MESH_OT_bridge_edge_loops"; /* api callbacks */ @@ -7686,6 +7687,7 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); @@ -8075,7 +8077,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot) ot->exec = edbm_point_normals_exec; ot->invoke = edbm_point_normals_invoke; ot->modal = edbm_point_normals_modal; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_point_normals_ui; ot->cancel = point_normals_free; @@ -8241,6 +8243,7 @@ static int normals_split_merge(bContext *C, const bool do_merge) BMEdge *e; BMIter eiter; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; @@ -8286,7 +8289,7 @@ void MESH_OT_merge_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_merge_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8306,7 +8309,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_split_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8344,6 +8347,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op) BMLoop *l, *l_curr, *l_first; BMIter fiter; + BKE_editmesh_ensure_autosmooth(em); bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; BKE_editmesh_lnorspace_update(em); @@ -8504,7 +8508,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_average_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_average_normals_ui; /* flags */ @@ -8567,6 +8571,7 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op) const int mode = RNA_enum_get(op->ptr, "mode"); const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; @@ -8723,7 +8728,7 @@ void MESH_OT_normals_tools(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_normals_tools_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; ot->ui = edbm_normals_tools_ui; /* flags */ @@ -8763,6 +8768,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); @@ -8828,6 +8834,7 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) MEM_freeN(vnors); EDBM_update_generic(em, true, false); } + MEM_freeN(objects); return OPERATOR_FINISHED; } @@ -8841,7 +8848,7 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_set_normals_from_faces_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8858,6 +8865,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) BMLoop *l; BMIter fiter, liter; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); @@ -8933,7 +8941,7 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_smoothen_normals_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8953,7 +8961,6 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot) static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; @@ -8972,7 +8979,7 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) const int cd_prop_int_offset = CustomData_get_n_offset( &bm->pdata, CD_PROP_INT, cd_prop_int_index); - const int face_strength = scene->toolsettings->face_strength; + const int face_strength = RNA_enum_get(op->ptr, "face_strength"); const bool set = RNA_boolean_get(op->ptr, "set"); BM_mesh_elem_index_ensure(bm, BM_FACE); @@ -9001,6 +9008,13 @@ static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static const EnumPropertyItem prop_mesh_face_strength_types[] = { + {FACE_STRENGTH_WEAK, "WEAK", 0, "Weak", ""}, + {FACE_STRENGTH_MEDIUM, "MEDIUM", 0, "Medium", ""}, + {FACE_STRENGTH_STRONG, "STRONG", 0, "Strong", ""}, + {0, NULL, 0, NULL, NULL}, +}; + void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) { /* identifiers */ @@ -9010,11 +9024,18 @@ void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) /* api callbacks */ ot->exec = edbm_mod_weighted_strength_exec; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + ot->prop = RNA_def_enum( + ot->srna, + "face_strength", + prop_mesh_face_strength_types, + FACE_STRENGTH_MEDIUM, + "Face Strength", + "Strength to use for assigning or selecting face influence for weighted normal modifier"); } diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index ed5e6c39f85..102ce3efc22 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -274,7 +274,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", "Extrude Region and Move", - "Extrude context and move result", + "Extrude region together along the average normal", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); @@ -283,7 +283,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten", "Extrude Region and Shrink/Fatten", - "Extrude along normals and move result", + "Extrude region together along local normals", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); @@ -292,7 +292,7 @@ void ED_operatormacros_mesh(void) ot = WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", - "Extrude faces and move result", + "Extrude each individual face separately along local normals", OPTYPE_UNDO | OPTYPE_REGISTER); otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv"); otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index c32fef42d27..41736fb9a14 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -61,6 +61,7 @@ #include "DEG_depsgraph_query.h" #include "ED_mesh.h" +#include "ED_select_buffer_utils.h" #include "ED_object.h" #include "ED_view3d.h" @@ -1109,18 +1110,16 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, } ED_view3d_viewcontext_init(C, &vc); + ED_view3d_select_id_validate(&vc); if (dist_px) { /* sample rect to increase chances of selecting, so that when clicking * on an edge in the backbuf, we can still select a face */ - - ED_view3d_select_id_validate(&vc); - - *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totpoly + 1, &dist_px); + *r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totpoly + 1, &dist_px); } else { /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + *r_index = ED_select_buffer_sample_point(mval); } if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) { @@ -1291,19 +1290,17 @@ bool ED_mesh_pick_vert( } ED_view3d_viewcontext_init(C, &vc); + ED_view3d_select_id_validate(&vc); if (use_zbuf) { if (dist_px > 0) { /* sample rect to increase chances of selecting, so that when clicking * on an face in the backbuf, we can still select a vert */ - - ED_view3d_select_id_validate(&vc); - - *r_index = ED_view3d_select_id_read_nearest(&vc, mval, 1, me->totvert + 1, &dist_px); + *r_index = ED_select_buffer_find_nearest_to_point(mval, 1, me->totvert + 1, &dist_px); } else { /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(&vc, mval[0], mval[1]); + *r_index = ED_select_buffer_sample_point(mval); } if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) { diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 54143822b61..18ff7ae1a5e 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -738,7 +738,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese } const uint hit_object = hitresult & 0xFFFF; - if (vc.obedit->select_id != hit_object) { + if (vc.obedit->runtime.select_id != hit_object) { continue; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f8a13579732..cb152cb4e49 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -113,6 +113,10 @@ #include "object_intern.h" +/* -------------------------------------------------------------------- */ +/** \name Local Enum Declarations + * \{ */ + /* this is an exact copy of the define in rna_light.c * kept here because of linking order. * Icons are only defined here */ @@ -161,7 +165,25 @@ static EnumPropertyItem lightprobe_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -/************************** Exported *****************************/ +enum { + ALIGN_WORLD = 0, + ALIGN_VIEW, + ALIGN_CURSOR, +}; + +static const EnumPropertyItem align_options[] = { + {ALIGN_WORLD, "WORLD", 0, "World", "Align the new object to the world"}, + {ALIGN_VIEW, "VIEW", 0, "View", "Align the new object to the view"}, + {ALIGN_CURSOR, "CURSOR", 0, "3D Cursor", "Use the 3D cursor orientation for the new object"}, + {0, NULL, 0, NULL, NULL}, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Add Object API + * + * \{ */ void ED_object_location_from_view(bContext *C, float loc[3]) { @@ -266,7 +288,11 @@ float ED_object_new_primitive_matrix( // return 1.0f; } -/********************* Add Object Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Object Operator + * \{ */ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(scene), @@ -291,16 +317,15 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) { PropertyRNA *prop; - /* note: this property gets hidden for add-camera operator */ - prop = RNA_def_boolean( - ot->srna, "view_align", 0, "Align to View", "Align the new object to the view"); - RNA_def_property_update_runtime(prop, view_align_update); - if (do_editmode) { prop = RNA_def_boolean( ot->srna, "enter_editmode", 0, "Enter Editmode", "Enter editmode when adding this object"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } + /* note: this property gets hidden for add-camera operator */ + prop = RNA_def_enum( + ot->srna, "align", align_options, ALIGN_WORLD, "Align", "The alignment of the new object"); + RNA_def_property_update_runtime(prop, view_align_update); prop = RNA_def_float_vector_xyz(ot->srna, "location", @@ -392,23 +417,44 @@ bool ED_object_add_generic_get_opts(bContext *C, rot = _rot; } + prop = RNA_struct_find_property(op->ptr, "align"); + int alignment = RNA_property_enum_get(op->ptr, prop); + bool alignment_set = RNA_property_is_set(op->ptr, prop); + if (RNA_struct_property_is_set(op->ptr, "rotation")) { *is_view_aligned = false; } - else if (RNA_struct_property_is_set(op->ptr, "view_align")) { - *is_view_aligned = RNA_boolean_get(op->ptr, "view_align"); + else if (alignment_set) { + *is_view_aligned = alignment == ALIGN_VIEW; } else { *is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0; - RNA_boolean_set(op->ptr, "view_align", *is_view_aligned); + if (*is_view_aligned) { + RNA_property_enum_set(op->ptr, prop, ALIGN_VIEW); + alignment = ALIGN_VIEW; + } + else if (U.flag & USER_ADD_CURSORALIGNED) { + RNA_property_enum_set(op->ptr, prop, ALIGN_CURSOR); + alignment = ALIGN_CURSOR; + } } - if (*is_view_aligned) { - ED_object_rotation_from_view(C, rot, view_align_axis); - RNA_float_set_array(op->ptr, "rotation", rot); - } - else { - RNA_float_get_array(op->ptr, "rotation", rot); + switch (alignment) { + case ALIGN_WORLD: + RNA_float_get_array(op->ptr, "rotation", rot); + break; + case ALIGN_VIEW: + ED_object_rotation_from_view(C, rot, view_align_axis); + RNA_float_set_array(op->ptr, "rotation", rot); + break; + case ALIGN_CURSOR: { + const Scene *scene = CTX_data_scene(C); + float tmat[3][3]; + BKE_scene_cursor_rot_to_mat3(&scene->cursor, tmat); + mat3_normalized_to_eul(rot, tmat); + RNA_float_set_array(op->ptr, "rotation", rot); + break; + } } } @@ -516,7 +562,11 @@ void OBJECT_OT_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************** Add Probe Operator **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Probe Operator + * \{ */ /* for object add operator */ static const char *get_lightprobe_defname(int type) @@ -604,7 +654,11 @@ void OBJECT_OT_lightprobe_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Effector Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Effector Operator + * \{ */ /* for object add operator */ static int effector_add_exec(bContext *C, wmOperator *op) @@ -677,7 +731,11 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Camera Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Camera Operator + * \{ */ static int object_camera_add_exec(bContext *C, wmOperator *op) { @@ -690,7 +748,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; /* force view align for cameras */ - RNA_boolean_set(op->ptr, "view_align", true); + RNA_enum_set(op->ptr, "align", ALIGN_VIEW); if (!ED_object_add_generic_get_opts( C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) { @@ -732,11 +790,15 @@ void OBJECT_OT_camera_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); /* hide this for cameras, default */ - prop = RNA_struct_type_find_property(ot->srna, "view_align"); + prop = RNA_struct_type_find_property(ot->srna, "align"); RNA_def_property_flag(prop, PROP_HIDDEN); } -/********************* Add Metaball Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Metaball Operator + * \{ */ static int object_metaball_add_exec(bContext *C, wmOperator *op) { @@ -797,7 +859,11 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Text Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Text Operator + * \{ */ static int object_add_text_exec(bContext *C, wmOperator *op) { @@ -842,7 +908,11 @@ void OBJECT_OT_text_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Armature Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Armature Operator + * \{ */ static int object_armature_add_exec(bContext *C, wmOperator *op) { @@ -905,7 +975,11 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/********************* Add Empty Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Empty Operator + * \{ */ static int object_empty_add_exec(bContext *C, wmOperator *op) { @@ -1025,7 +1099,12 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Gpencil Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Gpencil Operator + * \{ */ + static bool object_gpencil_add_poll(bContext *C) { Scene *scene = CTX_data_scene(C); @@ -1156,7 +1235,11 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); } -/********************* Add Light Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Light Operator + * \{ */ static const char *get_light_defname(int type) { @@ -1176,7 +1259,6 @@ static const char *get_light_defname(int type) static int object_light_add_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); Object *ob; Light *la; int type = RNA_enum_get(op->ptr, "type"); @@ -1207,9 +1289,8 @@ static int object_light_add_exec(bContext *C, wmOperator *op) la = (Light *)ob->data; la->type = type; - if (BKE_scene_uses_cycles(scene)) { - ED_node_shader_default(C, &la->id); - la->use_nodes = true; + if (type == LA_SUN) { + la->energy = 1.0f; } return OPERATOR_FINISHED; @@ -1238,7 +1319,11 @@ void OBJECT_OT_light_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Collection Instance Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Collection Instance Operator + * \{ */ static int collection_instance_add_exec(bContext *C, wmOperator *op) { @@ -1324,7 +1409,11 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } -/********************* Add Speaker Operator ********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Speaker Operator + * \{ */ static int object_speaker_add_exec(bContext *C, wmOperator *op) { @@ -1379,7 +1468,11 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot) ED_object_add_generic_props(ot, true); } -/**************************** Delete Object *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Object Operator + * \{ */ /* remove base from a specific scene */ /* note: now unlinks constraints as well */ @@ -1537,7 +1630,11 @@ void OBJECT_OT_delete(wmOperatorType *ot) WM_operator_properties_confirm_or_exec(ot); } -/**************************** Copy Utilities ******************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy Object Utilities + * \{ */ /* after copying objects, copied data should get new pointers */ static void copy_object_set_idnew(bContext *C) @@ -1552,7 +1649,11 @@ static void copy_object_set_idnew(bContext *C) BKE_main_id_clear_newpoins(bmain); } -/********************* Make Duplicates Real ************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Make Instanced Objects Real Operator + * \{ */ /** * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, @@ -1656,7 +1757,7 @@ static void make_object_duplilist_real( for (dob = lb_duplis->first; dob; dob = dob->next) { Object *ob_src = DEG_get_original_object(dob->ob); - Object *ob_dst = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, ob_src)); + Object *ob_dst = ID_NEW_SET(ob_src, BKE_object_copy(bmain, ob_src)); Base *base_dst; /* font duplis can have a totcol without material, we get them from parent @@ -1838,7 +1939,11 @@ void OBJECT_OT_duplicates_make_real(wmOperatorType *ot) ot->srna, "use_hierarchy", 0, "Keep Hierarchy", "Maintain parent child relationships"); } -/**************************** Convert **************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Convert Operator + * \{ */ static const EnumPropertyItem convert_target_items[] = { {OB_CURVE, "CURVE", ICON_OUTLINER_OB_CURVE, "Curve from Mesh/Text", ""}, @@ -1857,7 +1962,7 @@ static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Objec if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { /* We need 'for render' ON here, to enable computing bevel dipslist if needed. * Also makes sense anyway, we would not want e.g. to loose hidden parts etc. */ - BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false); } else if (ob->type == OB_MBALL) { BKE_displist_make_mball(depsgraph, scene, ob); @@ -1947,7 +2052,8 @@ static int convert_exec(bContext *C, wmOperator *op) FOREACH_SCENE_OBJECT_END; } - ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases"); + ListBase selected_editable_bases; + CTX_data_selected_editable_bases(C, &selected_editable_bases); /* Ensure we get all meshes calculated with a sufficient data-mask, * needed since re-evaluating single modifiers causes bugs if they depend @@ -2293,7 +2399,11 @@ void OBJECT_OT_convert(wmOperatorType *ot) "Keep original objects instead of replacing them"); } -/**************************** Duplicate ************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Object Operator + * \{ */ /* * dupflag: a flag made from constants declared in DNA_userdef_types.h @@ -2449,7 +2559,13 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/* **************** add named object, for dragdrop ************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Named Object Operator + * + * Use for for drag & drop. + * \{ */ static int add_named_exec(bContext *C, wmOperator *op) { @@ -2481,7 +2597,7 @@ static int add_named_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - basen->object->restrictflag &= ~OB_RESTRICT_VIEW; + basen->object->restrictflag &= ~OB_RESTRICT_VIEWPORT; if (event) { ARegion *ar = CTX_wm_region(C); @@ -2527,7 +2643,12 @@ void OBJECT_OT_add_named(wmOperatorType *ot) RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Object name to add"); } -/**************************** Join *************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Join Object Operator + * + * \{ */ static bool join_poll(bContext *C) { @@ -2596,7 +2717,11 @@ void OBJECT_OT_join(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/**************************** Join as Shape Key*************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Join as Shape Key Operator + * \{ */ static bool join_shapes_poll(bContext *C) { @@ -2649,3 +2774,5 @@ void OBJECT_OT_join_shapes(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 5ae757cac56..f87342a14ad 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -277,7 +277,8 @@ static bool write_internal_bake_pixels(Image *image, RE_bake_margin(ibuf, mask_buffer, margin); } - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_BITMAPDIRTY; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(image, ibuf); if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; @@ -704,10 +705,9 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob) +static Mesh *bake_mesh_new_from_object(Object *object) { - bool apply_modifiers = (ob->type != OB_MESH); - Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, apply_modifiers, false); + Mesh *me = BKE_object_to_mesh(object); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -903,7 +903,7 @@ static int bake(Render *re, ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_low = bake_mesh_new_from_object(ob_low_eval); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) { @@ -917,7 +917,7 @@ static int bake(Render *re, /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage_eval); + me_cage = bake_mesh_new_from_object(ob_cage_eval); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, @@ -946,7 +946,7 @@ static int bake(Render *re, md = md_next; } - me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval); + me_cage = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -965,7 +965,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob_eval); + highpoly[i].me = BKE_object_to_mesh(highpoly[i].ob_eval); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1088,7 +1088,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob_low_eval, true, false); + me_nores = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, @@ -1098,7 +1098,7 @@ static int bake(Render *re, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_id_free(bmain, me_nores); + BKE_object_to_mesh_clear(ob_low_eval); if (md) { md->mode = mode; @@ -1222,7 +1222,7 @@ cleanup: int i; for (i = 0; i < tot_highpoly; i++) { if (highpoly[i].me) { - BKE_id_free(bmain, highpoly[i].me); + BKE_object_to_mesh_clear(highpoly[i].ob_eval); } } MEM_freeN(highpoly); @@ -1253,11 +1253,11 @@ cleanup: } if (me_low) { - BKE_id_free(bmain, me_low); + BKE_object_to_mesh_clear(ob_low_eval); } if (me_cage) { - BKE_id_free(bmain, me_cage); + BKE_object_to_mesh_clear(ob_cage_eval); } DEG_graph_free(depsgraph); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 6a587bd6e2a..abdf64af595 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -160,7 +160,7 @@ static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2) if (index) { /* innovative use of a for...loop to search */ for (text = bmain->texts.first, i = 1; text && index != i; i++, text = text->id.next) { - ; + /* pass */ } } data->text = text; @@ -1878,14 +1878,6 @@ static int constraint_add_exec( if (type == CONSTRAINT_TYPE_NULL) { return OPERATOR_CANCELLED; } - if ((type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } - if ((type == CONSTRAINT_TYPE_SPLINEIK) && ((!pchan) || (list != &pchan->constraints))) { - BKE_report(op->reports, RPT_ERROR, "Spline IK constraint can only be added to bones"); - return OPERATOR_CANCELLED; - } /* Create a new constraint of the type required, * and add it to the active/given constraints list. */ @@ -2023,8 +2015,33 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op) /* ------------------ */ +/* Filters constraints that are only compatible with bones */ +static const EnumPropertyItem *object_constraint_add_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + const EnumPropertyItem *item = rna_enum_constraint_type_items; + EnumPropertyItem *object_constraint_items = NULL; + int totitem = 0; + + while (item->identifier) { + if ((item->value != CONSTRAINT_TYPE_KINEMATIC) && (item->value != CONSTRAINT_TYPE_SPLINEIK)) { + RNA_enum_item_add(&object_constraint_items, &totitem, item); + } + item++; + } + + RNA_enum_item_end(&object_constraint_items, &totitem); + *r_free = true; + + return object_constraint_items; +} + void OBJECT_OT_constraint_add(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Constraint"; ot->description = "Add a constraint to the active object"; @@ -2039,11 +2056,15 @@ void OBJECT_OT_constraint_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", ""); + RNA_def_enum_funcs(prop, object_constraint_add_itemf); + ot->prop = prop; } void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Constraint (with Targets)"; ot->description = @@ -2060,7 +2081,9 @@ void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", ""); + RNA_def_enum_funcs(prop, object_constraint_add_itemf); + ot->prop = prop; } void POSE_OT_constraint_add(wmOperatorType *ot) diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 795e1dd66a5..a542911f4d4 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -314,7 +314,7 @@ void ED_collection_hide_menu_draw(const bContext *C, uiLayout *layout) continue; } - if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) { + if (lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) { continue; } @@ -722,7 +722,7 @@ static bool editmode_toggle_poll(bContext *C) } /* if hidden but in edit mode, we still display */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) { + if ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)) { return 0; } @@ -1779,4 +1779,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot) "Name", "Name of the newly added collection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = prop; } diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index e555f0d940d..8d3a636671a 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -108,7 +108,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * BKE_displist_make_mball(depsgraph, scene_eval, ob_eval); } else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false); } } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index e15d85a7953..6df012cdc80 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -697,7 +697,7 @@ bool ED_object_parent_set(ReportList *reports, cu->flag |= CU_PATH | CU_FOLLOW; cu_eval->flag |= CU_PATH | CU_FOLLOW; /* force creation of path data */ - BKE_displist_make_curveTypes(depsgraph, scene, par, false, false, NULL); + BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); } else { cu->flag |= CU_FOLLOW; diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index cb8fe262730..40b7a245f69 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -47,6 +47,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -360,6 +361,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) DynamicPaintSurface *surface = job->surface; Object *cObject = job->ob; DynamicPaintCanvasSettings *canvas = surface->canvas; + Scene *input_scene = DEG_get_input_scene(job->depsgraph); Scene *scene = job->scene; int frame = 1, orig_frame; int frames; @@ -375,8 +377,8 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* Set frame to start point (also inits modifier data) */ frame = surface->start_frame; - orig_frame = scene->r.cfra; - scene->r.cfra = (int)frame; + orig_frame = input_scene->r.cfra; + input_scene->r.cfra = (int)frame; ED_update_for_newframe(job->bmain, job->depsgraph); /* Init surface */ @@ -402,7 +404,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) *(job->progress) = progress; /* calculate a frame */ - scene->r.cfra = (int)frame; + input_scene->r.cfra = (int)frame; ED_update_for_newframe(job->bmain, job->depsgraph); if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) { job->success = 0; @@ -438,7 +440,8 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) } } - scene->r.cfra = orig_frame; + input_scene->r.cfra = orig_frame; + ED_update_for_newframe(job->bmain, job->depsgraph); } static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress) @@ -470,25 +473,26 @@ static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update */ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) { - DynamicPaintModifierData *pmd = NULL; - DynamicPaintCanvasSettings *canvas; - Object *ob = ED_object_context(C); - Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob_ = ED_object_context(C); + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob_); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); DynamicPaintSurface *surface; /* * Get modifier data */ - pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); - if (!pmd) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType( + object_eval, eModifierType_DynamicPaint); + if (pmd == NULL) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); return OPERATOR_CANCELLED; } /* Make sure we're dealing with a canvas */ - canvas = pmd->canvas; - if (!canvas) { + DynamicPaintCanvasSettings *canvas = pmd->canvas; + if (canvas == NULL) { BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas"); return OPERATOR_CANCELLED; } @@ -500,15 +504,15 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"); job->bmain = CTX_data_main(C); - job->scene = scene; + job->scene = scene_eval; job->depsgraph = CTX_data_depsgraph(C); - job->ob = ob; + job->ob = object_eval; job->canvas = canvas; job->surface = surface; wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), - scene, + CTX_data_scene(C), "Dynamic Paint Bake", WM_JOB_PROGRESS, WM_JOB_TYPE_DPAINT_BAKE); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 09bcc0a3058..1e85c895f71 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -356,7 +356,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into - * the output rendering. We can't put that into RE_BlenderFrame, + * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(scene); @@ -364,18 +364,17 @@ static int screen_render_exec(bContext *C, wmOperator *op) BLI_threaded_malloc_begin(); if (is_animation) { - RE_BlenderAnim(re, - mainp, - scene, - single_layer, - camera_override, - scene->r.sfra, - scene->r.efra, - scene->r.frame_step); + RE_RenderAnim(re, + mainp, + scene, + single_layer, + camera_override, + scene->r.sfra, + scene->r.efra, + scene->r.frame_step); } else { - RE_BlenderFrame( - re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); + RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } BLI_threaded_malloc_end(); @@ -671,23 +670,23 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro RE_SetReports(rj->re, rj->reports); if (rj->anim) { - RE_BlenderAnim(rj->re, + RE_RenderAnim(rj->re, + rj->main, + rj->scene, + rj->single_layer, + rj->camera_override, + rj->scene->r.sfra, + rj->scene->r.efra, + rj->scene->r.frame_step); + } + else { + RE_RenderFrame(rj->re, rj->main, rj->scene, rj->single_layer, rj->camera_override, - rj->scene->r.sfra, - rj->scene->r.efra, - rj->scene->r.frame_step); - } - else { - RE_BlenderFrame(rj->re, - rj->main, - rj->scene, - rj->single_layer, - rj->camera_override, - rj->scene->r.cfra, - rj->write_still); + rj->scene->r.cfra, + rj->write_still); } RE_SetReports(rj->re, NULL); @@ -976,7 +975,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into - * the output rendering. We can't put that into RE_BlenderFrame, + * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(scene); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 28cfce00e6e..20229b63258 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -114,7 +114,6 @@ typedef struct OGLRender { GPUOffScreen *ofs; int ofs_samples; - bool ofs_full_samples; int sizex, sizey; int write_still; @@ -356,9 +355,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ImBuf *ibuf_view; const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL; - unsigned int draw_flags = V3D_OFSDRAW_NONE; - draw_flags |= (oglrender->ofs_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0; - if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph, scene, @@ -368,7 +364,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R sizex, sizey, IB_rectfloat, - draw_flags, alpha_mode, oglrender->ofs_samples, viewname, @@ -381,7 +376,6 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R } } else { - draw_flags |= V3D_OFSDRAW_SHOW_ANNOTATION; ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, NULL, @@ -390,7 +384,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R oglrender->sizex, oglrender->sizey, IB_rectfloat, - draw_flags, + V3D_OFSDRAW_SHOW_ANNOTATION, alpha_mode, oglrender->ofs_samples, viewname, @@ -489,8 +483,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) for (view_id = 0; view_id < oglrender->views_len; view_id++) { context.view_id = view_id; context.gpu_offscreen = oglrender->ofs; - context.gpu_full_samples = oglrender->ofs_full_samples; - oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); } } @@ -517,24 +509,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) } } -static bool screen_opengl_fullsample_enabled(Scene *scene) -{ - if (scene->r.scemode & R_FULL_SAMPLE) { - return true; - } - else { - /* XXX TODO: - * Technically if the hardware supports MSAA we could keep using Blender 2.7x approach. - * However anti-aliasing without full_sample is not playing well even in 2.7x. - * - * For example, if you enable depth of field, there is aliasing, even if the viewport is fine. - * For 2.8x this is more complicated because so many things rely on shader. - * So until we fix the gpu_framebuffer anti-aliasing suupport we need to force full sample. - */ - return true; - } -} - static bool screen_opengl_render_init(bContext *C, wmOperator *op) { /* new render clears all callbacks */ @@ -548,12 +522,11 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; - const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0; - const bool full_samples = (samples != 0) && screen_opengl_fullsample_enabled(scene); bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); + const int samples = U.ogl_multisamples; char err_out[256] = "unknown"; if (G.background) { @@ -598,7 +571,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out); + ofs = GPU_offscreen_create(sizex, sizey, samples, true, true, err_out); DRW_opengl_context_disable(); if (!ofs) { @@ -611,8 +584,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) op->customdata = oglrender; oglrender->ofs = ofs; - oglrender->ofs_samples = samples; - oglrender->ofs_full_samples = full_samples; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); @@ -621,6 +592,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->view_layer = CTX_data_view_layer(C); oglrender->depsgraph = CTX_data_depsgraph(C); oglrender->cfrao = scene->r.cfra; + oglrender->ofs_samples = samples; oglrender->write_still = is_write_still && !is_animation; oglrender->is_animation = is_animation; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index bf6d658f927..76b88b8df22 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -270,7 +270,7 @@ static const char *preview_collection_name(const char pr_type) case MA_FLUID: return "Fluid"; case MA_SPHERE_A: - return "World Shader Ball"; + return "World Sphere"; case MA_LAMP: return "Lamp"; case MA_SKY: @@ -437,7 +437,14 @@ static Scene *preview_prepare_scene( sce->world->horb = 0.05f; } - set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); + if (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) { + /* For grease pencil, always use sphere for icon renders. */ + set_preview_visibility(sce, view_layer, MA_SPHERE_A, sp->pr_method); + } + else { + /* Use specified preview shape for both preview panel and icon previews. */ + set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); + } if (sp->pr_method != PR_ICON_RENDER) { if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { @@ -449,7 +456,7 @@ static Scene *preview_prepare_scene( } } else { - sce->r.mode &= ~(R_OSA); + sce->display.render_aa = SCE_DISPLAY_AA_OFF; } for (Base *base = view_layer->object_bases.first; base; base = base->next) { @@ -861,7 +868,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs if (sp->pr_method == PR_ICON_RENDER) { sce->r.scemode |= R_NO_IMAGE_LOAD; - sce->r.mode |= R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } else if (sp->pr_method == PR_NODE_RENDER) { if (idtype == ID_MA) { @@ -870,10 +877,10 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs else if (idtype == ID_TE) { sce->r.scemode |= R_TEXNODE_PREVIEW; } - sce->r.mode &= ~R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_OFF; } else { /* PR_BUTS_RENDER */ - sce->r.mode |= R_OSA; + sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } /* callbacs are cleared on GetRender() */ @@ -969,7 +976,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied ID */ properties = IDP_GetProperties(sp->id_copy, false); if (properties) { - IDP_FreeProperty_ex(properties, false); + IDP_FreePropertyContent_ex(properties, false); MEM_freeN(properties); } switch (GS(sp->id_copy->name)) { diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 3186f011c6a..f7a1d7187f1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -595,7 +595,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&ma->id); RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -644,7 +644,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&tex->id); RNA_id_pointer_create(&tex->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -695,7 +695,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&wo->id); RNA_id_pointer_create(&wo->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 3f3f98bc6e5..64869b71746 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -132,7 +132,10 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update CTX_wm_region_set(C, ar); engine->flag &= ~RE_ENGINE_DO_UPDATE; - engine->type->view_update(engine, C); + /* NOTE: Important to pass non-updated depsgraph, This is because this function is called + * from inside dependency graph evaluation. Additionally, if we pass fully evaluated one + * we will loose updates stored in the graph. */ + engine->type->view_update(engine, C, CTX_data_depsgraph(C)); } else { RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); @@ -265,7 +268,7 @@ static void image_changed(Main *bmain, Image *ima) /* textures */ for (tex = bmain->textures.first; tex; tex = tex->id.next) { - if (tex->ima == ima) { + if (tex->type == TEX_IMAGE && tex->ima == ima) { texture_changed(bmain, tex); } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 38684afec39..9b35c809d5a 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -50,6 +50,7 @@ #include "ED_screen.h" #include "ED_screen_types.h" #include "ED_space_api.h" +#include "ED_time_scrub_ui.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" @@ -202,7 +203,7 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f alpha = min_ff(alpha, 0.75f); - UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha, NULL); + UI_icon_draw_ex(x, y, ICON_FULLSCREEN_EXIT, 0.7f * U.inv_dpi_fac, 0.0f, alpha, NULL, false); /* debug drawing : * The click_rect is the same as defined in fullscreen_click_rcti_init @@ -457,19 +458,6 @@ void ED_area_do_msg_notify_tag_refresh( ED_area_tag_refresh(sa); } -static void region_do_msg_notify_tag_redraw( - /* Follow wmMsgNotifyFn spec */ - bContext *UNUSED(C), - wmMsgSubscribeKey *UNUSED(msg_key), - wmMsgSubscribeValue *msg_val) -{ - ARegion *ar = msg_val->owner; - ED_region_tag_redraw(ar); - - /* FIXME(campbell): shouldn't be needed. */ - WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); -} - void ED_area_do_mgs_subscribe_for_tool_header( /* Follow ARegionType.message_subscribe */ const struct bContext *UNUSED(C), @@ -480,18 +468,39 @@ void ED_area_do_mgs_subscribe_for_tool_header( struct ARegion *ar, struct wmMsgBus *mbus) { + BLI_assert(ar->regiontype == RGN_TYPE_TOOL_HEADER); wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { .owner = ar, .user_data = ar, - /* TODO(campbell): investigate why - * ED_region_do_msg_notify_tag_redraw doesn't work here. */ - // .notify = ED_region_do_msg_notify_tag_redraw, - .notify = region_do_msg_notify_tag_redraw, + .notify = ED_region_do_msg_notify_tag_redraw, }; WM_msg_subscribe_rna_prop( mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw); } +void ED_area_do_mgs_subscribe_for_tool_ui( + /* Follow ARegionType.message_subscribe */ + const struct bContext *UNUSED(C), + struct WorkSpace *workspace, + struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), + struct ScrArea *UNUSED(sa), + struct ARegion *ar, + struct wmMsgBus *mbus) +{ + BLI_assert(ar->regiontype == RGN_TYPE_UI); + const char *category = UI_panel_category_active_get(ar, false); + if (category && STREQ(category, "Tool")) { + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + WM_msg_subscribe_rna_prop( + mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw); + } +} + /** * Although there's no general support for minimizing areas, the status-bar can * be snapped to be only a few pixels high. A few pixels rather than 0 so it @@ -1050,11 +1059,11 @@ static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *ar) { const View2D *v2d = &ar->v2d; - if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) { + if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) { region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_VERT); } if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) && - ((v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0)) { + ((v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0)) { region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_HOR); } } @@ -1110,7 +1119,7 @@ static int rct_fits(const rcti *rect, char dir, int size) static void region_overlap_fix(ScrArea *sa, ARegion *ar) { ARegion *ar1; - const int align = ar->alignment & ~RGN_SPLIT_PREV; + const int align = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); int align1 = 0; /* find overlapping previous region on same place */ @@ -1227,7 +1236,7 @@ static void region_rect_recursive( } } - int alignment = ar->alignment & ~RGN_SPLIT_PREV; + int alignment = RGN_ALIGN_ENUM_FROM_MASK(ar->alignment); /* set here, assuming userpref switching forces to call this again */ ar->overlap = ED_region_is_overlap(sa->spacetype, ar->regiontype); @@ -1596,14 +1605,19 @@ static void ed_default_handlers( wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } - if (flag & ED_KEYMAP_MARKERS) { + if (flag & ED_KEYMAP_ANIMATION) { + wmKeyMap *keymap; + /* time-markers */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0); + keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0); WM_event_add_keymap_handler_poll(handlers, keymap, event_in_markers_region); - } - if (flag & ED_KEYMAP_ANIMATION) { + + /* time-scrubbing */ + keymap = WM_keymap_ensure(wm->defaultconf, "Scrubbing", 0, 0); + WM_event_add_keymap_handler_poll(handlers, keymap, ED_event_in_scrubbing_region); + /* frame changing and timeline operators (for time spaces) */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0); + keymap = WM_keymap_ensure(wm->defaultconf, "Animation", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if (flag & ED_KEYMAP_FRAMES) { @@ -1613,14 +1627,19 @@ static void ed_default_handlers( } if (flag & ED_KEYMAP_HEADER) { /* standard keymap for headers regions */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Header", 0, 0); + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if (flag & ED_KEYMAP_FOOTER) { /* standard keymap for footer regions */ - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Footer", 0, 0); + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } + if (flag & ED_KEYMAP_NAVBAR) { + /* standard keymap for Navigation bar regions */ + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Region Context Menu", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + } /* Keep last because of LMB/RMB handling, see: T57527. */ if (flag & ED_KEYMAP_GPENCIL) { @@ -1690,7 +1709,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar } /* Some AZones use View2D data which is only updated in region init, so call that first! */ - region_azones_add(screen, area, ar, ar->alignment & ~RGN_SPLIT_PREV); + region_azones_add(screen, area, ar, RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)); } ED_area_azones_update(area, &win->eventstate->x); @@ -1761,7 +1780,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) } /* Some AZones use View2D data which is only updated in region init, so call that first! */ - region_azones_add(screen, sa, ar, ar->alignment & ~RGN_SPLIT_PREV); + region_azones_add(screen, sa, ar, RGN_ALIGN_ENUM_FROM_MASK(ar->alignment)); } /* Avoid re-initializing tools while resizing the window. */ @@ -2273,7 +2292,7 @@ static void ed_panel_draw(const bContext *C, } } - UI_panel_end(block, w, h); + UI_panel_end(block, w, h, open); } /** @@ -2281,34 +2300,62 @@ static void ed_panel_draw(const bContext *C, * Matching against any of these strings will draw the panel. * Can be NULL to skip context checks. */ -void ED_region_panels_layout_ex( - const bContext *C, ARegion *ar, const char *contexts[], int contextnr, const bool vertical) +void ED_region_panels_layout_ex(const bContext *C, + ARegion *ar, + ListBase *paneltypes, + const char *contexts[], + int contextnr, + const bool vertical, + const char *category_override) { + /* collect panels to draw */ + WorkSpace *workspace = CTX_wm_workspace(C); + LinkNode *panel_types_stack = NULL; + for (PanelType *pt = paneltypes->last; pt; pt = pt->prev) { + /* Only draw top level panels. */ + if (pt->parent) { + continue; + } + + if (category_override) { + if (!STREQ(pt->category, category_override)) { + continue; + } + } + + /* verify context */ + if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) { + continue; + } + + /* If we're tagged, only use compatible. */ + if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { + continue; + } + + /* draw panel */ + if (pt->draw && (!pt->poll || pt->poll(C, pt))) { + BLI_linklist_prepend_alloca(&panel_types_stack, pt); + } + } + ar->runtime.category = NULL; - const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); - PanelType *pt; View2D *v2d = &ar->v2d; int x, y, w, em; - bool is_context_new = 0; - int scroll; /* XXX, should use some better check? */ /* For now also has hardcoded check for clip editor until it supports actual toolbar. */ - bool use_category_tabs = ((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) || - (ar->regiontype == RGN_TYPE_TOOLS && sa->spacetype == SPACE_CLIP); + bool use_category_tabs = (category_override == NULL) && + ((((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) || + (ar->regiontype == RGN_TYPE_TOOLS && sa->spacetype == SPACE_CLIP))); /* offset panels for small vertical tab area */ const char *category = NULL; const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH; int margin_x = 0; const bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE; - - BLI_SMALLSTACK_DECLARE(pt_stack, PanelType *); - - if (contextnr != -1) { - is_context_new = UI_view2d_tab_set(v2d, contextnr); - } + const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false; /* before setting the view */ if (vertical) { @@ -2326,45 +2373,21 @@ void ED_region_panels_layout_ex( v2d->scroll |= (V2D_SCROLL_BOTTOM); v2d->scroll &= ~(V2D_SCROLL_RIGHT); } - - scroll = v2d->scroll; - - /* collect panels to draw */ - for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) { - /* Only draw top level panels. */ - if (pt->parent) { - continue; - } - - /* verify context */ - if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) { - continue; - } - - /* If we're tagged, only use compatible. */ - if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { - continue; - } - - /* draw panel */ - if (pt->draw && (!pt->poll || pt->poll(C, pt))) { - BLI_SMALLSTACK_PUSH(pt_stack, pt); - } - } + const int scroll = v2d->scroll; /* collect categories */ if (use_category_tabs) { UI_panel_category_clear_all(ar); /* gather unique categories */ - BLI_SMALLSTACK_ITER_BEGIN (pt_stack, pt) { + for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) { + PanelType *pt = pt_link->link; if (pt->category[0]) { if (!UI_panel_category_find(ar, pt->category)) { UI_panel_category_add(ar, pt->category); } } } - BLI_SMALLSTACK_ITER_END; if (!UI_panel_category_is_visible(ar)) { use_category_tabs = false; @@ -2392,7 +2415,8 @@ void ED_region_panels_layout_ex( /* set view2d view matrix - UI_block_begin() stores it */ UI_view2d_view_ortho(v2d); - BLI_SMALLSTACK_ITER_BEGIN (pt_stack, pt) { + for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) { + PanelType *pt = pt_link->link; Panel *panel = UI_panel_find_by_type(&ar->panels, pt); if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) { @@ -2403,7 +2427,6 @@ void ED_region_panels_layout_ex( ed_panel_draw(C, sa, ar, &ar->panels, pt, panel, w, em, vertical); } - BLI_SMALLSTACK_ITER_END; /* align panels and return size */ UI_panels_end(C, ar, &x, &y); @@ -2474,9 +2497,11 @@ void ED_region_panels_layout_ex( ar->runtime.category = category; } } + void ED_region_panels_layout(const bContext *C, ARegion *ar) { - ED_region_panels_layout_ex(C, ar, NULL, -1, true); + bool vertical = true; + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, NULL, -1, vertical, NULL); } void ED_region_panels_draw(const bContext *C, ARegion *ar) @@ -2525,7 +2550,7 @@ void ED_region_panels_ex( const bContext *C, ARegion *ar, const char *contexts[], int contextnr, const bool vertical) { /* TODO: remove? */ - ED_region_panels_layout_ex(C, ar, contexts, contextnr, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts, contextnr, vertical, NULL); ED_region_panels_draw(C, ar); } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index c60469e092f..6a5df8a3776 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -69,15 +69,10 @@ const char *screen_context_dir[] = { "scene", "view_layer", "visible_objects", - "visible_bases", "selectable_objects", - "selectable_bases", "selected_objects", - "selected_bases", "editable_objects", - "editable_bases", "selected_editable_objects", - "selected_editable_bases", "objects_in_mode", "objects_in_mode_unique_data", "visible_bones", @@ -89,7 +84,6 @@ const char *screen_context_dir[] = { "selected_pose_bones_from_active_object", "active_bone", "active_pose_bone", - "active_base", "active_object", "object", "edit_object", @@ -179,52 +173,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "visible_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_VISIBLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selectable_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTED(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_editable_bases")) { - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_SELECTED_EDITABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "editable_bases")) { - /* Visible + Editable, but not necessarily selected */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (BASE_EDITABLE(v3d, base)) { - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } else if (CTX_data_equals(member, "objects_in_mode")) { if (obact && (obact->mode != OB_MODE_OBJECT)) { FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) { @@ -455,13 +403,6 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } } - else if (CTX_data_equals(member, "active_base")) { - if (view_layer->basact) { - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); - } - - return 1; - } else if (CTX_data_equals(member, "active_object")) { if (obact) { CTX_data_id_pointer_set(result, &obact->id); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 2ce9d732eb7..3a90532aa56 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -675,6 +675,12 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) bool do_draw = false; for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + + /* call old area's deactivate if assigned */ + if (ar == old_ar && area_iter->type->deactivate) { + area_iter->type->deactivate(area_iter); + } + if (ar == old_ar || ar == scr->active_region) { do_draw = true; } @@ -884,9 +890,11 @@ static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmai { for (bScreen *screen_iter = bmain->screens.first; screen_iter; screen_iter = screen_iter->id.next) { - ScrArea *sa = screen_iter->areabase.first; - if (sa && sa->full == screen) { - return screen_iter; + if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) { + ScrArea *sa = screen_iter->areabase.first; + if (sa && sa->full == screen) { + return screen_iter; + } } } @@ -905,9 +913,7 @@ bScreen *screen_change_prepare( return NULL; } - if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) { - screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); - } + screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); /* check for valid winid */ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 9f452dd79e0..a94c0e35876 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -342,7 +342,7 @@ bool ED_operator_console_active(bContext *C) static bool ed_object_hidden(Object *ob) { /* if hidden but in edit mode, we still display, can happen with animation */ - return ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)); + return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT)); } bool ED_operator_object_active(bContext *C) @@ -631,24 +631,6 @@ static bool screen_active_editable(bContext *C) return 0; } -static ARegion *screen_find_region_type(bContext *C, int type) -{ - ARegion *ar = CTX_wm_region(C); - - /* find the header region - * - try context first, but upon failing, search all regions in area... - */ - if ((ar == NULL) || (ar->regiontype != type)) { - ScrArea *sa = CTX_wm_area(C); - ar = BKE_area_find_region_type(sa, type); - } - else { - ar = NULL; - } - - return ar; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -2431,7 +2413,7 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge) /* regions in regions. */ if (scalear->alignment & RGN_SPLIT_PREV) { - const int align = scalear->alignment & RGN_ALIGN_ENUM_MASK; + const int align = RGN_ALIGN_ENUM_FROM_MASK(scalear->alignment); if (ELEM(align, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { ARegion *ar = scalear->prev; @@ -3582,6 +3564,12 @@ static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } +static bool repeat_last_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_repeat_last(wmOperatorType *ot) { /* identifiers */ @@ -3592,7 +3580,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) /* api callbacks */ ot->exec = repeat_last_exec; - ot->poll = ED_operator_screenactive; + ot->poll = repeat_last_poll; } /** \} */ @@ -3645,6 +3633,12 @@ static int repeat_history_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool repeat_history_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_repeat_history(wmOperatorType *ot) { /* identifiers */ @@ -3656,7 +3650,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) ot->invoke = repeat_history_invoke; ot->exec = repeat_history_exec; - ot->poll = ED_operator_screenactive; + ot->poll = repeat_history_poll; RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); } @@ -3678,6 +3672,12 @@ static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent * return OPERATOR_CANCELLED; } +static bool redo_last_poll(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return ED_operator_screenactive(C) && !BLI_listbase_is_empty(&wm->operators); +} + static void SCREEN_OT_redo_last(wmOperatorType *ot) { /* identifiers */ @@ -3688,7 +3688,7 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) /* api callbacks */ ot->invoke = redo_last_invoke; - ot->poll = ED_operator_screenactive; + ot->poll = redo_last_poll; } /** \} */ @@ -3955,10 +3955,10 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Header Tools Operator +/** \name Region Context Menu Operator (Header/Footer/Navbar) * \{ */ -static bool header_context_menu_poll(bContext *C) +static bool screen_region_context_menu_poll(bContext *C) { ScrArea *sa = CTX_wm_area(C); return (sa && sa->spacetype != SPACE_STATUSBAR); @@ -4008,89 +4008,17 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN } } -static int header_context_menu_invoke(bContext *C, - wmOperator *UNUSED(op), - const wmEvent *UNUSED(event)) -{ - uiPopupMenu *pup; - uiLayout *layout; - - pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - ED_screens_header_tools_menu_create(C, layout, NULL); - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; -} - -static void SCREEN_OT_header_context_menu(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Header Context Menu"; - ot->description = "Display header region context menu"; - ot->idname = "SCREEN_OT_header_context_menu"; - - /* api callbacks */ - ot->poll = header_context_menu_poll; - ot->invoke = header_context_menu_invoke; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Footer Toggle Operator - * \{ */ - -static int footer_exec(bContext *C, wmOperator *UNUSED(op)) -{ - ARegion *ar = screen_find_region_type(C, RGN_TYPE_FOOTER); - - if (ar == NULL) { - return OPERATOR_CANCELLED; - } - - ar->flag ^= RGN_FLAG_HIDDEN; - - ED_area_tag_redraw(CTX_wm_area(C)); - - WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -static void SCREEN_OT_footer(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Toggle Footer"; - ot->description = "Toggle footer display"; - ot->idname = "SCREEN_OT_footer"; - - /* api callbacks */ - ot->exec = footer_exec; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Footer Tools Operator - * \{ */ - -static bool footer_context_menu_poll(bContext *C) -{ - ScrArea *sa = CTX_wm_area(C); - return sa; -} - void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : IFACE_("Flip to Top"); - - uiItemO(layout, IFACE_("Toggle Footer"), ICON_NONE, "SCREEN_OT_footer"); + { + PointerRNA ptr; + RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr); + uiItemR(layout, &ptr, "show_region_footer", 0, IFACE_("Show Footer"), ICON_NONE); + } /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); @@ -4107,51 +4035,58 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN } } -static int footer_context_menu_invoke(bContext *C, +void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) +{ + const ARegion *ar = CTX_wm_region(C); + const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : + IFACE_("Flip to Left"); + + /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip"); +} + +static int screen_context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; + const ARegion *ar = CTX_wm_region(C); - pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE); - layout = UI_popup_menu_layout(pup); - - ED_screens_footer_tools_menu_create(C, layout, NULL); - - UI_popup_menu_end(C, pup); + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { + pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_header_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } + else if (ar->regiontype == RGN_TYPE_FOOTER) { + pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_footer_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } + else if (ar->regiontype == RGN_TYPE_NAV_BAR) { + pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE); + layout = UI_popup_menu_layout(pup); + ED_screens_navigation_bar_tools_menu_create(C, layout, NULL); + UI_popup_menu_end(C, pup); + } return OPERATOR_INTERFACE; } -static void SCREEN_OT_footer_context_menu(wmOperatorType *ot) +static void SCREEN_OT_region_context_menu(wmOperatorType *ot) { /* identifiers */ - ot->name = "Footer Context Menu"; - ot->description = "Display footer region context menu"; - ot->idname = "SCREEN_OT_footer_context_menu"; + ot->name = "Region Context Menu"; + ot->description = "Display region context menu"; + ot->idname = "SCREEN_OT_region_context_menu"; /* api callbacks */ - ot->poll = footer_context_menu_poll; - ot->invoke = footer_context_menu_invoke; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Navigation Bar Tools Menu - * \{ */ - -void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) -{ - const ARegion *ar = CTX_wm_region(C); - const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : - IFACE_("Flip to Left"); - - /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */ - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); - - uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip"); + ot->poll = screen_region_context_menu_poll; + ot->invoke = screen_context_menu_invoke; } /** \} */ @@ -5299,9 +5234,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_region_scale); WM_operatortype_append(SCREEN_OT_region_flip); WM_operatortype_append(SCREEN_OT_header_toggle_menus); - WM_operatortype_append(SCREEN_OT_header_context_menu); - WM_operatortype_append(SCREEN_OT_footer); - WM_operatortype_append(SCREEN_OT_footer_context_menu); + WM_operatortype_append(SCREEN_OT_region_context_menu); WM_operatortype_append(SCREEN_OT_screen_set); WM_operatortype_append(SCREEN_OT_screen_full_area); WM_operatortype_append(SCREEN_OT_back_to_previous); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 6294a64af0f..863e3a15120 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -165,7 +165,9 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager } screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win); - BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new); + if (BKE_workspace_layout_screen_get(layout_new) != screen_new) { + layout_new = BKE_workspace_layout_find(workspace_new, screen_new); + } if (screen_new == NULL) { return false; @@ -371,13 +373,15 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) &bmain->workspaces, idname, offsetof(ID, name) + 2); BLI_assert(appended_workspace != NULL); - /* Reorder to last position. */ - BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); + if (appended_workspace) { + /* Reorder to last position. */ + BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); - /* Changing workspace changes context. Do delayed! */ - WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); + /* Changing workspace changes context. Do delayed! */ + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; + } } return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 5a45f4946f2..f7a589350f9 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -47,6 +47,7 @@ #include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_brush.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -154,7 +155,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int } } - ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_mark_dirty(ima, ibuf); if (tmpibuf) { IMB_freeImBuf(tmpibuf); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 0737218eea4..303c3fac363 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1837,7 +1837,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) false); } - pjIma->ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf); /* tile ready, publish */ if (tinf->lock) { BLI_spin_lock(tinf->lock); @@ -1895,7 +1895,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps, /* other thread may be initializing the tile so wait here */ while (projima->undoRect[tile_index] == TILE_PENDING) { - ; + /* pass */ } BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y))); @@ -6188,7 +6188,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) w, h, IB_rect, - V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, @@ -6394,7 +6393,7 @@ static const EnumPropertyItem layer_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -static Image *proj_paint_image_create(wmOperator *op, Main *bmain) +static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data) { Image *ima; float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; @@ -6417,6 +6416,11 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain) ima = BKE_image_add_generated( bmain, width, height, imagename, alpha ? 32 : 24, use_float, gen_type, color, false); + if (is_data) { + STRNCPY(ima->colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA)); + } + return ima; } @@ -6487,6 +6491,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) if (ma) { Main *bmain = CTX_data_main(C); int type = RNA_enum_get(op->ptr, "type"); + bool is_data = (type > LAYER_BASE_COLOR); bNode *imanode; bNodeTree *ntree = ma->nodetree; @@ -6501,7 +6506,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) /* try to add an image node */ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); - ima = proj_paint_image_create(op, bmain); + ima = proj_paint_image_create(op, bmain, is_data); imanode->id = &ima->id; nodeSetActive(ntree, imanode); @@ -6553,12 +6558,6 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) } } - if (type > LAYER_BASE_COLOR) { - /* This is a "non color data" image */ - NodeTexImage *tex = imanode->storage; - tex->color_space = SHD_COLORSPACE_NONE; - } - /* Check if the socket in already connected to something */ bNodeLink *link = in_sock ? in_sock->link : NULL; if (in_sock != NULL && link == NULL) { diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index b80144ac4af..bb73d424152 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -349,7 +349,9 @@ static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map) undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); + BKE_image_mark_dirty(ima, ibuf); GPU_free_image(ima); /* force OpenGL reload */ + if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ } diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 6d003820723..c8ad1b5781d 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -71,6 +71,7 @@ #include "BLI_sys_types.h" #include "ED_mesh.h" /* for face mask functions */ +#include "ED_select_buffer_utils.h" #include "WM_api.h" #include "WM_types.h" @@ -389,7 +390,8 @@ static int imapaint_pick_face(ViewContext *vc, } /* sample only on the exact position */ - *r_index = ED_view3d_select_id_sample(vc, mval[0], mval[1]); + ED_view3d_select_id_validate(vc); + *r_index = ED_select_buffer_sample_point(mval); if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) { return 0; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index c1c2964156f..b6a6c897606 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -161,7 +161,7 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot) ot->poll = weight_from_bones_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; /* properties */ ot->prop = RNA_def_enum( @@ -695,7 +695,7 @@ static void gradientVertInit__mapFunc(void *userData, static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; - WPGradient_vertStoreBase *vert_cache = gesture->userdata; + WPGradient_vertStoreBase *vert_cache = gesture->user_data.data; int ret = WM_gesture_straightline_modal(C, op, event); if (ret & OPERATOR_RUNNING_MODAL) { @@ -751,15 +751,15 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) WPGradient_userData data = {NULL}; if (is_interactive) { - if (gesture->userdata == NULL) { - gesture->userdata = MEM_mallocN(sizeof(WPGradient_vertStoreBase) + - (sizeof(WPGradient_vertStore) * me->totvert), - __func__); - gesture->userdata_free = false; + if (gesture->user_data.data == NULL) { + gesture->user_data.data = MEM_mallocN(sizeof(WPGradient_vertStoreBase) + + (sizeof(WPGradient_vertStore) * me->totvert), + __func__); + gesture->user_data.use_free = false; data.is_init = true; wpaint_prev_create( - &((WPGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert); + &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, me->dvert, me->totvert); /* on init only, convert face -> vert sel */ if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { @@ -767,7 +767,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) } } - vert_cache = gesture->userdata; + vert_cache = gesture->user_data.data; } else { if (ED_wpaint_ensure_data(C, op->reports, 0, NULL) == false) { @@ -880,7 +880,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot) ot->cancel = WM_gesture_straightline_cancel; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 3356edd6b36..36cc3605273 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -600,7 +600,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm if (do_island_optimization && (element->island != island_index)) { /* skip this uv if not on the active island */ for (; element->next && !(element->next->separate); element = element->next) { - ; + /* pass */ } continue; } diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 25c05e2d1d0..381173999c4 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -136,7 +136,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) id_us_min(&sound->id); RNA_id_pointer_create(&sound->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index db504272d2f..bc7f8a0f79d 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -155,7 +155,7 @@ static void actedit_change_action(bContext *C, bAction *act) RNA_id_pointer_create((ID *)act, &idptr); /* set the new pointer, and force a refresh */ - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -261,7 +261,7 @@ static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) * NOTE: we can't use actedit_change_action, as this function is also called from the NLA */ RNA_id_pointer_create(&action->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } @@ -619,7 +619,7 @@ void ED_animedit_unlink_action( prop = RNA_struct_find_property(&ptr, "action"); /* clear... */ - RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL); + RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL, NULL); RNA_property_update(C, &ptr, prop); } } diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9827967f947..f32207fe08b 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -71,68 +71,50 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) int filter; View2D *v2d = &ar->v2d; - float y = 0.0f; size_t items; - int height; /* build list of channels to draw */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - if (height > BLI_rcti_size_y(&v2d->mask)) { - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - } + int height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; + /* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */ UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); /* loop through channels, and set up drawing depending on their type */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } } { /* second pass: widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } UI_block_end(C, block); @@ -159,8 +141,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) bDopeSheet *ads = &saction->ads; AnimData *adt = NULL; - float y; - unsigned char col1[4], col2[4]; unsigned char col1a[4], col2a[4]; unsigned char col1b[4], col2b[4]; @@ -181,14 +161,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); - - /* first backdrop strips */ - y = (float)(-ACHANNEL_HEIGHT(ac)); + int height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -197,13 +171,15 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) GPU_blend(true); - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + /* first backdrop strips */ + float ymax = ACHANNEL_FIRST_TOP(ac); + + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); int sel = 0; @@ -264,11 +240,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* draw region twice: firstly backdrop, then the current range */ - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } else if (ac->datatype == ANIMCONT_GPENCIL) { unsigned char *color; @@ -285,44 +257,25 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* frames less than one get less saturated background */ immUniformColor4ubv(color); - immRectf(pos, - 0.0f, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmin, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax); /* frames one and higher get a saturated background */ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ unsigned char *color = sel ? col1 : col2; immUniformColor4ubv(color); - immRectf(pos, - 0.0f, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmin, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax); /* frames one and higher get a saturated background */ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2)); - immRectf(pos, - v2d->cur.xmin, - (float)y - ACHANNEL_HEIGHT_HALF(ac), - v2d->cur.xmax + EXTRA_SCROLL_PAD, - (float)y + ACHANNEL_HEIGHT_HALF(ac)); + immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax); } } } - - /* Increment the step */ - y -= ACHANNEL_STEP(ac); } GPU_blend(false); @@ -342,21 +295,21 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) * This is to try to optimize this for heavier data sets * 2) Keyframes which are out of view horizontally are disregarded */ - y = (float)(-ACHANNEL_HEIGHT(ac)); - int action_flag = saction->flag; if (saction->mode == SACTCONT_TIMELINE) { action_flag &= ~(SACTION_SHOW_INTERPOLATION | SACTION_SHOW_EXTREMES); } - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + ymax = ACHANNEL_FIRST_TOP(ac); + + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); + float ycenter = (ymin + ymax) / 2.0f; /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* check if anything to show for this channel */ if (ale->datatype != ALE_NONE) { adt = ANIM_nla_mapping_get(ac, ale); @@ -364,34 +317,32 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: - draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, action_flag); + draw_summary_channel(v2d, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_SCE: - draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + draw_scene_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_OB: - draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, action_flag); + draw_object_channel(v2d, ads, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_ACT: - draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + draw_action_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GROUP: - draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, action_flag); + draw_agroup_channel(v2d, adt, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_FCURVE: - draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, action_flag); + draw_fcurve_channel(v2d, adt, ale->key_data, ycenter, ac->yscale_fac, action_flag); break; case ALE_GPFRAME: - draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + draw_gpl_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; case ALE_MASKLAY: - draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, action_flag); + draw_masklay_channel(v2d, ads, ale->data, ycenter, ac->yscale_fac, action_flag); break; } } } - - y -= ACHANNEL_STEP(ac); } /* free temporary channels used for drawing */ @@ -460,7 +411,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene) } GPU_matrix_push(); - GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs); + GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_HANDLES + yoffs); GPU_matrix_scale_2f(1.0, cache_draw_height); switch (pid->type) { diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 8df773e98d6..7fc84db3f75 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -325,24 +325,23 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, /* NOTE: not bool, since we want prioritise individual channels over expanders */ short found = 0; - float y; /* get all items - we need to do it this way */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ - y = (float)ACHANNEL_FIRST(ac); + float ymax = ACHANNEL_FIRST_TOP(ac); - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); /* must be selected... */ if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ - *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + *min = ymax - ACHANNEL_HEIGHT(ac); + *max = ymax; /* is this high enough priority yet? */ found = acf->channel_role; @@ -354,9 +353,6 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, break; } } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); } /* free all temp data */ @@ -983,8 +979,7 @@ static bool delete_action_keys(bAnimContext *ac) changed = delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 1614e1c432d..1371305487e 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -47,6 +47,7 @@ #include "BKE_gpencil.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_gpencil.h" @@ -230,7 +231,6 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho KeyframeEditFunc ok_cb, select_cb; View2D *v2d = &ac->ar->v2d; rctf rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); /* Convert mouse coordinates to frame ranges and channel * coordinates corrected for view pan/zoom. */ @@ -254,12 +254,14 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); + float ymax = ACHANNEL_FIRST_TOP(ac); + /* loop over data, doing box select */ - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); + float ymin = ymax - ACHANNEL_STEP(ac); /* set horizontal range (if applicable) */ if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { @@ -314,9 +316,6 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho } } } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; } /* cleanup */ @@ -418,7 +417,6 @@ static void region_select_action_keys( KeyframeEditFunc ok_cb, select_cb; View2D *v2d = &ac->ar->v2d; rctf rectf, scaled_rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); /* Convert mouse coordinates to frame ranges and channel * coordinates corrected for view pan/zoom. */ @@ -448,15 +446,17 @@ static void region_select_action_keys( ked.data = &scaled_rectf; } + float ymax = ACHANNEL_FIRST_TOP(ac); + /* loop over data, doing region select */ - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac)) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP(ac); + float ymin = ymax - ACHANNEL_STEP(ac); /* compute midpoint of channel (used for testing if the key is in the region or not) */ - ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac); + ked.channel_y = (ymin + ymax) / 2.0f; /* if channel is mapped in NLA, apply correction * - Apply to the bounds being checked, not all the keyframe points, @@ -520,9 +520,6 @@ static void region_select_action_keys( break; } } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; } /* cleanup */ @@ -1453,7 +1450,7 @@ static void mouse_action_keys(bAnimContext *ac, /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); UI_view2d_listview_view_to_cell( - v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); + 0, ACHANNEL_STEP(ac), 0, ACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale * (in screen/region-space), on either side of mouse click (size of keyframe icon). diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 843abbd16db..972f19bb643 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -45,6 +45,7 @@ #include "WM_types.h" #include "WM_message.h" +#include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -52,6 +53,7 @@ #include "ED_screen.h" #include "ED_anim_api.h" #include "ED_markers.h" +#include "ED_time_scrub_ui.h" #include "action_intern.h" /* own include */ #include "GPU_framebuffer.h" @@ -69,7 +71,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene) saction->autosnap = SACTSNAP_FRAME; saction->mode = SACTCONT_DOPESHEET; saction->mode_prev = SACTCONT_DOPESHEET; - saction->flag = SACTION_SHOW_INTERPOLATION; + saction->flag = SACTION_SHOW_INTERPOLATION | SACTION_SHOW_MARKER_LINES; saction->ads.filterflag |= ADS_FILTER_SUMMARY; @@ -125,7 +127,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -234,20 +236,13 @@ static void action_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* scrubbing region */ + ED_scrubbing_draw(ar, scene, saction->flag & SACTION_DRAWTIME, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, saction->flag & SACTION_DRAWTIME); - - /* draw current frame number-indicator on top of scrollers */ - if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); - } } /* add handlers, stuff you only do once or on area/region changes */ @@ -285,6 +280,9 @@ static void action_channel_region_draw(const bContext *C, ARegion *ar) draw_channel_names((bContext *)C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -869,7 +867,7 @@ void ED_spacetype_action(void) art->draw = action_main_region_draw; art->listener = action_main_region_listener; art->message_subscribe = saction_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -901,7 +899,7 @@ void ED_spacetype_action(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI; art->listener = action_region_listener; art->init = action_buttons_area_init; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 607c3ddbb10..fde8b8f85f8 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -785,6 +785,10 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r SpaceProperties *sbuts = CTX_wm_space_properties(C); ButsContextPath *path = sbuts ? sbuts->path : NULL; + if (sbuts->mainb == BCONTEXT_TOOL) { + return 0; + } + if (!path) { return 0; } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index fe4ed0209bf..500efe4bb4d 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -56,15 +56,10 @@ static int context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - const ARegion *ar = CTX_wm_region(C); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Context Menu"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); uiItemM(layout, "INFO_MT_area", NULL, ICON_NONE); - if (ar->regiontype == RGN_TYPE_NAV_BAR) { - ED_screens_navigation_bar_tools_menu_create(C, layout, NULL); - } - UI_popup_menu_end(C, pup); return OPERATOR_INTERFACE; diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index f9244049d54..9b0150d731d 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -34,6 +34,7 @@ #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_view3d.h" /* To draw toolbar UI. */ #include "WM_api.h" #include "WM_types.h" @@ -198,105 +199,7 @@ static void buttons_main_region_layout_properties(const bContext *C, } const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts, sbuts->mainb, vertical); -} - -static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar) -{ - const enum eContextObjectMode mode = CTX_data_mode_enum(C); - - const char *contexts_base[5] = {NULL}; - contexts_base[0] = ".active_tool"; - const char **contexts = &contexts_base[1]; - - /* Hard coded to 3D view. */ - { - switch (mode) { - case CTX_MODE_EDIT_MESH: - ARRAY_SET_ITEMS(contexts, ".mesh_edit"); - break; - case CTX_MODE_EDIT_CURVE: - ARRAY_SET_ITEMS(contexts, ".curve_edit"); - break; - case CTX_MODE_EDIT_SURFACE: - ARRAY_SET_ITEMS(contexts, ".curve_edit"); - break; - case CTX_MODE_EDIT_TEXT: - ARRAY_SET_ITEMS(contexts, ".text_edit"); - break; - case CTX_MODE_EDIT_ARMATURE: - ARRAY_SET_ITEMS(contexts, ".armature_edit"); - break; - case CTX_MODE_EDIT_METABALL: - ARRAY_SET_ITEMS(contexts, ".mball_edit"); - break; - case CTX_MODE_EDIT_LATTICE: - ARRAY_SET_ITEMS(contexts, ".lattice_edit"); - break; - case CTX_MODE_POSE: - ARRAY_SET_ITEMS(contexts, ".posemode"); - break; - case CTX_MODE_SCULPT: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".sculpt_mode"); - break; - case CTX_MODE_PAINT_WEIGHT: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".weightpaint"); - break; - case CTX_MODE_PAINT_VERTEX: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".vertexpaint"); - break; - case CTX_MODE_PAINT_TEXTURE: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".imagepaint"); - break; - case CTX_MODE_PARTICLE: - ARRAY_SET_ITEMS(contexts, ".paint_common", ".particlemode"); - break; - case CTX_MODE_OBJECT: - ARRAY_SET_ITEMS(contexts, ".objectmode"); - break; - case CTX_MODE_PAINT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); - break; - case CTX_MODE_SCULPT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); - break; - case CTX_MODE_WEIGHT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); - break; - default: - break; - } - } - - /* for grease pencil we don't use tool system yet, so we need check outside - * workspace->tools_space_type because this value is not available - */ - switch (mode) { - case CTX_MODE_PAINT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); - break; - case CTX_MODE_SCULPT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); - break; - case CTX_MODE_WEIGHT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); - break; - case CTX_MODE_EDIT_GPENCIL: - ARRAY_SET_ITEMS(contexts, ".greasepencil_edit"); - break; - default: - break; - } - - int i = 0; - while (contexts_base[i]) { - i++; - } - BLI_assert(i < ARRAY_SIZE(contexts_base)); - contexts_base[i] = ".workspace"; - - const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts_base, -1, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts, sbuts->mainb, vertical, NULL); } static void buttons_main_region_layout(const bContext *C, ARegion *ar) @@ -305,7 +208,7 @@ static void buttons_main_region_layout(const bContext *C, ARegion *ar) SpaceProperties *sbuts = CTX_wm_space_properties(C); if (sbuts->mainb == BCONTEXT_TOOL) { - buttons_main_region_layout_tool(C, ar); + ED_view3d_buttons_region_layout_ex(C, ar, "Tool"); } else { buttons_main_region_layout_properties(C, sbuts, ar); @@ -400,9 +303,6 @@ static void buttons_header_region_message_subscribe(const bContext *UNUSED(C), static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Property Editor", SPACE_PROPERTIES, 0); - WM_event_add_keymap_handler(&ar->handlers, keymap); - ar->flag |= RGN_FLAG_PREFSIZE_OR_HIDDEN; ED_region_panels_init(wm, ar); @@ -749,7 +649,7 @@ void ED_spacetype_buttons(void) art->regionid = RGN_TYPE_NAV_BAR; art->prefsizex = AREAMINX - 3; /* XXX Works and looks best, * should we update AREAMINX accordingly? */ - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_NAVBAR; art->init = buttons_navigation_bar_region_init; art->draw = buttons_navigation_bar_region_draw; art->message_subscribe = buttons_navigation_bar_region_message_subscribe; diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index c985d61a8b8..2496b16ffae 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -808,12 +808,13 @@ void uiTemplateMovieclipInformation(uiLayout *layout, user = userptr->data; col = uiLayoutColumn(layout, false); + uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT); ibuf = BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, MOVIECLIP_CACHE_SKIP); /* Display frame dimensions, channels number and byffer type. */ BKE_movieclip_get_size(clip, user, &width, &height); - ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Size %d x %d"), width, height); + ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("%d x %d"), width, height); if (ibuf) { if (ibuf->rect_float) { diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 70dc1caf36f..081515ca4bc 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -35,7 +35,7 @@ struct bContext; struct wmOperatorType; /* channel heights */ -#define CHANNEL_FIRST (-0.8f * U.widget_unit) +#define CHANNEL_FIRST (-UI_SCRUBBING_MARGIN_Y - CHANNEL_HEIGHT_HALF - CHANNEL_SKIP) #define CHANNEL_HEIGHT (0.8f * U.widget_unit) #define CHANNEL_HEIGHT_HALF (0.4f * U.widget_unit) #define CHANNEL_SKIP (0.1f * U.widget_unit) diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 3f971c4444a..710a46fdd51 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -245,7 +245,7 @@ static int open_exec(bContext *C, wmOperator *op) id_us_min(&clip->id); RNA_id_pointer_create(&clip->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } else if (sc) { @@ -955,10 +955,10 @@ static bool change_frame_poll(bContext *C) { /* prevent changes during render */ if (G.is_rendering) { - return 0; + return false; } - - return ED_space_clip_poll(C); + SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip != NULL; } static void change_frame_apply(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 542f99e49ee..f26175a6c57 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -47,6 +47,7 @@ #include "ED_mask.h" #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "ED_select_utils.h" #include "ED_clip.h" #include "ED_transform.h" @@ -94,7 +95,7 @@ static void init_preview_region(const Scene *scene, ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -115,8 +116,8 @@ static void init_preview_region(const Scene *scene, ar->v2d.max[0] = MAXFRAMEF; ar->v2d.max[1] = FLT_MAX; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.minzoom = 0.0f; ar->v2d.maxzoom = 0.0f; @@ -249,7 +250,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene) sc->zoom = 1.0f; sc->path_length = 20; sc->scopes.track_preview_height = 120; - sc->around = V3D_AROUND_LOCAL_ORIGINS; + sc->around = V3D_AROUND_CENTER_MEDIAN; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for clip"); @@ -1001,9 +1002,13 @@ static void clip_preview_region_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "Clip", SPACE_CLIP, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); + keymap = WM_keymap_ensure(wm->defaultconf, "Clip Scrubbing", SPACE_CLIP, RGN_TYPE_PREVIEW); + WM_event_add_keymap_handler_poll(&ar->handlers, keymap, ED_event_in_scrubbing_region); + keymap = WM_keymap_ensure(wm->defaultconf, "Clip Graph Editor", SPACE_CLIP, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); @@ -1041,22 +1046,24 @@ static void graph_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); /* scale indicators */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS); - UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert); - - /* current frame indicator */ - if (sc->flag & SC_SHOW_SECONDS) { - cfra_flag |= DRAWCFRA_UNIT_SECONDS; + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_TEXT); } - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); } static void dopesheet_region_draw(const bContext *C, ARegion *ar) @@ -1093,18 +1100,13 @@ static void dopesheet_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, sc->flag & SC_SHOW_SECONDS, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, sc->flag & SC_SHOW_SECONDS); - - /* current frame number indicator */ - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); } static void clip_preview_region_draw(const bContext *C, ARegion *ar) @@ -1369,7 +1371,7 @@ void ED_spacetype_clip(void) /* regions: properties */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region properties"); art->regionid = RGN_TYPE_UI; - art->prefsizex = UI_COMPACT_PANEL_WIDTH; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; art->init = clip_properties_region_init; art->draw = clip_properties_region_draw; @@ -1380,7 +1382,7 @@ void ED_spacetype_clip(void) /* regions: tools */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region tools"); art->regionid = RGN_TYPE_TOOLS; - art->prefsizex = UI_COMPACT_PANEL_WIDTH; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; art->listener = clip_props_region_listener; art->init = clip_tools_region_init; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 18d48b426e0..b51baafbcf5 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1299,6 +1299,12 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot) /********************** frame jump operator *********************/ +static bool frame_jump_poll(bContext *C) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + return space_clip != NULL; +} + static int frame_jump_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -1377,7 +1383,7 @@ void CLIP_OT_frame_jump(wmOperatorType *ot) /* api callbacks */ ot->exec = frame_jump_exec; - ot->poll = ED_space_clip_poll; + ot->poll = frame_jump_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index bb8680682d2..6b3baa1e766 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -478,7 +478,7 @@ static void file_draw_preview(uiBlock *block, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); if (icon) { - UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f, NULL); + UI_icon_draw_ex((float)xco, (float)yco, icon, icon_aspect, 1.0f, 0.0f, NULL, false); } /* border */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 674735f3e1d..5ac7ff72aed 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1011,7 +1011,7 @@ static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op)) BLI_make_file_string( "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu, name); - fsmenu_refresh_bookmarks_status(fsmenu); + fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu); ED_area_tag_refresh(sa); ED_area_tag_redraw(sa); } @@ -1567,6 +1567,9 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) /* refresh system directory menu */ fsmenu_refresh_system_category(fsmenu); + /* Update bookmarks 'valid' state. */ + fsmenu_refresh_bookmarks_status(wm, fsmenu); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 38423a87447..b50c37baae6 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -44,6 +44,9 @@ # include "BLI_winstuff.h" #endif +#include "WM_api.h" +#include "WM_types.h" + #ifdef __APPLE__ # include <Carbon/Carbon.h> #endif /* __APPLE__ */ @@ -721,31 +724,59 @@ void fsmenu_refresh_system_category(struct FSMenu *fsmenu) fsmenu_read_system(fsmenu, true); } -void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu) +static void fsmenu_free_ex(FSMenu **fsmenu) { - int categories[] = { - FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; - int i; - - for (i = sizeof(categories) / sizeof(*categories); i--;) { - FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); - for (; fsm_iter; fsm_iter = fsm_iter->next) { - fsmenu_entry_refresh_valid(fsm_iter); - } + if (*fsmenu != NULL) { + fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM); + fsmenu_free_category(*fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); + fsmenu_free_category(*fsmenu, FS_CATEGORY_BOOKMARKS); + fsmenu_free_category(*fsmenu, FS_CATEGORY_RECENT); + MEM_freeN(*fsmenu); } + + *fsmenu = NULL; } void fsmenu_free(void) { - if (g_fsmenu) { - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT); - MEM_freeN(g_fsmenu); + fsmenu_free_ex(&g_fsmenu); +} + +static void fsmenu_copy_category(struct FSMenu *fsmenu_dst, + struct FSMenu *fsmenu_src, + const FSMenuCategory category) +{ + FSMenuEntry *fsm_dst_prev = NULL, *fsm_dst_head = NULL; + FSMenuEntry *fsm_src_iter = ED_fsmenu_get_category(fsmenu_src, category); + + for (; fsm_src_iter != NULL; fsm_src_iter = fsm_src_iter->next) { + FSMenuEntry *fsm_dst = MEM_dupallocN(fsm_src_iter); + if (fsm_dst->path != NULL) { + fsm_dst->path = MEM_dupallocN(fsm_dst->path); + } + + if (fsm_dst_prev != NULL) { + fsm_dst_prev->next = fsm_dst; + } + else { + fsm_dst_head = fsm_dst; + } + fsm_dst_prev = fsm_dst; } - g_fsmenu = NULL; + ED_fsmenu_set_category(fsmenu_dst, category, fsm_dst_head); +} + +static FSMenu *fsmenu_copy(FSMenu *fsmenu) +{ + FSMenu *fsmenu_copy = MEM_dupallocN(fsmenu); + + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_SYSTEM_BOOKMARKS); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_BOOKMARKS); + fsmenu_copy_category(fsmenu_copy, fsmenu_copy, FS_CATEGORY_RECENT); + + return fsmenu_copy; } int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir) @@ -761,3 +792,99 @@ int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory categor return -1; } + +/* Thanks to some bookmarks sometimes being network drives that can have tens of seconds of delay + * before being defined as unreachable by the OS, we need to validate the bookmarks in an async + * job... + */ +static void fsmenu_bookmark_validate_job_startjob(void *fsmenuv, + short *stop, + short *do_update, + float *UNUSED(progress)) +{ + FSMenu *fsmenu = fsmenuv; + + int categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; + + for (size_t i = ARRAY_SIZE(categories); i--;) { + FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); + for (; fsm_iter; fsm_iter = fsm_iter->next) { + if (*stop) { + return; + } + /* Note that we do not really need atomics primitives or thread locks here, since this only + * sets one short, which is assumed to be 'atomic'-enough for us here. */ + fsmenu_entry_refresh_valid(fsm_iter); + *do_update = true; + } + } +} + +static void fsmenu_bookmark_validate_job_update(void *fsmenuv) +{ + FSMenu *fsmenu_job = fsmenuv; + + int categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; + + for (size_t i = ARRAY_SIZE(categories); i--;) { + FSMenuEntry *fsm_iter_src = ED_fsmenu_get_category(fsmenu_job, categories[i]); + FSMenuEntry *fsm_iter_dst = ED_fsmenu_get_category(ED_fsmenu_get(), categories[i]); + for (; fsm_iter_dst != NULL; fsm_iter_dst = fsm_iter_dst->next) { + while (fsm_iter_src != NULL && !STREQ(fsm_iter_dst->path, fsm_iter_src->path)) { + fsm_iter_src = fsm_iter_src->next; + } + if (fsm_iter_src == NULL) { + return; + } + fsm_iter_dst->valid = fsm_iter_src->valid; + } + } +} + +static void fsmenu_bookmark_validate_job_end(void *fsmenuv) +{ + /* In case there would be some dangling update... */ + fsmenu_bookmark_validate_job_update(fsmenuv); +} + +static void fsmenu_bookmark_validate_job_free(void *fsmenuv) +{ + FSMenu *fsmenu = fsmenuv; + fsmenu_free_ex(&fsmenu); +} + +static void fsmenu_bookmark_validate_job_start(wmWindowManager *wm) +{ + wmJob *wm_job; + FSMenu *fsmenu_job = fsmenu_copy(g_fsmenu); + + /* setup job */ + wm_job = WM_jobs_get( + wm, wm->winactive, wm, "Validating Bookmarks...", 0, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE); + WM_jobs_customdata_set(wm_job, fsmenu_job, fsmenu_bookmark_validate_job_free); + WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_callbacks(wm_job, + fsmenu_bookmark_validate_job_startjob, + NULL, + fsmenu_bookmark_validate_job_update, + fsmenu_bookmark_validate_job_end); + + /* start the job */ + WM_jobs_start(wm, wm_job); +} + +static void fsmenu_bookmark_validate_job_stop(wmWindowManager *wm) +{ + WM_jobs_kill_type(wm, wm, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE); +} + +void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu) +{ + BLI_assert(fsmenu == ED_fsmenu_get()); + UNUSED_VARS_NDEBUG(fsmenu); + + fsmenu_bookmark_validate_job_stop(wm); + fsmenu_bookmark_validate_job_start(wm); +} diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h index cb0dccf0499..d9850cb855d 100644 --- a/source/blender/editors/space_file/fsmenu.h +++ b/source/blender/editors/space_file/fsmenu.h @@ -68,7 +68,7 @@ void fsmenu_free(void); void fsmenu_refresh_system_category(struct FSMenu *fsmenu); /** Refresh 'valid' status of all menu entries */ -void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu); +void fsmenu_refresh_bookmarks_status(struct wmWindowManager *wm, struct FSMenu *fsmenu); /** Get active index based on given directory. */ int fsmenu_get_active_indices(struct FSMenu *fsmenu, diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 9fb07042104..1fd878e4662 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -142,18 +142,16 @@ static void file_free(SpaceLink *sl) } /* spacetype; init callback, area size changes, screen set, etc */ -static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) +static void file_init(wmWindowManager *wm, ScrArea *sa) { SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + struct FSMenu *fsmenu = ED_fsmenu_get(); /* refresh system directory list */ - fsmenu_refresh_system_category(ED_fsmenu_get()); + fsmenu_refresh_system_category(fsmenu); - /* Update bookmarks 'valid' state. - * Done here, because it seems BLI_is_dir() can have huge impact on performances - * in some cases, on win systems... See T43684. - */ - fsmenu_refresh_bookmarks_status(ED_fsmenu_get()); + /* Update bookmarks 'valid' state. */ + fsmenu_refresh_bookmarks_status(wm, fsmenu); if (sfile->layout) { sfile->layout->dirty = true; diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index dfc59a79c49..062c9f86fab 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -1230,9 +1230,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) int filter; View2D *v2d = &ar->v2d; - float y = 0.0f, height; + float height; size_t items; - int i = 0; /* build list of channels to draw */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); @@ -1240,62 +1239,47 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) /* Update max-extent of channels here (taking into account scrollers): * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2)); - UI_view2d_totRect_set(v2d, BLI_rcti_size_x(&ar->v2d.mask), height); + * to avoid regenerating the list again and/or also because channels list is drawn first */ + height = ACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; /* loop through channels, and set up drawing depending on their type */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = ACHANNEL_FIRST_TOP(ac); - y = (float)ACHANNEL_FIRST(ac); - - for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } } { /* second pass: widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - - y = (float)ACHANNEL_FIRST(ac); + float ymax = ACHANNEL_FIRST_TOP(ac); /* set blending again, as may not be set in previous step */ GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); GPU_blend(true); - for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); + for (ale = anim_data.first; ale; ale = ale->next, ymax -= ACHANNEL_STEP(ac), channel_index++) { + float ymin = ymax - ACHANNEL_HEIGHT(ac); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax - V2D_SCROLL_WIDTH, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax - V2D_SCROLL_WIDTH, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= ACHANNEL_STEP(ac); - channel_index++; } UI_block_end(C, block); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 0954538e430..b3fafa09256 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -55,6 +55,7 @@ #include "DEG_depsgraph_build.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_anim_api.h" #include "ED_keyframing.h" @@ -282,10 +283,18 @@ static int graphkeys_viewall(bContext *C, do_sel_only, include_handles); + /* Give some more space at the borders. */ BLI_rctf_scale(&cur_new, 1.1f); - UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); + /* Take regions into account, that could block the view. */ + float pad_top = UI_SCRUBBING_MARGIN_Y; + float pad_bottom = 0; + if (!BLI_listbase_is_empty(ED_context_get_markers(C))) { + pad_bottom = UI_MARKER_MARGIN_Y; + } + BLI_rctf_pad_y(&cur_new, ac.ar->sizey * UI_DPI_FAC, pad_bottom, pad_top); + UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } @@ -1172,9 +1181,7 @@ static bool delete_graph_keys(bAnimContext *ac) } /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && - (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && - (fcu->driver == NULL)) { + if (BKE_fcurve_is_empty(fcu)) { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); ale->key_data = NULL; } @@ -2820,6 +2827,7 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) /* id-props */ prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_enum_funcs(prop, graph_fmodifier_itemf); ot->prop = prop; diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 13a42f091f6..5ea07c56286 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1141,7 +1141,7 @@ typedef enum eGraphVertIndex { /* Tolerance for absolute radius (in pixels) of the vert from the cursor to use */ // TODO: perhaps this should depend a bit on the size that the user set the vertices to be? -#define GVERTSEL_TOL 10 +#define GVERTSEL_TOL (10 * U.pixelsize) /* ....... */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 86d0b961a31..4e131c653f8 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -42,6 +42,7 @@ #include "ED_screen.h" #include "ED_anim_api.h" #include "ED_markers.h" +#include "ED_time_scrub_ui.h" #include "GPU_immediate.h" #include "GPU_state.h" @@ -57,6 +58,7 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "graph_intern.h" // own include @@ -79,7 +81,7 @@ static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene) /* settings for making it easier by default to just see what you're interested in tweaking */ sipo->ads->filterflag |= ADS_FILTER_ONLYSEL; - sipo->flag |= SIPO_SELVHANDLESONLY; + sipo->flag |= SIPO_SELVHANDLESONLY | SIPO_MARKER_LINES; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for graphedit"); @@ -124,8 +126,8 @@ static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene) ar->v2d.max[0] = MAXFRAMEF; ar->v2d.max[1] = FLT_MAX; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.keeptot = 0; @@ -291,12 +293,14 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) } /* markers */ - UI_view2d_view_orthoSpecial(ar, v2d, 1); - int marker_draw_flag = DRAW_MARKERS_MARGIN; - if (sipo->flag & SIPO_MARKER_LINES) { - marker_draw_flag |= DRAW_MARKERS_LINES; + if (sipo->mode != SIPO_MODE_DRIVERS) { + UI_view2d_view_orthoSpecial(ar, v2d, 1); + int marker_draw_flag = DRAW_MARKERS_MARGIN; + if (sipo->flag & SIPO_MARKER_LINES) { + marker_draw_flag |= DRAW_MARKERS_LINES; + } + ED_markers_draw(C, marker_draw_flag); } - ED_markers_draw(C, marker_draw_flag); /* preview range */ UI_view2d_view_ortho(v2d); @@ -309,6 +313,9 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* time-scrubbing */ + ED_scrubbing_draw(ar, scene, display_seconds, false); + /* scrollers */ // FIXME: args for scrollers depend on the type of data being shown... scrollers = UI_view2d_scrollers_calc(v2d, NULL); @@ -316,13 +323,14 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); /* scale numbers */ - UI_view2d_draw_scale_x__frames_or_seconds(ar, v2d, &v2d->hor, scene, display_seconds); - UI_view2d_draw_scale_y__values(ar, v2d, &v2d->vert); - - /* draw current frame number-indicator on top of scrollers */ - if ((sipo->mode != SIPO_MODE_DRIVERS) && ((sipo->flag & SIPO_NODRAWCFRANUM) == 0)) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__values(ar, v2d, &rect, TH_SCROLL_TEXT); } } @@ -367,6 +375,9 @@ static void graph_channel_region_draw(const bContext *C, ARegion *ar) graph_draw_channel_names((bContext *)C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -849,7 +860,7 @@ void ED_spacetype_ipo(void) art->draw = graph_main_region_draw; art->listener = graph_region_listener; art->message_subscribe = graph_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -880,7 +891,7 @@ void ED_spacetype_ipo(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = graph_region_listener; art->init = graph_buttons_region_init; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 752eedebe71..b32f5ef6d9e 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -42,6 +42,7 @@ #include "RE_pipeline.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -62,81 +63,6 @@ #define B_NOP -1 #define MAX_IMAGE_INFO_LEN 128 -/* proto */ - -static void image_info( - Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str, size_t len) -{ - size_t ofs = 0; - - str[0] = 0; - if (ima == NULL) { - return; - } - - if (ibuf == NULL) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Can't Load Image"), len - ofs); - } - else { - if (ima->source == IMA_SRC_MOVIE) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs); - if (BKE_image_has_anim(ima)) { - ofs += BLI_snprintf( - str + ofs, - len - ofs, - IFACE_(" %d frs"), - IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN)); - } - } - else { - ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs); - } - - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y); - - if (ibuf->rect_float) { - if (ibuf->channels != 4) { - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels); - } - else if (ibuf->planes == R_IMF_PLANES_RGBA) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs); - } - else { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs); - } - } - else { - if (ibuf->planes == R_IMF_PLANES_RGBA) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs); - } - else { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs); - } - } - if (ibuf->zbuf || ibuf->zbuf_float) { - ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs); - } - - if (ima->source == IMA_SRC_SEQUENCE) { - const char *file = BLI_last_slash(ibuf->name); - if (file == NULL) { - file = ibuf->name; - } - else { - file++; - } - ofs += BLI_snprintf(str + ofs, len - ofs, ", %s", file); - } - } - - /* the frame number, even if we cant */ - if (ima->source == IMA_SRC_SEQUENCE) { - /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ - const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL); - ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(", Frame: %d"), framenr); - } -} - /* gets active viewer user */ struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree) { @@ -650,23 +576,6 @@ static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v)) WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); } -#if 0 -static void image_freecache_cb(bContext *C, void *ima_v, void *unused) -{ - Scene *scene = CTX_data_scene(C); - BKE_image_free_anim_ibufs(ima_v, scene->r.cfra); - WM_event_add_notifier(C, NC_IMAGE, ima_v); -} -#endif - -#if 0 -static void image_user_change(bContext *C, void *iuser_v, void *unused) -{ - Scene *scene = CTX_data_scene(C); - BKE_image_user_calc_imanr(iuser_v, scene->r.cfra, 0); -} -#endif - static void uiblock_layer_pass_buttons( uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot) { @@ -839,6 +748,22 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) RNA_property_update(C, &cb->ptr, cb->prop); } +static bool image_has_alpha(Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); + if (ibuf == NULL) { + return false; + } + + int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions); + char valid_channels = BKE_imtype_valid_channels(imtype, false); + bool has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0; + + BKE_image_release_ibuf(ima, ibuf, NULL); + + return has_alpha; +} + void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, @@ -847,23 +772,11 @@ void uiTemplateImage(uiLayout *layout, bool compact, bool multiview) { - PropertyRNA *prop; - PointerRNA imaptr; - RNAUpdateCb *cb; - Image *ima; - ImageUser *iuser; - Scene *scene = CTX_data_scene(C); - uiLayout *row, *split, *col; - uiBlock *block; - char str[MAX_IMAGE_INFO_LEN]; - - void *lock; - if (!ptr->data) { return; } - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); @@ -878,23 +791,20 @@ void uiTemplateImage(uiLayout *layout, return; } - block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(layout); - imaptr = RNA_property_pointer_get(ptr, prop); - ima = imaptr.data; - iuser = userptr->data; + PointerRNA imaptr = RNA_property_pointer_get(ptr, prop); + Image *ima = imaptr.data; + ImageUser *iuser = userptr->data; + Scene *scene = CTX_data_scene(C); BKE_image_user_frame_calc(iuser, (int)scene->r.cfra); - cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); - cb->ptr = *ptr; - cb->prop = prop; - cb->iuser = iuser; - uiLayoutSetContextPointer(layout, "edit_image", &imaptr); uiLayoutSetContextPointer(layout, "edit_image_user", userptr); - if (!compact) { + SpaceImage *space_image = CTX_wm_space_image(C); + if (!compact && (space_image == NULL || iuser != &space_image->iuser)) { uiTemplateID(layout, C, ptr, @@ -904,217 +814,178 @@ void uiTemplateImage(uiLayout *layout, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); + + if (ima != NULL) { + uiItemS(layout); + } } - if (ima) { - UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL); - - if (ima->source == IMA_SRC_VIEWER) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); - BKE_image_release_ibuf(ima, ibuf, lock); - - uiItemL(layout, ima->id.name + 2, ICON_NONE); - uiItemL(layout, str, ICON_NONE); - - if (ima->type == IMA_TYPE_COMPOSITE) { - // XXX not working yet -#if 0 - iuser = ntree_get_active_iuser(scene->nodetree); - if (iuser) { - UI_block_align_begin(block); - uiDefIconTextBut(block, - UI_BTYPE_BUT, - B_SIMA_RECORD, - ICON_REC, - "Record", - 10, - 120, - 100, - 20, - 0, - 0, - 0, - 0, - 0, - ""); - uiDefIconTextBut(block, - UI_BTYPE_BUT, - B_SIMA_PLAY, - ICON_PLAY, - "Play", - 110, - 120, - 100, - 20, - 0, - 0, - 0, - 0, - 0, - ""); - but = uiDefBut( - block, UI_BTYPE_BUT, B_NOP, "Free Cache", 210, 120, 100, 20, 0, 0, 0, 0, 0, ""); - UI_but_func_set(but, image_freecache_cb, ima, NULL); - - if (iuser->frames) - BLI_snprintf(str, sizeof(str), "(%d) Frames:", iuser->framenr); - else - strcpy(str, "Frames:"); - UI_block_align_begin(block); - uiDefButI(block, - UI_BTYPE_NUM, - imagechanged, - str, - 10, - 90, - 150, - 20, - &iuser->frames, - 0.0, - MAXFRAMEF, - 0, - 0, - "Number of images of a movie to use"); - uiDefButI(block, - UI_BTYPE_NUM, - imagechanged, - "StartFr:", - 160, - 90, - 150, - 20, - &iuser->sfra, - 1.0, - MAXFRAMEF, - 0, - 0, - "Global starting frame of the movie"); - } -#endif - } - else if (ima->type == IMA_TYPE_R_RESULT) { - /* browse layer/passes */ - RenderResult *rr; - const float dpi_fac = UI_DPI_FAC; - const int menus_width = 230 * dpi_fac; - - /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ - rr = BKE_image_acquire_renderresult(scene, ima); - uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot); - BKE_image_release_renderresult(scene, ima); - } + if (ima == NULL) { + return; + } + + if (ima->source == IMA_SRC_VIEWER) { + /* Viewer images. */ + uiTemplateImageInfo(layout, C, ima, iuser); + + if (ima->type == IMA_TYPE_COMPOSITE) { + } + else if (ima->type == IMA_TYPE_R_RESULT) { + /* browse layer/passes */ + RenderResult *rr; + const float dpi_fac = UI_DPI_FAC; + const int menus_width = 230 * dpi_fac; + + /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ + rr = BKE_image_acquire_renderresult(scene, ima); + uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot); + BKE_image_release_renderresult(scene, ima); + } + + return; + } + + /* Set custom callback for property updates. */ + RNAUpdateCb *cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb"); + cb->ptr = *ptr; + cb->prop = prop; + cb->iuser = iuser; + UI_block_funcN_set(block, rna_update_cb, cb, NULL); + + /* Disable editing if image was modified, to avoid losing changes. */ + const bool is_dirty = BKE_image_is_dirty(ima); + if (is_dirty) { + uiLayout *row = uiLayoutRow(layout, true); + uiItemO(row, IFACE_("Save"), ICON_NONE, "image.save"); + uiItemO(row, IFACE_("Discard"), ICON_NONE, "image.reload"); + uiItemS(layout); + } + + layout = uiLayoutColumn(layout, false); + uiLayoutSetEnabled(layout, !is_dirty); + uiLayoutSetPropDecorate(layout, false); + + /* Image source */ + { + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiItemR(col, &imaptr, "source", 0, NULL, ICON_NONE); + } + + /* Filepath */ + const bool is_packed = BKE_image_has_packedfile(ima); + const bool no_filepath = is_packed && !BKE_image_has_filepath(ima); + + if ((ima->source != IMA_SRC_GENERATED) && !no_filepath) { + uiItemS(layout); + + uiLayout *row = uiLayoutRow(layout, true); + if (is_packed) { + uiItemO(row, "", ICON_PACKAGE, "image.unpack"); } else { - uiItemR(layout, &imaptr, "source", 0, NULL, ICON_NONE); + uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); + } - if (ima->source != IMA_SRC_GENERATED) { - row = uiLayoutRow(layout, true); - if (BKE_image_has_packedfile(ima)) { - uiItemO(row, "", ICON_PACKAGE, "image.unpack"); - } - else { - uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); - } + row = uiLayoutRow(row, true); + uiLayoutSetEnabled(row, is_packed == false); + uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); + } - row = uiLayoutRow(row, true); - uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false); - uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); - uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); - } + /* Image layers and Info */ + if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { + uiItemS(layout); - /* multilayer? */ - if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { - const float dpi_fac = UI_DPI_FAC; - uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL); - } - else if (ima->source != IMA_SRC_GENERATED) { - if (compact == 0) { - uiTemplateImageInfo(layout, C, ima, iuser); - } - } + const float dpi_fac = UI_DPI_FAC; + uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL); + } + else if (ima->source == IMA_SRC_GENERATED) { + uiItemS(layout); - col = uiLayoutColumn(layout, false); - uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); - uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); + /* Generated */ + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); - if (ima->source != IMA_SRC_GENERATED) { - if (compact == 0) { /* background image view doesn't need these */ - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - bool has_alpha = true; - - if (ibuf) { - int imtype = BKE_image_ftype_to_imtype(ibuf->ftype, &ibuf->foptions); - char valid_channels = BKE_imtype_valid_channels(imtype, false); - - has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0; - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - - if (multiview) { - if ((scene->r.scemode & R_MULTIVIEW) != 0) { - uiItemR(layout, &imaptr, "use_multiview", 0, NULL, ICON_NONE); - - if (RNA_boolean_get(&imaptr, "use_multiview")) { - uiTemplateImageViews(layout, &imaptr); - } - } - } - - if (has_alpha) { - col = uiLayoutColumn(layout, false); - uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); - row = uiLayoutRow(col, false); - uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha")); - uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); - } - - if (ima->source == IMA_SRC_MOVIE) { - col = uiLayoutColumn(layout, false); - uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE); - } - } - } + uiLayout *sub = uiLayoutColumn(col, true); + uiItemR(sub, &imaptr, "generated_width", 0, "X", ICON_NONE); + uiItemR(sub, &imaptr, "generated_height", 0, "Y", ICON_NONE); + + uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); + + uiItemS(col); + + uiItemR(col, &imaptr, "generated_type", UI_ITEM_R_EXPAND, IFACE_("Type"), ICON_NONE); + if (ima->gen_type == IMA_GENTYPE_BLANK) { + uiItemR(col, &imaptr, "generated_color", 0, NULL, ICON_NONE); + } + } + else if (compact == 0) { + uiTemplateImageInfo(layout, C, ima, iuser); + } + + if (BKE_image_is_animated(ima)) { + /* Animation */ + uiItemS(layout); - if (BKE_image_is_animated(ima)) { - uiItemS(layout); + uiLayout *col = uiLayoutColumn(layout, true); + uiLayoutSetPropSep(col, true); - split = uiLayoutSplit(layout, 0.0f, false); + uiLayout *sub = uiLayoutColumn(col, true); + uiLayout *row = uiLayoutRow(sub, true); + uiItemR(row, userptr, "frame_duration", 0, IFACE_("Frames"), ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "IMAGE_OT_match_movie_length"); - col = uiLayoutColumn(split, false); + uiItemR(sub, userptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); + uiItemR(sub, userptr, "frame_offset", 0, NULL, ICON_NONE); - BLI_snprintf(str, sizeof(str), IFACE_("(%d) Frames"), iuser->framenr); - uiItemR(col, userptr, "frame_duration", 0, str, ICON_NONE); - uiItemR(col, userptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); - uiItemR(col, userptr, "frame_offset", 0, NULL, ICON_NONE); + uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE); + uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE); - col = uiLayoutColumn(split, false); - uiItemO(col, NULL, ICON_NONE, "IMAGE_OT_match_movie_length"); - uiItemR(col, userptr, "use_auto_refresh", 0, NULL, ICON_NONE); - uiItemR(col, userptr, "use_cyclic", 0, NULL, ICON_NONE); + if (ima->source == IMA_SRC_MOVIE && compact == 0) { + uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE); + } + } + + /* Multiview */ + if (multiview && compact == 0) { + if ((scene->r.scemode & R_MULTIVIEW) != 0) { + uiItemS(layout); + + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiItemR(col, &imaptr, "use_multiview", 0, NULL, ICON_NONE); + + if (RNA_boolean_get(&imaptr, "use_multiview")) { + uiTemplateImageViews(layout, &imaptr); } - else if (ima->source == IMA_SRC_GENERATED) { - split = uiLayoutSplit(layout, 0.0f, false); + } + } - col = uiLayoutColumn(split, true); - uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE); - uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE); + /* Colorspace and alpha */ + { + uiItemS(layout); - uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, true); + uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); - uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + if (compact == 0) { + if (ima->source != IMA_SRC_GENERATED) { + if (image_has_alpha(ima, iuser)) { + uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); - if (ima->gen_type == IMA_GENTYPE_BLANK) { - uiItemR(layout, &imaptr, "generated_color", 0, NULL, ICON_NONE); + bool is_data = IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name); + uiLayoutSetActive(sub, !is_data); } } - } - UI_block_funcN_set(block, NULL, NULL, NULL); + uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); + } } - MEM_freeN(cb); + UI_block_funcN_set(block, NULL, NULL, NULL); } void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management) @@ -1327,21 +1198,87 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser) { - Scene *scene = CTX_data_scene(C); - ImBuf *ibuf; - char str[MAX_IMAGE_INFO_LEN]; + if (ima == NULL || iuser == NULL) { + return; + } + + /* Acquire image buffer. */ void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - if (!ima || !iuser) { - return; + uiLayout *col = uiLayoutColumn(layout, true); + uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_RIGHT); + + if (ibuf == NULL) { + uiItemL(col, IFACE_("Can't Load Image"), ICON_NONE); } + else { + char str[MAX_IMAGE_INFO_LEN] = {0}; + const int len = MAX_IMAGE_INFO_LEN; + int ofs = 0; - ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d x %d, "), ibuf->x, ibuf->y); + + if (ibuf->rect_float) { + if (ibuf->channels != 4) { + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels); + } + else if (ibuf->planes == R_IMF_PLANES_RGBA) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs); + } + else { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs); + } + } + else { + if (ibuf->planes == R_IMF_PLANES_RGBA) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs); + } + else { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs); + } + } + if (ibuf->zbuf || ibuf->zbuf_float) { + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs); + } + + uiItemL(col, str, ICON_NONE); + } + + /* Frame number, even if we can't load the image. */ + if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { + /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ + Scene *scene = CTX_data_scene(C); + const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL); + char str[MAX_IMAGE_INFO_LEN]; + int duration = 0; + + if (ima->source == IMA_SRC_MOVIE && BKE_image_has_anim(ima)) { + struct anim *anim = ((ImageAnim *)ima->anims.first)->anim; + if (anim) { + duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); + } + } + + if (duration > 0) { + /* Movie duration */ + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d / %d"), framenr, duration); + } + else if (ima->source == IMA_SRC_SEQUENCE && ibuf) { + /* Image sequence frame number + filename */ + const char *filename = BLI_last_slash(ibuf->name); + filename = (filename == NULL) ? ibuf->name : filename + 1; + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d: %s"), framenr, filename); + } + else { + /* Frame number */ + BLI_snprintf(str, MAX_IMAGE_INFO_LEN, IFACE_("Frame %d"), framenr); + } + + uiItemL(col, str, ICON_NONE); + } - BKE_image_user_frame_calc(iuser, (int)scene->r.cfra); - image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); BKE_image_release_ibuf(ima, ibuf, lock); - uiItemL(layout, str, ICON_NONE); } #undef MAX_IMAGE_INFO_LEN @@ -1373,6 +1310,7 @@ void image_buttons_register(ARegionType *art) strcpy(pt->label, N_("Metadata")); strcpy(pt->category, "Image"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->order = 10; pt->poll = metadata_panel_context_poll; pt->draw = metadata_panel_context_draw; pt->flag |= PNL_DEFAULT_CLOSED; diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index a851684f2f3..2c723f45e94 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -66,6 +66,7 @@ void IMAGE_OT_reload(struct wmOperatorType *ot); void IMAGE_OT_save(struct wmOperatorType *ot); void IMAGE_OT_save_as(struct wmOperatorType *ot); void IMAGE_OT_save_sequence(struct wmOperatorType *ot); +void IMAGE_OT_save_all_modified(struct wmOperatorType *ot); void IMAGE_OT_pack(struct wmOperatorType *ot); void IMAGE_OT_unpack(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index cec2e1c68d9..bcea65d1634 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -34,8 +34,10 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -179,31 +181,59 @@ static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf sima_zoom_set(sima, ar, size, NULL); } -#if 0 // currently unused -static bool image_poll(bContext *C) +static Image *image_from_context(const bContext *C) { - return (CTX_data_edit_image(C) != NULL); + /* Edit image is set by templates used throughout the interface, so image + * operations work outside the image editor. */ + Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data; + + if (ima) { + return ima; + } + else { + /* Image editor. */ + SpaceImage *sima = CTX_wm_space_image(C); + return (sima) ? sima->image : NULL; + } } -#endif -static bool space_image_buffer_exists_poll(bContext *C) +static ImageUser *image_user_from_context(const bContext *C) { - SpaceImage *sima = CTX_wm_space_image(C); - if (sima && ED_space_image_has_buffer(sima)) { - return true; + /* Edit image user is set by templates used throughout the interface, so + * image operations work outside the image editor. */ + ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data; + + if (iuser) { + return iuser; + } + else { + /* Image editor. */ + SpaceImage *sima = CTX_wm_space_image(C); + return (sima) ? &sima->iuser : NULL; } - return false; } -static bool image_not_packed_poll(bContext *C) +static bool image_buffer_exists_from_context(bContext *C) { - SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); - /* Do not run 'replace' on packed images, it does not give user expected results at all. */ - if (sima && sima->image && BLI_listbase_is_empty(&sima->image->packedfiles)) { - return true; + if (ima == NULL) { + return false; } - return false; + + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + const bool has_buffer = (ibuf && (ibuf->rect || ibuf->rect_float)); + BKE_image_release_ibuf(ima, ibuf, lock); + return has_buffer; +} + +static bool image_not_packed_poll(bContext *C) +{ + /* Do not run 'replace' on packed images, it does not give user expected results at all. */ + Image *ima = image_from_context(C); + return (ima && BLI_listbase_is_empty(&ima->packedfiles)); } static bool imbuf_format_writeable(const ImBuf *ibuf) @@ -214,52 +244,6 @@ static bool imbuf_format_writeable(const ImBuf *ibuf) return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype); } -static bool space_image_file_exists_poll(bContext *C) -{ - if (space_image_buffer_exists_poll(C)) { - Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); - ImBuf *ibuf; - void *lock; - bool ret = false; - char name[FILE_MAX]; - - ibuf = ED_space_image_acquire_buffer(sima, &lock); - if (ibuf) { - BLI_strncpy(name, ibuf->name, FILE_MAX); - BLI_path_abs(name, BKE_main_blendfile_path(bmain)); - - if (BLI_exists(name) == false) { - CTX_wm_operator_poll_msg_set(C, "image file not found"); - } - else if (!BLI_file_is_writable(name)) { - CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); - } - else if (!imbuf_format_writeable(ibuf)) { - CTX_wm_operator_poll_msg_set(C, "image format is read-only"); - } - else { - ret = true; - } - } - ED_space_image_release_buffer(sima, ibuf, lock); - - return ret; - } - return false; -} - -#if 0 /* UNUSED */ -static bool space_image_poll(bContext *C) -{ - SpaceImage *sima = CTX_wm_space_image(C); - if (sima && sima->image) { - return true; - } - return false; -} -#endif - bool space_image_main_region_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); @@ -288,24 +272,23 @@ static bool space_image_main_area_not_uv_brush_poll(bContext *C) static bool image_sample_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); - if (sima) { - Object *obedit = CTX_data_edit_object(C); - if (obedit) { - /* Disable when UV editing so it doesn't swallow all click events - * (use for setting cursor). */ - if (ED_space_image_show_uvedit(sima, obedit)) { - return false; - } - } - else if (sima->mode != SI_MODE_VIEW) { + if (sima == NULL) { + return false; + } + + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + /* Disable when UV editing so it doesn't swallow all click events + * (use for setting cursor). */ + if (ED_space_image_show_uvedit(sima, obedit)) { return false; } - - return space_image_main_region_poll(C); } - else { + else if (sima->mode != SI_MODE_VIEW) { return false; } + + return true; } /********************** view pan operator *********************/ @@ -1337,7 +1320,7 @@ static int image_open_exec(bContext *C, wmOperator *op) PointerRNA imaptr; RNA_id_pointer_create(&ima->id, &imaptr); - RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr); + RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr, NULL); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); } @@ -1522,21 +1505,16 @@ void IMAGE_OT_open(wmOperatorType *ot) static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data; - ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data; + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); if (!ima || !iuser) { /* Try to get a Texture, or a SpaceImage from context... */ - SpaceImage *sima = CTX_wm_space_image(C); Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; if (tex && tex->type == TEX_IMAGE) { ima = tex->ima; iuser = &tex->iuser; } - else if (sima) { - ima = sima->image; - iuser = &sima->iuser; - } } if (!ima || !iuser || !BKE_image_has_anim(ima)) { @@ -1811,14 +1789,11 @@ static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op) RNA_string_set(op->ptr, "filepath", opts->filepath); } -static bool save_image_op(const bContext *C, - SpaceImage *sima, - wmOperator *op, - ImageSaveOptions *opts) +static bool save_image_op(const bContext *C, wmOperator *op, ImageSaveOptions *opts) { Main *bmain = CTX_data_main(C); - Image *ima = ED_space_image(sima); - ImageUser *iuser = &sima->iuser; + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")); @@ -1856,21 +1831,27 @@ static int image_save_as_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); ImageSaveOptions opts; BKE_image_save_options_init(&opts, bmain, scene); /* just in case to initialize values, * these should be set on invoke or by the caller. */ - image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false); + image_save_options_init(bmain, &opts, image, iuser, false, false); image_save_options_from_op(bmain, &opts, op); opts.do_newpath = true; - save_image_op(C, sima, op, &opts); + save_image_op(C, op, &opts); + + if (opts.save_copy == false) { + BKE_image_free_packedfiles(image); + } image_save_as_free(op); + return OPERATOR_FINISHED; } @@ -1883,8 +1864,8 @@ static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op) static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = ED_space_image(sima); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveOptions opts; PropertyRNA *prop; @@ -1897,7 +1878,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS BKE_image_save_options_init(&opts, bmain, scene); - if (image_save_options_init(bmain, &opts, ima, &sima->iuser, true, save_as_render) == 0) { + if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) { return OPERATOR_CANCELLED; } image_save_options_to_op(&opts, op); @@ -1965,20 +1946,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) static bool image_save_as_poll(bContext *C) { - if (space_image_buffer_exists_poll(C)) { - if (G.is_rendering) { - /* no need to NULL check here */ - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = ED_space_image(sima); + if (!image_buffer_exists_from_context(C)) { + return false; + } - if (ima->source == IMA_SRC_VIEWER) { - CTX_wm_operator_poll_msg_set(C, "can't save image while rendering"); - return false; - } + if (G.is_rendering) { + /* no need to NULL check here */ + Image *ima = image_from_context(C); + + if (ima->source == IMA_SRC_VIEWER) { + CTX_wm_operator_poll_msg_set(C, "can't save image while rendering"); + return false; } - return true; } - return false; + + return true; } void IMAGE_OT_save_as(wmOperatorType *ot) @@ -2022,21 +2004,83 @@ void IMAGE_OT_save_as(wmOperatorType *ot) /******************** save image operator ********************/ +static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser) +{ + /* Can always repack images. */ + if (BKE_image_has_packedfile(ima)) { + return true; + } + + /* Test for valid filepath. */ + void *lock; + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + bool ret = false; + + if (ibuf) { + Main *bmain = CTX_data_main(C); + char name[FILE_MAX]; + BLI_strncpy(name, ibuf->name, FILE_MAX); + BLI_path_abs(name, BKE_main_blendfile_path(bmain)); + + if (BLI_exists(name) == false) { + CTX_wm_operator_poll_msg_set(C, "image file not found"); + } + else if (!BLI_file_is_writable(name)) { + CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); + } + else if (!imbuf_format_writeable(ibuf)) { + CTX_wm_operator_poll_msg_set(C, "image format is read-only"); + } + else { + ret = true; + } + } + + BKE_image_release_ibuf(ima, ibuf, lock); + return ret; +} + +static bool image_save_poll(bContext *C) +{ + /* Can't save if there are no pixels. */ + if (image_buffer_exists_from_context(C) == false) { + return false; + } + + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); + + /* Images without a filepath will go to save as. */ + if (!BKE_image_has_filepath(ima)) { + return true; + } + + /* Check if there is a valid file path and image format we can write. */ + return image_file_path_saveable(C, ima, iuser); +} + static int image_save_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); Scene *scene = CTX_data_scene(C); ImageSaveOptions opts; + if (BKE_image_has_packedfile(image)) { + /* Save packed files to memory. */ + BKE_image_memorypack(image); + return OPERATOR_FINISHED; + } + BKE_image_save_options_init(&opts, bmain, scene); - if (image_save_options_init(bmain, &opts, sima->image, &sima->iuser, false, false) == 0) { + if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) { return OPERATOR_CANCELLED; } image_save_options_from_op(bmain, &opts, op); if (BLI_exists(opts.filepath) && BLI_file_is_writable(opts.filepath)) { - if (save_image_op(C, sima, op, &opts)) { + if (save_image_op(C, op, &opts)) { /* report since this can be called from key-shortcuts */ BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", opts.filepath); } @@ -2050,6 +2094,19 @@ static int image_save_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int image_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Image *ima = image_from_context(C); + + if (!BKE_image_has_packedfile(ima) && !BKE_image_has_filepath(ima)) { + WM_operator_name_call(C, "IMAGE_OT_save_as", WM_OP_INVOKE_DEFAULT, NULL); + return OPERATOR_CANCELLED; + } + else { + return image_save_exec(C, op); + } +} + void IMAGE_OT_save(wmOperatorType *ot) { /* identifiers */ @@ -2059,7 +2116,8 @@ void IMAGE_OT_save(wmOperatorType *ot) /* api callbacks */ ot->exec = image_save_exec; - ot->poll = space_image_file_exists_poll; + ot->invoke = image_save_invoke; + ot->poll = image_save_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2070,30 +2128,30 @@ void IMAGE_OT_save(wmOperatorType *ot) static int image_save_sequence_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *image = image_from_context(C); ImBuf *ibuf, *first_ibuf = NULL; int tot = 0; char di[FILE_MAX]; struct MovieCacheIter *iter; - if (sima->image == NULL) { + if (image == NULL) { return OPERATOR_CANCELLED; } - if (sima->image->source != IMA_SRC_SEQUENCE) { + if (image->source != IMA_SRC_SEQUENCE) { BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences"); return OPERATOR_CANCELLED; } - if (sima->image->type == IMA_TYPE_MULTILAYER) { + if (image->type == IMA_TYPE_MULTILAYER) { BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences"); return OPERATOR_CANCELLED; } /* get total dirty buffers and first dirty buffer which is used for menu */ ibuf = NULL; - if (sima->image->cache != NULL) { - iter = IMB_moviecacheIter_new(sima->image->cache); + if (image->cache != NULL) { + iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { ibuf = IMB_moviecacheIter_getImBuf(iter); if (ibuf->userflags & IB_BITMAPDIRTY) { @@ -2116,7 +2174,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) BLI_split_dir_part(first_ibuf->name, di, sizeof(di)); BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di); - iter = IMB_moviecacheIter_new(sima->image->cache); + iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { ibuf = IMB_moviecacheIter_getImBuf(iter); @@ -2151,7 +2209,139 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) /* api callbacks */ ot->exec = image_save_sequence_exec; - ot->poll = space_image_buffer_exists_poll; + ot->poll = image_buffer_exists_from_context; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** save all operator **********************/ + +static bool image_should_be_saved_when_modified(Image *ima) +{ + return !ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE); +} + +static bool image_should_be_saved(Image *ima) +{ + if (BKE_image_is_dirty(ima) && + (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_GENERATED)) { + return image_should_be_saved_when_modified(ima); + } + else { + return false; + } +} + +static bool image_has_valid_path(Image *ima) +{ + return strchr(ima->name, '\\') || strchr(ima->name, '/'); +} + +bool ED_image_should_save_modified(const bContext *C) +{ + return ED_image_save_all_modified_info(C, NULL) > 0; +} + +int ED_image_save_all_modified_info(const bContext *C, ReportList *reports) +{ + Main *bmain = CTX_data_main(C); + GSet *unique_paths = BLI_gset_str_new(__func__); + + int num_saveable_images = 0; + + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + if (image_should_be_saved(ima)) { + if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) { + if (ima->id.lib == NULL) { + num_saveable_images++; + } + else { + BKE_reportf(reports, + RPT_WARNING, + "Packed library image: %s from library %s can't be saved", + ima->id.name, + ima->id.lib->name); + } + } + else { + if (image_has_valid_path(ima)) { + num_saveable_images++; + if (BLI_gset_haskey(unique_paths, ima->name)) { + BKE_reportf(reports, + RPT_WARNING, + "File path used by more than one saved image: %s", + ima->name); + } + else { + BLI_gset_insert(unique_paths, BLI_strdup(ima->name)); + } + } + else { + BKE_reportf(reports, + RPT_WARNING, + "Image %s can't be saved, no valid file path: %s", + ima->id.name, + ima->name); + } + } + } + } + + BLI_gset_free(unique_paths, MEM_freeN); + return num_saveable_images; +} + +bool ED_image_save_all_modified(const bContext *C, ReportList *reports) +{ + ED_image_save_all_modified_info(C, reports); + + Main *bmain = CTX_data_main(C); + bool ok = true; + + for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { + if (image_should_be_saved(ima)) { + if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) { + BKE_image_memorypack(ima); + } + else { + if (image_has_valid_path(ima)) { + ImageSaveOptions opts; + Scene *scene = CTX_data_scene(C); + BKE_image_save_options_init(&opts, bmain, scene); + if (image_save_options_init(bmain, &opts, ima, NULL, false, false)) { + bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts); + ok = ok && saved_successfully; + } + } + } + } + } + return ok; +} + +static bool image_save_all_modified_poll(bContext *C) +{ + int num_files = ED_image_save_all_modified_info(C, NULL); + return num_files > 0; +} + +static int image_save_all_modified_exec(bContext *C, wmOperator *op) +{ + ED_image_save_all_modified(C, op->reports); + return OPERATOR_FINISHED; +} + +void IMAGE_OT_save_all_modified(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Save All Modified"; + ot->idname = "IMAGE_OT_save_all_modified"; + ot->description = "Save all modified images"; + + /* api callbacks */ + ot->exec = image_save_all_modified_exec; + ot->poll = image_save_all_modified_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2162,8 +2352,8 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); - Image *ima = CTX_data_edit_image(C); - SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = image_from_context(C); + ImageUser *iuser = image_user_from_context(C); if (!ima) { return OPERATOR_CANCELLED; @@ -2172,7 +2362,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) /* XXX unpackImage frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD); + BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); DEG_id_tag_update(&ima->id, 0); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -2284,7 +2474,7 @@ static int image_new_exec(bContext *C, wmOperator *op) PointerRNA imaptr; RNA_id_pointer_create(&ima->id, &imaptr); - RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr); + RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, NULL); RNA_property_update(C, &data->pprop.ptr, data->pprop.prop); } else if (sima) { @@ -2414,14 +2604,14 @@ void IMAGE_OT_new(wmOperatorType *ot) static bool image_invert_poll(bContext *C) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); return BKE_image_has_ibuf(ima, NULL); } static int image_invert_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); SpaceImage *sima = CTX_wm_space_image(C); /* undo is supported only on image paint mode currently */ @@ -2494,7 +2684,8 @@ static int image_invert_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(ima, ibuf); if (ibuf->mipmap[0]) { ibuf->userflags |= IB_MIPMAP_INVALID; @@ -2545,7 +2736,7 @@ void IMAGE_OT_invert(wmOperatorType *ot) static bool image_pack_test(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!ima) { return 0; @@ -2562,7 +2753,7 @@ static bool image_pack_test(bContext *C, wmOperator *op) static int image_pack_exec(bContext *C, wmOperator *op) { struct Main *bmain = CTX_data_main(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!image_pack_test(C, op)) { return OPERATOR_CANCELLED; @@ -2598,7 +2789,7 @@ void IMAGE_OT_pack(wmOperatorType *ot) static int image_unpack_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); int method = RNA_enum_get(op->ptr, "method"); /* find the suppplied image by name */ @@ -2607,7 +2798,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "id", imaname); ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2); if (!ima) { - ima = CTX_data_edit_image(C); + ima = image_from_context(C); } } @@ -2638,7 +2829,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (RNA_struct_property_is_set(op->ptr, "id")) { return image_unpack_exec(C, op); @@ -3225,176 +3416,18 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -#if 0 /* Not ported to 2.5x yet */ -/******************** record composite operator *********************/ - -typedef struct RecordCompositeData { - wmTimer *timer; - int old_cfra; - int sfra, efra; -} RecordCompositeData; - -static int image_record_composite_apply(bContext *C, wmOperator *op) -{ - SpaceImage *sima = CTX_wm_space_image(C); - RecordCompositeData *rcd = op->customdata; - Scene *scene = CTX_data_scene(C); - ImBuf *ibuf; - - WM_cursor_time(CTX_wm_window(C), scene->r.cfra); - - // XXX scene->nodetree->test_break = BKE_blender_test_break; - // XXX scene->nodetree->test_break = NULL; - - BKE_image_all_free_anim_ibufs(scene->r.cfra); - ntreeCompositExecTree(scene->nodetree, - &scene->r, - 0, - scene->r.cfra != rcd->old_cfra, - &scene->view_settings, - &scene->display_settings); /* 1 is no previews */ - - ED_area_tag_redraw(CTX_wm_area(C)); - - ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, NULL); - /* save memory in flipbooks */ - if (ibuf) - imb_freerectfloatImBuf(ibuf); - - BKE_image_release_ibuf(sima->image, ibuf, NULL); - - scene->r.cfra++; - - return (scene->r.cfra <= rcd->efra); -} - -static int image_record_composite_init(bContext *C, wmOperator *op) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - RecordCompositeData *rcd; - - if (sima->iuser.frames < 2) - return 0; - if (scene->nodetree == NULL) - return 0; - - op->customdata = rcd = MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData"); - - rcd->old_cfra = scene->r.cfra; - rcd->sfra = sima->iuser.sfra; - rcd->efra = sima->iuser.sfra + sima->iuser.frames - 1; - scene->r.cfra = rcd->sfra; - - return 1; -} - -static void image_record_composite_exit(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - SpaceImage *sima = CTX_wm_space_image(C); - RecordCompositeData *rcd = op->customdata; - - scene->r.cfra = rcd->old_cfra; - - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (rcd->timer) - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer); - - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image); - - // XXX play_anim(0); - // XXX allqueue(REDRAWNODE, 1); - - MEM_freeN(rcd); -} - -static int image_record_composite_exec(bContext *C, wmOperator *op) -{ - if (!image_record_composite_init(C, op)) - return OPERATOR_CANCELLED; - - while (image_record_composite_apply(C, op)) { - } - - image_record_composite_exit(C, op); - - return OPERATOR_FINISHED; -} - -static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - RecordCompositeData *rcd; - - if (!image_record_composite_init(C, op)) - return OPERATOR_CANCELLED; - - rcd = op->customdata; - rcd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f); - WM_event_add_modal_handler(C, op); - - if (!image_record_composite_apply(C, op)) - return OPERATOR_FINISHED; - - return OPERATOR_RUNNING_MODAL; -} - -static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - RecordCompositeData *rcd = op->customdata; - - switch (event->type) { - case TIMER: - if (rcd->timer == event->customdata) { - if (!image_record_composite_apply(C, op)) { - image_record_composite_exit(C, op); - return OPERATOR_FINISHED; - } - } - break; - case ESCKEY: - image_record_composite_exit(C, op); - return OPERATOR_FINISHED; - } - - return OPERATOR_RUNNING_MODAL; -} - -static void image_record_composite_cancel(bContext *C, wmOperator *op) -{ - image_record_composite_exit(C, op); - return OPERATOR_CANCELLED; -} - -void IMAGE_OT_record_composite(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Record Composite"; - ot->idname = "IMAGE_OT_record_composite"; - - /* api callbacks */ - ot->exec = image_record_composite_exec; - ot->invoke = image_record_composite_invoke; - ot->modal = image_record_composite_modal; - ot->cancel = image_record_composite_cancel; - ot->poll = space_image_buffer_exists_poll; -} - -#endif - /********************* cycle render slot operator *********************/ static bool image_cycle_render_slot_poll(bContext *C) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); return (ima && ima->type == IMA_TYPE_R_RESULT); } static int image_cycle_render_slot_exec(bContext *C, wmOperator *op) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1; if (!ED_image_slot_cycle(ima, direction)) { @@ -3434,7 +3467,7 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot) static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) { return OPERATOR_CANCELLED; @@ -3464,7 +3497,7 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot) static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); RenderSlot *slot = BKE_image_add_renderslot(ima, NULL); ima->render_slot = BLI_findindex(&ima->renderslots, slot); @@ -3494,7 +3527,7 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot) static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = CTX_data_edit_image(C); + Image *ima = image_from_context(C); if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 386e258a833..a8be93ad213 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -224,6 +224,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_save); WM_operatortype_append(IMAGE_OT_save_as); WM_operatortype_append(IMAGE_OT_save_sequence); + WM_operatortype_append(IMAGE_OT_save_all_modified); WM_operatortype_append(IMAGE_OT_pack); WM_operatortype_append(IMAGE_OT_unpack); @@ -567,7 +568,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) Object *obedit = CTX_data_edit_object(C); Depsgraph *depsgraph = CTX_data_depsgraph(C); Mask *mask = NULL; - bool curve = false; + bool show_uvedit = false; + bool show_curve = false; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View2D *v2d = &ar->v2d; @@ -609,13 +611,13 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) /* check for mask (delay draw) */ if (ED_space_image_show_uvedit(sima, obedit)) { - /* pass */ + show_uvedit = true; } else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); } else if (ED_space_image_paint_curve(C)) { - curve = true; + show_curve = true; } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -669,12 +671,9 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) false, NULL, C); - - UI_view2d_view_ortho(v2d); - ED_image_draw_cursor(ar, sima->cursor); - UI_view2d_view_restore(C); } - else if (curve) { + + if (show_uvedit || mask || show_curve) { UI_view2d_view_ortho(v2d); ED_image_draw_cursor(ar, sima->cursor); UI_view2d_view_restore(C); @@ -764,7 +763,7 @@ static void image_buttons_region_layout(const bContext *C, ARegion *ar) } const bool vertical = true; - ED_region_panels_layout_ex(C, ar, contexts_base, -1, vertical); + ED_region_panels_layout_ex(C, ar, &ar->type->paneltypes, contexts_base, -1, vertical, NULL); } static void image_buttons_region_draw(const bContext *C, ARegion *ar) @@ -1035,9 +1034,10 @@ void ED_spacetype_image(void) /* regions: listview/buttons/scopes */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 220; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = image_buttons_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = image_buttons_region_init; art->layout = image_buttons_region_layout; art->draw = image_buttons_region_draw; diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 171d8505222..bf43e493cc5 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -160,19 +160,11 @@ static int pack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev { Main *bmain = CTX_data_main(C); Image *ima; - ImBuf *ibuf; // first check for dirty images for (ima = bmain->images.first; ima; ima = ima->id.next) { - if (BKE_image_has_loaded_ibuf(ima)) { /* XXX FIX */ - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - - if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - break; - } - - BKE_image_release_ibuf(ima, ibuf, NULL); + if (BKE_image_is_dirty(ima)) { + break; } } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 4115d6b49ba..e5c116e85de 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -52,6 +52,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -384,19 +386,12 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv selectmode = SELECT_REPLACE; } - /** - * Figure out which channel user clicked in: - * - * \note Although channels technically start at y= NLACHANNEL_FIRST, - * we need to adjust by half a channel's height so that the tops of channels get caught ok. - * Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use NLACHANNEL_HEIGHT_HALF. - */ + /* Figure out which channel user clicked in. */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - NLACHANNEL_NAMEWIDTH, + UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), + NLACHANNEL_FIRST_TOP(&ac), x, y, NULL, diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 1df2190b7af..68cbfd76331 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -689,23 +689,19 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); - - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); + int height = NLACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; /* loop through channels, and set up drawing depending on their type */ - float y = (float)(-NLACHANNEL_HEIGHT(snla)); + float ymax = NLACHANNEL_FIRST_TOP(ac); - for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); + float ycenter = (ymax + ymin) / 2.0f; /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* data to draw depends on the type of channel */ switch (ale->type) { case ANIMTYPE_NLATRACK: { @@ -721,18 +717,18 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) const float xmaxc = strip->end + text_margin_x; /* draw the visualization of the strip */ - nla_draw_strip(snla, adt, nlt, strip, v2d, yminc, ymaxc); + nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax); /* add the text for this strip to the cache */ if (xminc < xmaxc) { - nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, yminc, ymaxc); + nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax); } /* if transforming strips (only real reason for temp-metas currently), * add to the cache the frame numbers of the strip's extents */ if (strip->flag & NLASTRIP_FLAG_TEMP_META) { - nla_draw_strip_frames_text(nlt, strip, v2d, yminc, ymaxc); + nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax); } } } @@ -761,27 +757,27 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) * but also slightly shorter for some more contrast when viewing the strips */ immRectf( - pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); /* draw 'embossed' lines above and below the strip for effect */ /* white base-lines */ GPU_line_width(2.0f); immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f); immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* black top-lines */ GPU_line_width(1.0f); immUniformColor3f(0.0f, 0.0f, 0.0f); immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP); - immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymin + NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmin, ymax - NLACHANNEL_SKIP); + immVertex2f(pos, v2d->cur.xmax, ymax - NLACHANNEL_SKIP); immEnd(); /* TODO: these lines but better --^ */ @@ -790,16 +786,13 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar) /* draw keyframes in the action */ nla_action_draw_keyframes( - v2d, adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP); + v2d, adt, ale->data, ycenter, ymin + NLACHANNEL_SKIP, ymax - NLACHANNEL_SKIP); GPU_blend(false); break; } } } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); } /* free tempolary channels */ @@ -817,7 +810,6 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) SpaceNla *snla = (SpaceNla *)ac->sl; View2D *v2d = &ar->v2d; - float y = 0.0f; size_t items; /* build list of channels to draw */ @@ -830,11 +822,9 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) * - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2)); - /* don't use totrect set, as the width stays the same - * (NOTE: this is ok here, the configuration is pretty straightforward) - */ - v2d->tot.ymin = (float)(-height); + int height = NLACHANNEL_TOT_HEIGHT(ac, items); + v2d->tot.ymin = -height; + /* need to do a view-sync here, so that the keys area doesn't jump around * (it must copy this) */ UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY); @@ -842,30 +832,24 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) /* draw channels */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; + float ymax = NLACHANNEL_FIRST_TOP(ac); - y = (float)(-NLACHANNEL_HEIGHT(snla)); - - for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (ale = anim_data.first; ale; + ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ - ANIM_channel_draw(ac, ale, yminc, ymaxc, channel_index); + ANIM_channel_draw(ac, ale, ymin, ymax, channel_index); } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); - channel_index++; } } { /* second pass: UI widgets */ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - - y = (float)(-NLACHANNEL_HEIGHT(snla)); + float ymax = NLACHANNEL_FIRST_TOP(ac); /* set blending again, as may not be set in previous step */ GPU_blend_set_func_separate( @@ -873,22 +857,18 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar) GPU_blend(true); /* loop through channels, and set up drawing depending on their type */ - for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla)); - const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla)); + for (ale = anim_data.first; ale; + ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++) { + float ymin = ymax - NLACHANNEL_HEIGHT(snla); /* check if visible */ - if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || - IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax)) { + if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) || + IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) { /* draw all channels using standard channel-drawing API */ rctf channel_rect; - BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, yminc, ymaxc); + BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax); ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index); } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); - channel_index++; } UI_block_end(C, block); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 0446235a776..acb3d913114 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -421,27 +421,25 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa int filter; SpaceNla *snla = (SpaceNla *)ac->sl; - const float half_height = NLACHANNEL_HEIGHT_HALF(snla); /* NOTE: not bool, since we want prioritise individual channels over expanders */ short found = 0; - float y; /* get all items - we need to do it this way */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ - y = (float)NLACHANNEL_FIRST; + float ymax = NLACHANNEL_FIRST_TOP(ac); - for (ale = anim_data.first; ale; ale = ale->next) { + for (ale = anim_data.first; ale; ale = ale->next, ymax -= NLACHANNEL_STEP(snla)) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); /* must be selected... */ if (acf && acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT) && ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ - *min = (float)(y - half_height); - *max = (float)(y + half_height); + *min = ymax - NLACHANNEL_HEIGHT(snla); + *max = ymax; /* is this high enough priority yet? */ found = acf->channel_role; @@ -453,9 +451,6 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa break; } } - - /* adjust y-position for next one */ - y -= NLACHANNEL_STEP(snla); } /* free all temp data */ @@ -2451,6 +2446,7 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot) /* id-props */ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf); RNA_def_boolean(ot->srna, diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 5c9e48f3d5d..0de9acfec25 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -47,6 +47,7 @@ #include "WM_types.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "nla_intern.h" // own include @@ -541,15 +542,8 @@ static void mouse_nla_strips( /* use View2D to determine the index of the channel * (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, - 0, - NLACHANNEL_STEP(snla), - 0, - (float)NLACHANNEL_HEIGHT_HALF(snla), - x, - y, - NULL, - &channel_index); + UI_view2d_listview_view_to_cell( + 0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(ac), x, y, NULL, &channel_index); /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click * (that is the size of keyframe icons, so user should be expecting similar tolerances) diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index b054f550c6c..4b7dfe5d653 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -40,6 +40,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "WM_api.h" #include "WM_types.h" @@ -47,6 +48,7 @@ #include "RNA_access.h" +#include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -69,6 +71,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene) /* set auto-snapping settings */ snla->autosnap = SACTSNAP_FRAME; + snla->flag = SNLA_SHOW_MARKER_LINES; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for nla"); @@ -116,7 +119,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 50; - ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); ar->v2d.scroll |= (V2D_SCROLL_RIGHT); ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; @@ -201,6 +204,9 @@ static void nla_channel_region_draw(const bContext *C, ARegion *ar) draw_nla_channel_list(C, &ac, ar); } + /* channel filter next to scrubbing area */ + ED_channel_search_draw(C, ar, ac.ads); + /* reset view matrix */ UI_view2d_view_restore(C); @@ -284,20 +290,12 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + ED_scrubbing_draw(ar, scene, snla->flag & SNLA_DRAWTIME, true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - - /* frame numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, snla->flag & SNLA_DRAWTIME); - - /* draw current frame number-indicator on top of scrollers */ - if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); - } } /* add handlers, stuff you only do once or on area/region changes */ @@ -614,7 +612,7 @@ void ED_spacetype_nla(void) art->draw = nla_main_region_draw; art->listener = nla_main_region_listener; art->message_subscribe = nla_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -645,7 +643,7 @@ void ED_spacetype_nla(void) /* regions: UI buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 200; + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI; art->listener = nla_region_listener; art->init = nla_buttons_region_init; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 447fea8098c..e39e024e44a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -708,6 +708,16 @@ static void node_buts_image_user(uiLayout *layout, col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); } + + uiLayout *split = uiLayoutSplit(layout, 0.5f, true); + PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings"); + uiItemL(split, IFACE_("Color Space"), ICON_NONE); + uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); + + /* Avoid losing changes image is painted. */ + if (BKE_image_is_dirty(imaptr->data)) { + uiLayoutSetEnabled(split, false); + } } static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -782,7 +792,6 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA NULL, UI_TEMPLATE_ID_FILTER_ALL, false); - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -820,11 +829,10 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin UI_TEMPLATE_ID_FILTER_ALL, false); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); - - uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -875,7 +883,6 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiTemplateImageInfo(layout, C, ima, iuserptr.data); } - uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); } diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 714ed707e18..01a30f677a3 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -521,7 +521,7 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) id_us_min(&ntree->id); RNA_id_pointer_create(&ntree->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } else if (snode) { diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 3e73cc52c52..fb34d9dc459 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -453,13 +453,8 @@ void ED_node_shader_default(const bContext *C, ID *id) output_type = SH_NODE_OUTPUT_LIGHT; shader_type = SH_NODE_EMISSION; - copy_v3_v3(color, &la->r); - if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA) { - strength = 100.0f; - } - else { - strength = 1.0f; - } + copy_v3_fl3(color, 1.0f, 1.0f, 1.0f); + strength = 1.0f; break; } default: diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index b52d1d3b78f..a8331c26ce6 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -429,19 +429,24 @@ void node_select_single(bContext *C, bNode *node) WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } -static int node_mouse_select(Main *bmain, - SpaceNode *snode, - ARegion *ar, +static int node_mouse_select(bContext *C, const int mval[2], const bool extend, const bool socket_select, - const bool deselect_all) + const bool deselect_all, + const bool wait_to_deselect_others) { + Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *ar = CTX_wm_region(C); bNode *node, *tnode; bNodeSocket *sock = NULL; bNodeSocket *tsock; float cursor[2]; - bool selected = false; + int ret_value = OPERATOR_CANCELLED; + + /* Waiting to deselect others is only allowed for basic selection. */ + BLI_assert(!(extend || socket_select) || !wait_to_deselect_others); /* get mouse coordinates in view2d space */ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); @@ -449,89 +454,114 @@ static int node_mouse_select(Main *bmain, /* first do socket selection, these generally overlap with nodes. */ if (socket_select) { if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { - node_socket_toggle(node, sock, 1); - selected = true; + /* NOTE: SOCK_IN does not take into account the extend case... + * This feature is not really used anyway currently? */ + node_socket_toggle(node, sock, true); + ret_value = OPERATOR_FINISHED; } else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { if (sock->flag & SELECT) { if (extend) { - node_socket_deselect(node, sock, 1); + node_socket_deselect(node, sock, true); } else { - selected = true; + ret_value = OPERATOR_FINISHED; } } else { - /* only allow one selected output per node, for sensible linking. - * allows selecting outputs from different nodes though. */ + /* Only allow one selected output per node, for sensible linking. + * Allow selecting outputs from different nodes though, if extend is true. */ if (node) { for (tsock = node->outputs.first; tsock; tsock = tsock->next) { - node_socket_deselect(node, tsock, 1); + if (tsock == sock) { + continue; + } + node_socket_deselect(node, tsock, true); } } - if (extend) { - /* only allow one selected output per node, for sensible linking. - * allows selecting outputs from different nodes though. */ - for (tsock = node->outputs.first; tsock; tsock = tsock->next) { - if (tsock != sock) { - node_socket_deselect(node, tsock, 1); + if (!extend) { + for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { + if (tnode == node) { + continue; + } + for (tsock = tnode->outputs.first; tsock; tsock = tsock->next) { + node_socket_deselect(tnode, tsock, true); } } } node_socket_select(node, sock); - selected = true; + ret_value = OPERATOR_FINISHED; } } } - if (!sock) { - if (extend) { - /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); + /* In case we do two-steps selection, we do not want to select the node if some valid socket + * is below the mouse, as that would prevent draging from sockets (NODE_OT_link) + * to be properly triggered. See T64660. */ + if (wait_to_deselect_others) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN) || + node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { + ret_value = OPERATOR_CANCELLED; + } + } - if (node) { - if ((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0) { - /* if node is selected but not active make it active */ - ED_node_set_active(bmain, snode->edittree, node); - } - else { + if (sock == NULL) { + /* find the closest visible node */ + node = node_under_mouse_select(snode->edittree, (int)cursor[0], (int)cursor[1]); + + if (extend) { + if (node != NULL) { + /* If node is selected but not active, we want to make it active, + * but not toggle (deselect) it. */ + if (!((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0)) { node_toggle(node); - ED_node_set_active(bmain, snode->edittree, node); } - selected = true; + ret_value = OPERATOR_FINISHED; } } - else { - /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); + else if (deselect_all && node == NULL) { + /* Deselect in empty space. */ + for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { + nodeSetSelected(tnode, false); + } + ret_value = OPERATOR_FINISHED; + } + else if (node != NULL) { + /* When clicking on an already selected node, we want to wait to deselect + * others and allow the user to start moving the node without that. */ + if (wait_to_deselect_others && (node->flag & SELECT)) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + nodeSetSelected(node, true); - if (node != NULL || deselect_all) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { - nodeSetSelected(tnode, false); - } - selected = true; - if (node != NULL) { - nodeSetSelected(node, true); - ED_node_set_active(bmain, snode->edittree, node); + if (tnode != node) { + nodeSetSelected(tnode, false); + } } + + ret_value = OPERATOR_FINISHED; } } } /* update node order */ - if (selected) { + if (ret_value != OPERATOR_CANCELLED) { + if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) { + ED_node_set_active(bmain, snode->edittree, node); + } ED_node_set_active_viewer_key(snode); ED_node_sort(snode->edittree); + + WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } - return selected; + return ret_value; } static int node_select_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *ar = CTX_wm_region(C); int mval[2]; /* get settings from RNA properties for operator */ @@ -544,17 +574,70 @@ static int node_select_exec(bContext *C, wmOperator *op) const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); /* perform the select */ - if (node_mouse_select(bmain, snode, ar, mval, extend, socket_select, deselect_all)) { - /* send notifiers */ - WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); + + /* allow tweak event to work too */ + return ret_value | OPERATOR_PASS_THROUGH; +} + +static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + const short init_event_type = (short)POINTER_AS_INT(op->customdata); + + /* get settings from RNA properties for operator */ + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + const bool extend = RNA_boolean_get(op->ptr, "extend"); + /* always do socket_select when extending selection. */ + const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select"); + const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - /* allow tweak event to work too */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + /* These cases are never modal. */ + if (extend || socket_select) { + return node_select_exec(C, op); } - else { - /* allow tweak event to work too */ - return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + + if (init_event_type == 0) { + if (event->val == KM_PRESS) { + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true); + + op->customdata = POINTER_FROM_INT((int)event->type); + if (ret_value & OPERATOR_RUNNING_MODAL) { + WM_event_add_modal_handler(C, op); + } + return ret_value | OPERATOR_PASS_THROUGH; + } + else { + /* If we are in init phase, and cannot validate init of modal operations, + * just fall back to basic exec. + */ + return node_select_exec(C, op); + } } + else if (event->type == init_event_type && event->val == KM_RELEASE) { + const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false); + return ret_value | OPERATOR_PASS_THROUGH; + } + else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + const int dx = mval[0] - event->mval[0]; + const int dy = mval[1] - event->mval[1]; + const float tweak_threshold = U.tweak_threshold * U.dpi_fac; + /* If user moves mouse more than defined threshold, we consider select operator as + * finished. Otherwise, it is still running until we get an 'release' event. In any + * case, we pass through event, but select op is not finished yet. */ + if (abs(dx) + abs(dy) > tweak_threshold) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + else { + /* Important not to return anything other than PASS_THROUGH here, + * otherwise it prevents underlying tweak detection code to work properly. */ + return OPERATOR_PASS_THROUGH; + } + } + + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -562,7 +645,9 @@ static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "mouse_x", event->mval[0]); RNA_int_set(op->ptr, "mouse_y", event->mval[1]); - return node_select_exec(C, op); + op->customdata = POINTER_FROM_INT(0); + + return node_select_modal(C, op, event); } void NODE_OT_select(wmOperatorType *ot) @@ -575,6 +660,7 @@ void NODE_OT_select(wmOperatorType *ot) /* api callbacks */ ot->invoke = node_select_invoke; ot->exec = node_select_exec; + ot->modal = node_select_modal; ot->poll = ED_operator_node_active; /* flags */ @@ -1186,7 +1272,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op) static int node_find_node_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - UI_popup_block_invoke(C, node_find_menu, op); + UI_popup_block_invoke(C, node_find_menu, op, NULL); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 2152bb9847a..7183512a5bc 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -998,9 +998,10 @@ void ED_spacetype_node(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 180; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = node_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = node_buttons_region_init; art->draw = node_buttons_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 6da42ecb3c0..21e54a29fb9 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -855,7 +855,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) { /* identifiers */ - ot->name = "Set Exclude"; + ot->name = "Disable from View Layer"; ot->idname = "OUTLINER_OT_collection_exclude_set"; ot->description = "Exclude collection from the active view layer"; @@ -870,7 +870,7 @@ void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Clear Exclude"; + ot->name = "Enable in View Layer"; ot->idname = "OUTLINER_OT_collection_exclude_clear"; ot->description = "Include collection in the active view layer"; @@ -965,8 +965,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) LayerCollection *lc_master = view_layer->layer_collections.first; for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + lc_iter->flag |= LAYER_COLLECTION_HIDE; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE); } } @@ -1023,12 +1023,12 @@ void OUTLINER_OT_collection_isolate(wmOperatorType *ot) static bool collection_show_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_HIDE); } static bool collection_hide_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_HIDE); } static bool collection_inside_poll(bContext *C) @@ -1163,12 +1163,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag) static bool collection_enable_poll(bContext *C) { - return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEWPORT); } static bool collection_disable_poll(bContext *C) { - return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEWPORT); } static bool collection_enable_render_poll(bContext *C) @@ -1188,7 +1188,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) SpaceOutliner *soops = CTX_wm_space_outliner(C); const bool is_render = strstr(op->idname, "render"); const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); - int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW; + int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEWPORT; struct CollectionEditData data = { .scene = scene, .soops = soops, @@ -1215,7 +1215,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) /* Make sure (at least for this view layer) the collection is visible. */ if (clear && !is_render) { - layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + layer_collection->flag &= ~LAYER_COLLECTION_HIDE; } } BLI_gset_free(data.collections_to_edit, NULL); @@ -1408,8 +1408,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) LayerCollection *lc_master = view_layer->layer_collections.first; for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + lc_iter->flag &= ~LAYER_COLLECTION_HIDE; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE); } /* Unhide all objects. */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index b556f58a02d..aed7af3911f 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -270,127 +270,413 @@ static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void } } -static int base_pushed_state_cb(bContext *UNUSED(C), void *poin) +static void outliner_object_set_flag_recursive_cb(bContext *C, + Base *base, + Object *ob, + const char *propname) +{ + Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + PointerRNA ptr; + + bool extend = (win->eventstate->shift != 0); + + if (!extend) { + return; + } + + /* Create PointerRNA and PropertyRNA for either Object or Base. */ + ID *id = ob ? &ob->id : &scene->id; + StructRNA *struct_rna = ob ? &RNA_Object : &RNA_ObjectBase; + void *data = ob ? (void *)ob : (void *)base; + + RNA_pointer_create(id, struct_rna, data, &ptr); + PropertyRNA *base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname); + const bool value = RNA_property_boolean_get(&ptr, base_or_object_prop); + + Object *ob_parent = ob ? ob : base->object; + + for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) { + if (BKE_object_is_child_recursive(ob_parent, ob_iter)) { + if (ob) { + RNA_id_pointer_create(&ob_iter->id, &ptr); + DEG_id_tag_update(&ob_iter->id, ID_RECALC_COPY_ON_WRITE); + } + else { + Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter); + RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr); + } + RNA_property_boolean_set(&ptr, base_or_object_prop, value); + } + } + + /* We don't call RNA_property_update() due to performance, so we batch update them. */ + if (ob) { + BKE_main_collection_sync_remap(bmain); + DEG_relations_tag_update(bmain); + } + else { + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + } +} + +/** + * Object properties. + * */ +static void outliner__object_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + Object *ob = poin; + char *propname = poin2; + outliner_object_set_flag_recursive_cb(C, NULL, ob, propname); +} + +/** + * Base properties. + * */ +static void outliner__base_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) { Base *base = poin; - Object *ob = base->object; + char *propname = poin2; + outliner_object_set_flag_recursive_cb(C, base, NULL, propname); +} - const bool is_visible = ((base->flag & BASE_HIDDEN) == 0) && - ((ob->restrictflag & OB_RESTRICT_VIEW) == 0); - return !is_visible; +/** Create either a RNA_LayerCollection or a RNA_Collection pointer. */ +static void outliner_layer_or_collection_pointer_create(Scene *scene, + LayerCollection *layer_collection, + Collection *collection, + PointerRNA *ptr) +{ + if (collection) { + RNA_id_pointer_create(&collection->id, ptr); + } + else { + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, ptr); + } } -static void hidebutton_base_flag_cb(bContext *C, void *poin, void *poin2) +/** Create either a RNA_ObjectBase or a RNA_Object pointer. */ +static void outliner_base_or_object_pointer_create(ViewLayer *view_layer, + Collection *collection, + Object *ob, + PointerRNA *ptr) { - wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - Base *base = poin2; - Object *ob = base->object; - bool do_disable = (CTX_wm_window(C)->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; - bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - const bool is_linked = ID_IS_LINKED(ob); + if (collection) { + RNA_id_pointer_create(&ob->id, ptr); + } + else { + Base *base = BKE_view_layer_base_find(view_layer, ob); + RNA_pointer_create(&base->object->id, &RNA_ObjectBase, base, ptr); + } +} - if (do_disable) { - if (!is_linked) { - ob->restrictflag |= OB_RESTRICT_VIEW; - depsgraph_changed = true; - } +/* Note: Collection is only valid when we want to change the collection data, otherwise we get it + * from layer collection. Layer collection is valid whenever we are looking at a view layer. */ +static void outliner_collection_set_flag_recursive(Scene *scene, + ViewLayer *view_layer, + LayerCollection *layer_collection, + Collection *collection, + PropertyRNA *layer_or_collection_prop, + PropertyRNA *base_or_object_prop, + const bool value) +{ + if (layer_collection && layer_collection->flag & LAYER_COLLECTION_EXCLUDE) { + return; } - else if (do_isolate) { - depsgraph_changed = (!is_linked) && ((ob->restrictflag & OB_RESTRICT_VIEW) != 0); + PointerRNA ptr; + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, value); - if (!extend) { - /* Make only one base visible. */ - for (Base *other = view_layer->object_bases.first; other; other = other->next) { - other->flag |= BASE_HIDDEN; - } + /* Set the same flag for the nested objects as well. */ + if (base_or_object_prop) { + /* Note: We can't use BKE_collection_object_cache_get() + * otherwise we would not take collection exclusion into account. */ + for (CollectionObject *cob = layer_collection->collection->gobject.first; cob; + cob = cob->next) { - base->flag &= ~BASE_HIDDEN; - } - else { - /* Toggle visibility of one base. */ - base->flag ^= BASE_HIDDEN; - } + outliner_base_or_object_pointer_create(view_layer, collection, cob->ob, &ptr); + RNA_property_boolean_set(&ptr, base_or_object_prop, value); - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; + if (collection) { + DEG_id_tag_update(&cob->ob->id, ID_RECALC_COPY_ON_WRITE); + } } } - else if (ob->restrictflag & OB_RESTRICT_VIEW) { - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; - base->flag &= ~BASE_HIDDEN; + + /* Keep going recursively. */ + ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); + for (Link *link = lb->first; link; link = link->next) { + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + Collection *collection_iter = layer_collection ? + (collection ? layer_collection_iter->collection : NULL) : + ((CollectionChild *)link)->collection; + outliner_collection_set_flag_recursive(scene, + view_layer, + layer_collection_iter, + collection_iter, + layer_or_collection_prop, + base_or_object_prop, + value); + } + + if (collection) { + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); + } +} + +/** Check if collection is already isolated. + * + * A collection is isolated if all its parents and children are "visible". + * All the other collections must be "invisible". + * + * Note: We could/should boost performance by iterating over the tree twice. + * First tagging all the children/parent collections, then getting their values and comparing. + * To run BKE_collection_has_collection() so many times is silly and slow. + */ +static bool outliner_collection_is_isolated(Scene *scene, + const LayerCollection *layer_collection_cmp, + const Collection *collection_cmp, + const bool value_cmp, + const PropertyRNA *layer_or_collection_prop, + LayerCollection *layer_collection, + Collection *collection) +{ + PointerRNA ptr; + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + const bool value = RNA_property_boolean_get(&ptr, (PropertyRNA *)layer_or_collection_prop); + Collection *collection_ensure = collection ? collection : layer_collection->collection; + const Collection *collection_ensure_cmp = collection_cmp ? collection_cmp : + layer_collection_cmp->collection; + + if (collection_ensure->flag & COLLECTION_IS_MASTER) { + } + else if (collection_ensure == collection_ensure_cmp) { + } + else if (BKE_collection_has_collection(collection_ensure, (Collection *)collection_ensure_cmp) || + BKE_collection_has_collection((Collection *)collection_ensure_cmp, collection_ensure)) { + /* This collection is either a parent or a child of the collection. + * We expect it to be set "visble" already. */ + if (value != value_cmp) { + return false; } - depsgraph_changed = true; } else { - base->flag ^= BASE_HIDDEN; + /* This collection is neither a parent nor a child of the collection. + * We expect it to be "invisble". */ + if (value == value_cmp) { + return false; + } } - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id); + /* Keep going recursively. */ + ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); + for (Link *link = lb->first; link; link = link->next) { + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + Collection *collection_iter = layer_collection ? + (collection ? layer_collection_iter->collection : NULL) : + ((CollectionChild *)link)->collection; + if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } + if (!outliner_collection_is_isolated(scene, + layer_collection_cmp, + collection_cmp, + value_cmp, + layer_or_collection_prop, + layer_collection_iter, + collection_iter)) { + return false; + } } - if (!do_disable) { - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + return true; } -static int layer_collection_pushed_state_cb(bContext *UNUSED(C), void *poin) +static void outliner_collection_isolate_flag(Scene *scene, + ViewLayer *view_layer, + LayerCollection *layer_collection, + Collection *collection, + PropertyRNA *layer_or_collection_prop, + const char *propname, + const bool value) { - LayerCollection *lc = poin; - Collection *collection = lc->collection; + PointerRNA ptr; + const bool is_hide = strstr(propname, "hide_") != NULL; + + LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first : + NULL; + Collection *top_collection = collection ? scene->master_collection : NULL; + + bool was_isolated = (value == is_hide); + was_isolated &= outliner_collection_is_isolated(scene, + layer_collection, + collection, + !is_hide, + layer_or_collection_prop, + top_layer_collection, + top_collection); + + if (was_isolated) { + const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop); + /* Make every collection go back to its default "visibility" state. */ + outliner_collection_set_flag_recursive(scene, + view_layer, + top_layer_collection, + top_collection, + layer_or_collection_prop, + NULL, + default_value); + return; + } + + /* Make every collection "invisible". */ + outliner_collection_set_flag_recursive(scene, + view_layer, + top_layer_collection, + top_collection, + layer_or_collection_prop, + NULL, + is_hide); + + /* Make this collection and its children collections the only "visible". */ + outliner_collection_set_flag_recursive( + scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide); + + /* Make this collection direct parents also "visible". */ + if (layer_collection) { + LayerCollection *lc_parent = layer_collection; + for (LayerCollection *lc_iter = top_layer_collection->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) { + lc_parent = lc_iter; + break; + } + } - const bool is_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) == 0) && - ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0); - return !is_visible; + while (lc_parent != layer_collection) { + outliner_layer_or_collection_pointer_create( + scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide); + + for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) { + lc_parent = lc_iter; + break; + } + } + } + } + else { + CollectionParent *parent; + Collection *child = collection; + while ((parent = child->parents.first)) { + if (parent->collection->flag & COLLECTION_IS_MASTER) { + break; + } + RNA_id_pointer_create(&parent->collection->id, &ptr); + RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide); + child = parent->collection; + } + } } -static void hidebutton_layer_collection_flag_cb(bContext *C, void *poin, void *poin2) +static void outliner_collection_set_flag_recursive_cb(bContext *C, + LayerCollection *layer_collection, + Collection *collection, + const char *propname) { Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - LayerCollection *lc = poin2; - Collection *collection = lc->collection; - bool do_disable = (win->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; + ViewLayer *view_layer = CTX_data_view_layer(C); + PointerRNA ptr; + + bool do_isolate = (win->eventstate->ctrl != 0); bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - if (do_disable) { - if (!ID_IS_LINKED(collection)) { - collection->flag |= COLLECTION_RESTRICT_VIEW; - depsgraph_changed = true; - } + if (!ELEM(true, do_isolate, extend)) { + return; } - else if (do_isolate) { - depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, lc, extend); + + /* Create PointerRNA and PropertyRNA for either Collection or LayerCollection. */ + ID *id = collection ? &collection->id : &scene->id; + StructRNA *struct_rna = collection ? &RNA_Collection : &RNA_LayerCollection; + void *data = collection ? (void *)collection : (void *)layer_collection; + + RNA_pointer_create(id, struct_rna, data, &ptr); + outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr); + PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname); + const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop); + + PropertyRNA *base_or_object_prop = NULL; + if (layer_collection != NULL) { + /* If we are toggling Layer collections we still want to change the properties of the base + * or the objects. If we have a matching property, toggle it as well, it can be NULL. */ + struct_rna = collection ? &RNA_Object : &RNA_ObjectBase; + base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname); } - else { - bool make_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0) || - ((collection->flag & COLLECTION_RESTRICT_VIEW) != 0); - depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, lc, make_visible, extend); + + if (extend) { + outliner_collection_set_flag_recursive(scene, + view_layer, + layer_collection, + collection, + layer_or_collection_prop, + base_or_object_prop, + value); } + else { + outliner_collection_isolate_flag(scene, + view_layer, + layer_collection, + collection, + layer_or_collection_prop, + propname, + value); + } + + /* We don't call RNA_property_update() due to performance, so we batch update them. */ + BKE_main_collection_sync_remap(bmain); + DEG_relations_tag_update(bmain); +} - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); +/** + * Layer collection properties called from the ViewLayer mode. + * Change the (non-excluded) collection children, and the objects nested to them all. + */ +static void view_layer__layer_collection_set_flag_recursive_cb(bContext *C, + void *poin, + void *poin2) +{ + LayerCollection *layer_collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb(C, layer_collection, NULL, propname); +} - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_relations_tag_update(bmain); - } - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); +/** + * Collection properties called from the ViewLayer mode. + * Change the (non-excluded) collection children, and the objects nested to them all. + */ +static void view_layer__collection_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + LayerCollection *layer_collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb( + C, layer_collection, layer_collection->collection, propname); +} + +/** + * Collection properties called from the Scenes mode. + * Change the collection children but no objects. + */ +static void scenes__collection_set_flag_recursive_cb(bContext *C, void *poin, void *poin2) +{ + Collection *collection = poin; + char *propname = poin2; + outliner_collection_set_flag_recursive_cb(C, NULL, collection, propname); } static void namebutton_cb(bContext *C, void *tsep, char *oldname) @@ -568,64 +854,197 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) } } +typedef struct RestrictProperties { + bool initialized; + + PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; + PropertyRNA *base_hide_viewport; + PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; + PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only, + *layer_collection_hide_viewport; + PropertyRNA *modifier_show_viewport, *modifier_show_render; +} RestrictProperties; + +/* We don't care about the value of the property + * but whether the property should be active or grayed out. */ +typedef struct RestrictPropertiesActive { + bool object_hide_viewport; + bool object_hide_select; + bool object_hide_render; + bool base_hide_viewport; + bool collection_hide_viewport; + bool collection_hide_select; + bool collection_hide_render; + bool layer_collection_holdout; + bool layer_collection_indirect_only; + bool layer_collection_hide_viewport; + bool modifier_show_viewport; + bool modifier_show_render; +} RestrictPropertiesActive; + +static void outliner_restrict_properties_enable_collection_set( + PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active) +{ + if (props_active->collection_hide_render) { + props_active->collection_hide_render = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_render); + if (!props_active->collection_hide_render) { + props_active->layer_collection_holdout = false; + props_active->layer_collection_indirect_only = false; + props_active->object_hide_render = false; + props_active->modifier_show_render = false; + } + } + + if (props_active->collection_hide_viewport) { + props_active->collection_hide_viewport = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_viewport); + if (!props_active->collection_hide_viewport) { + props_active->collection_hide_select = false; + props_active->object_hide_select = false; + props_active->layer_collection_hide_viewport = false; + props_active->object_hide_viewport = false; + props_active->base_hide_viewport = false; + props_active->modifier_show_viewport = false; + } + } + + if (props_active->collection_hide_select) { + props_active->collection_hide_select = !RNA_property_boolean_get( + collection_ptr, props->collection_hide_select); + if (!props_active->collection_hide_select) { + props_active->object_hide_select = false; + } + } +} + +static void outliner_restrict_properties_enable_layer_collection_set( + PointerRNA *layer_collection_ptr, + PointerRNA *collection_ptr, + RestrictProperties *props, + RestrictPropertiesActive *props_active) +{ + outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active); + + if (props_active->layer_collection_holdout) { + props_active->layer_collection_holdout = RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_holdout); + } + + if (props_active->layer_collection_indirect_only) { + props_active->layer_collection_indirect_only = RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_indirect_only); + } + + if (props_active->layer_collection_hide_viewport) { + props_active->layer_collection_hide_viewport = !RNA_property_boolean_get( + layer_collection_ptr, props->layer_collection_hide_viewport); + + if (!props_active->layer_collection_hide_viewport) { + props_active->base_hide_viewport = false; + props_active->collection_hide_select = false; + props_active->object_hide_select = false; + } + } +} + static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *ar, SpaceOutliner *soops, - ListBase *lb) + ListBase *lb, + RestrictPropertiesActive props_active_parent) { /* Get RNA properties (once for speed). */ - static struct RestrictProperties { - bool initialized; - - PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; - PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; - PropertyRNA *modifier_show_viewport, *modifier_show_render; - } props = {false}; - + static RestrictProperties props = {false}; if (!props.initialized) { props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport"); props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select"); props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render"); - props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); + props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport"); props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport"); + props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); + props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection, + "holdout"); + props.layer_collection_indirect_only = RNA_struct_type_find_property(&RNA_LayerCollection, + "indirect_only"); + props.layer_collection_hide_viewport = RNA_struct_type_find_property(&RNA_LayerCollection, + "hide_viewport"); props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport"); props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render"); props.initialized = true; } + struct { + int select; + int hide; + int viewport; + int render; + int indirect_only; + int holdout; + } restrict_offsets = {0}; + int restrict_column_offset = 0; + + /* This will determine the order of drawing from RIGHT to LEFT. */ + if (soops->outlinevis == SO_VIEW_LAYER) { + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + restrict_offsets.indirect_only = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + restrict_offsets.holdout = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + } + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + restrict_offsets.render = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + restrict_offsets.viewport = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH; + } + BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) == + outliner_restrict_columns_width(soops)); + /* Create buttons. */ uiBut *bt; for (TreeElement *te = lb->first; te; te = te->next) { TreeStoreElem *tselem = TREESTORE(te); + RestrictPropertiesActive props_active = props_active_parent; + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { if (tselem->type == TSE_R_LAYER && (soops->outlinevis == SO_SCENES)) { - /* View layer render toggle. */ - ViewLayer *layer = te->directdata; + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + /* View layer render toggle. */ + ViewLayer *layer = te->directdata; - bt = uiDefIconButBitS(block, - UI_BTYPE_ICON_TOGGLE_N, - VIEW_LAYER_RENDER, - 0, - ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &layer->flag, - 0, - 0, - 0, - 0, - TIP_("Use view layer for rendering")); - UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE_N, + VIEW_LAYER_RENDER, + 0, + ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer->flag, + 0, + 0, + 0, + 0, + TIP_("Use view layer for rendering")); + UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } else if ((tselem->type == 0 && te->idcode == ID_OB) && (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { @@ -634,40 +1053,71 @@ static void outliner_draw_restrictbuts(uiBlock *block, else if (tselem->type == 0 && te->idcode == ID_OB) { PointerRNA ptr; Object *ob = (Object *)tselem->id; - RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0) { - icon = (base->flag & BASE_HIDDEN) != 0 ? ICON_HIDE_ON : ICON_HIDE_OFF; + RNA_id_pointer_create(&ob->id, &ptr); + + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + Base *base = (te->directdata) ? (Base *)te->directdata : + BKE_view_layer_base_find(view_layer, ob); + if (base) { + PointerRNA base_ptr; + RNA_pointer_create(&ob->id, &RNA_ObjectBase, base, &base_ptr); + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.hide), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &base_ptr, + props.base_hide_viewport, + -1, + 0, + 0, + 0, + 0, + TIP_("Temporarly hide in viewport\n" + "* Shift to set children")); + UI_but_func_set( + bt, outliner__base_set_flag_recursive_cb, base, (void *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.base_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - bt = uiDefIconBut(block, - UI_BTYPE_ICON_TOGGLE, - 0, - icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Hide object in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility")); - UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base); - UI_but_func_pushed_state_set(bt, base_pushed_state_cb, base); + } + + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_select, + -1, + 0, + 0, + -1, + -1, + TIP_("Disable selection in viewport\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (char *)"hide_select"); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_select) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - else { + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -678,256 +1128,352 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, -1, -1, + TIP_("Globally disable in viewports\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (void *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_render, + -1, + 0, + 0, + -1, + -1, + TIP_("Globally disable in renders\n" + "* Shift to set children")); + UI_but_func_set(bt, outliner__object_set_flag_recursive_cb, ob, (char *)"hide_render"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.object_hide_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + } + else if (tselem->type == TSE_MODIFIER) { + ModifierData *md = (ModifierData *)te->directdata; + + PointerRNA ptr; + RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_viewport, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.modifier_show_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_render, + -1, + 0, + 0, + -1, + -1, NULL); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.modifier_show_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } + } + else if (tselem->type == TSE_POSE_CHANNEL) { + bPoseChannel *pchan = (bPoseChannel *)te->directdata; + Bone *bone = pchan->bone; + Object *ob = (Object *)tselem->id; - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_P, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.object_hide_select, - -1, + &(bone->flag), + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + 0, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.object_hide_render, - -1, + &(bone->flag), + 0, + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + TIP_("Restrict selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } - else if (tselem->type == TSE_MODIFIER) { - ModifierData *md = (ModifierData *)te->directdata; - - PointerRNA ptr; - RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); + else if (tselem->type == TSE_EBONE) { + EditBone *ebone = (EditBone *)te->directdata; - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_A, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.modifier_show_viewport, - -1, + &(ebone->flag), + 0, + 0, 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } - bt = uiDefIconButR_prop(block, + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, - props.modifier_show_render, - -1, + &(ebone->flag), 0, 0, - -1, - -1, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else if (tselem->type == TSE_POSE_CHANNEL) { - bPoseChannel *pchan = (bPoseChannel *)te->directdata; - Bone *bone = pchan->bone; - Object *ob = (Object *)tselem->id; - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_P, - 0, - ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_UNSELECTABLE, - 0, - ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(bone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - } - else if (tselem->type == TSE_EBONE) { - EditBone *ebone = (EditBone *)te->directdata; - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_HIDDEN_A, - 0, - ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(ebone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI(block, - UI_BTYPE_ICON_TOGGLE, - BONE_UNSELECTABLE, - 0, - ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &(ebone->flag), - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + 0, + 0, + TIP_("Restrict selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } } else if (tselem->type == TSE_GP_LAYER) { ID *id = tselem->id; bGPDlayer *gpl = (bGPDlayer *)te->directdata; - bt = uiDefIconButBitS(block, - UI_BTYPE_ICON_TOGGLE, - GP_LAYER_HIDE, - 0, - ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &gpl->flag, - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitS( - block, - UI_BTYPE_ICON_TOGGLE, - GP_LAYER_LOCKED, - 0, - ICON_UNLOCKED, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &gpl->flag, - 0, - 0, - 0, - 0, - TIP_("Restrict/Allow editing of strokes and keyframes in this layer")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_HIDE, + 0, + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } + + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_LOCKED, + 0, + ICON_UNLOCKED, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict editing of strokes and keyframes in this layer")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } } else if (outliner_is_collection_tree_element(te)) { - LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL; + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? + te->directdata : + NULL; Collection *collection = outliner_collection_from_tree_element(te); - - if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && + if ((!layer_collection || !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) && !(collection->flag & COLLECTION_IS_MASTER)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; RNA_id_pointer_create(&collection->id, &collection_ptr); + if (layer_collection != NULL) { + RNA_pointer_create( + &scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); + } - if (lc != NULL) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0) { - icon = (lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0 ? ICON_HIDE_ON : - ICON_HIDE_OFF; - } - bt = uiDefIconBut(block, - UI_BTYPE_ICON_TOGGLE, - 0, - icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Hide collection in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility\n" - "* Shift to hide inside objects and collections")); - UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); - UI_but_func_pushed_state_set(bt, layer_collection_pushed_state_cb, lc); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + /* Update the restriction column values for the collection children. */ + if (layer_collection) { + outliner_restrict_properties_enable_layer_collection_set( + &layer_collection_ptr, &collection_ptr, &props, &props_active); } else { + outliner_restrict_properties_enable_collection_set( + &collection_ptr, &props, &props_active); + } + + if (layer_collection != NULL) { + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.hide), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_hide_viewport, + -1, + 0, + 0, + 0, + 0, + TIP_("Temporarily hide in viewport\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_viewport"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.holdout), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_holdout, + -1, + 0, + 0, + 0, + 0, + TIP_("Mask out objects in collection from view layer\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"holdout"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_holdout) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + bt = uiDefIconButR_prop( + block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.indirect_only), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + props.layer_collection_indirect_only, + -1, + 0, + 0, + 0, + 0, + TIP_("Objects in collection only contribute indirectly (through shadows and " + "reflections) in the view layer\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections")); + UI_but_func_set(bt, + view_layer__layer_collection_set_flag_recursive_cb, + layer_collection, + (char *)"indirect_only"); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.layer_collection_indirect_only) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } + } + + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - restrict_offsets.viewport), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -938,51 +1484,102 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, 0, - NULL); + TIP_("Globally disable in viewports\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_viewport"); + } + else { + UI_but_func_set(bt, + scenes__collection_set_flag_recursive_cb, + collection, + (char *)"hide_viewport"); + } UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_viewport) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } } - bt = uiDefIconButR_prop(block, - UI_BTYPE_ICON_TOGGLE, - 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &collection_ptr, - props.collection_hide_render, - -1, - 0, - 0, - 0, - 0, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.render), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_render, + -1, + 0, + 0, + 0, + 0, + TIP_("Globally disable in renders\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_render"); + } + else { + UI_but_func_set( + bt, scenes__collection_set_flag_recursive_cb, collection, (char *)"hide_render"); + } + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_render) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } - bt = uiDefIconButR_prop(block, - UI_BTYPE_ICON_TOGGLE, - 0, - 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - &collection_ptr, - props.collection_hide_select, - -1, - 0, - 0, - 0, - 0, - NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - restrict_offsets.select), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_select, + -1, + 0, + 0, + 0, + 0, + TIP_("Disable selection in viewport\n" + "* Ctrl to isolate collection\n" + "* Shift to set inside collections and objects")); + if (layer_collection != NULL) { + UI_but_func_set(bt, + view_layer__collection_set_flag_recursive_cb, + layer_collection, + (char *)"hide_select"); + } + else { + UI_but_func_set( + bt, scenes__collection_set_flag_recursive_cb, collection, (char *)"hide_select"); + } + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (!props_active.collection_hide_select) { + UI_but_flag_enable(bt, UI_BUT_INACTIVE); + } + } } } } if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree); + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree, props_active); } } } @@ -1005,6 +1602,23 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s but_flag |= UI_BUT_DISABLED; } + BLI_str_format_int_grouped(buf, id->us); + bt = uiDefBut(block, + UI_BTYPE_BUT, + 1, + buf, + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + TIP_("Number of users of this data-block")); + UI_but_flag_enable(bt, but_flag); + if (id->flag & LIB_FAKEUSER) { icon = ICON_FILE_TICK; tip = TIP_("Data-block will be retained using a fake user"); @@ -1018,7 +1632,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s LIB_FAKEUSER, 1, icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -1031,29 +1645,12 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *s UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); UI_but_flag_enable(bt, but_flag); - BLI_str_format_int_grouped(buf, id->us); - bt = uiDefBut(block, - UI_BTYPE_BUT, - 1, - buf, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), - te->ys, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - TIP_("Number of users of this data-block")); - UI_but_flag_enable(bt, but_flag); - bt = uiDefButBitS(block, UI_BTYPE_ICON_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ", - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)(ar->v2d.cur.xmax - OL_TOG_USER_BUTS_FAKEUSER), te->ys, UI_UNIT_X, UI_UNIT_Y, @@ -1179,8 +1776,13 @@ static void outliner_draw_rnabuts( } } -static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) +static void outliner_buttons(const bContext *C, + uiBlock *block, + ARegion *ar, + const float restrict_column_width, + TreeElement *te) { + SpaceOutliner *soops = CTX_wm_space_outliner(C); uiBut *bt; TreeStoreElem *tselem; int spx, dx, len; @@ -1206,7 +1808,11 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre } spx = te->xs + 1.8f * UI_UNIT_X; - dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X); + if ((tselem->type == TSE_LAYER_COLLECTION) && + (soops->show_restrict_flags & SO_RESTRICT_ENABLE)) { + spx += UI_UNIT_X; + } + dx = ar->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X); bt = uiDefBut(block, UI_BTYPE_TEXT, @@ -1778,6 +2384,60 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) return data; } +static void tselem_draw_layer_collection_enable_icon( + Scene *scene, uiBlock *block, int xmax, float x, float y, TreeElement *te, float alpha) +{ + /* Get RNA property (once for speed). */ + static PropertyRNA *exclude_prop = NULL; + if (exclude_prop == NULL) { + exclude_prop = RNA_struct_type_find_property(&RNA_LayerCollection, "exclude"); + } + + if (x >= xmax) { + /* Placement of icons, copied from interface_widgets.c. */ + float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; + x += 2.0f * aspect; + y += 2.0f * aspect; + + /* restrict column clip... it has been coded by simply overdrawing, + * doesn't work for buttons */ + char color[4]; + int icon = RNA_property_ui_icon(exclude_prop); + if (UI_icon_get_theme_color(icon, (uchar *)color)) { + UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + } + else { + UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + } + } + else { + LayerCollection *layer_collection = te->directdata; + PointerRNA layer_collection_ptr; + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); + + char emboss = UI_block_emboss_get(block); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiBut *bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + x, + y, + UI_UNIT_X, + UI_UNIT_Y, + &layer_collection_ptr, + exclude_prop, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_block_emboss_set(block, emboss); + } +} + static void tselem_draw_icon(uiBlock *block, int xmax, float x, @@ -1801,7 +2461,13 @@ static void tselem_draw_icon(uiBlock *block, /* restrict column clip... it has been coded by simply overdrawing, * doesn't work for buttons */ - UI_icon_draw_alpha(x, y, data.icon, alpha); + char color[4]; + if (UI_icon_get_theme_color(data.icon, (uchar *)color)) { + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); + } + else { + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + } } else { uiDefIconBut(block, @@ -1868,6 +2534,17 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, GPU_blend(true); /* Roundbox and text drawing disables. */ } +static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) +{ + float text[4]; + UI_GetThemeColor4fv(TH_TEXT, text); + + copy_v3_v3(icon_color, text); + icon_color[3] = 0.4f; + copy_v3_v3(icon_border, text); + icon_border[3] = 0.2f; +} + static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, const uiFontStyle *fstyle, @@ -1882,23 +2559,34 @@ static void outliner_draw_iconrow_doit(uiBlock *block, if (active != OL_DRAWSEL_NONE) { float ufac = UI_UNIT_X / 20.0f; - float color[4] = {1.0f, 1.0f, 1.0f, 0.2f}; - + float icon_color[4], icon_border[4]; + outliner_icon_background_colors(icon_color, icon_border); + icon_color[3] *= alpha_fac; + if (active == OL_DRAWSEL_ACTIVE) { + UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color); + icon_border[3] = 0.3f; + } UI_draw_roundbox_corner_set(UI_CNR_ALL); - color[3] *= alpha_fac; UI_draw_roundbox_aa(true, - (float)*offsx + 1.0f * ufac, - (float)ys + 1.0f * ufac, - (float)*offsx + UI_UNIT_X - 1.0f * ufac, + (float)*offsx, + (float)ys + ufac, + (float)*offsx + UI_UNIT_X, + (float)ys + UI_UNIT_Y - ufac, + (float)UI_UNIT_Y / 4.0f, + icon_color); + /* border around it */ + UI_draw_roundbox_aa(false, + (float)*offsx, + (float)ys + ufac, + (float)*offsx + UI_UNIT_X, (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac, - color); + (float)UI_UNIT_Y / 4.0f, + icon_border); GPU_blend(true); /* Roundbox disables. */ } - /* No inlined icon should be clickable. */ - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false); te->xs = *offsx; te->ys = ys; te->xend = (short)*offsx + UI_UNIT_X; @@ -1952,7 +2640,7 @@ static void outliner_draw_iconrow(bContext *C, float alpha_fac, MergedIconRow *merged) { - eOLDrawState active; + eOLDrawState active = OL_DRAWSEL_NONE; const Object *obact = OBACT(view_layer); for (TreeElement *te = lb->first; te; te = te->next) { @@ -1972,7 +2660,7 @@ static void outliner_draw_iconrow(bContext *C, OL_DRAWSEL_NONE; } else if (is_object_data_in_editmode(tselem->id, obact)) { - active = OL_DRAWSEL_NORMAL; + active = OL_DRAWSEL_ACTIVE; } else { active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false); @@ -2068,21 +2756,23 @@ static void outliner_draw_tree_element(bContext *C, bool draw_grayed_out, int startx, int *starty, + const float restrict_column_width, TreeElement **te_edit) { - TreeStoreElem *tselem; + TreeStoreElem *tselem = TREESTORE(te); float ufac = UI_UNIT_X / 20.0f; int offsx = 0; eOLDrawState active = OL_DRAWSEL_NONE; - float color[4]; - tselem = TREESTORE(te); + unsigned char text_color[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_color); + float icon_bgcolor[4], icon_border[4]; + outliner_icon_background_colors(icon_bgcolor, icon_border); if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { const float alpha_fac = ((te->flag & TE_DISABLED) || (te->flag & TE_CHILD_NOT_IN_COLLECTION) || draw_grayed_out) ? 0.5f : 1.0f; - const float alpha = 0.5f * alpha_fac; int xmax = ar->v2d.cur.xmax; if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { @@ -2090,8 +2780,8 @@ static void outliner_draw_tree_element(bContext *C, } /* icons can be ui buts, we don't want it to overlap with restrict */ - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - xmax -= OL_TOGW + UI_UNIT_X; + if (restrict_column_width > 0) { + xmax -= restrict_column_width + UI_UNIT_X; } GPU_blend(true); @@ -2101,7 +2791,8 @@ static void outliner_draw_tree_element(bContext *C, const Object *obact = OBACT(view_layer); if (te->idcode == ID_SCE) { if (tselem->id == (ID *)scene) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + /* active scene */ + icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -2111,35 +2802,33 @@ static void outliner_draw_tree_element(bContext *C, BKE_view_layer_base_find(view_layer, ob); const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); - if (ob == obact || is_selected) { - uchar col[4] = {0, 0, 0, 0}; - - /* outliner active ob: always white text, circle color now similar to view3d */ - + if (ob == obact) { active = OL_DRAWSEL_ACTIVE; - if (ob == obact) { - if (is_selected) { - UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); - col[3] = alpha; - } + } - active = OL_DRAWSEL_NORMAL; + if (is_selected) { + if (ob == obact) { + /* active selected object */ + UI_GetThemeColor3ubv(TH_ACTIVE_OBJECT, text_color); + text_color[3] = 255; } - else if (is_selected) { - UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); - col[3] = alpha; + else { + /* other selected objects */ + UI_GetThemeColor3ubv(TH_SELECTED_OBJECT, text_color); + text_color[3] = 255; } - rgba_float_args_set( - color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); } } else if (is_object_data_in_editmode(tselem->id, obact)) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + /* objects being edited */ + UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor); + icon_border[3] = 0.3f; active = OL_DRAWSEL_ACTIVE; } else { if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) { - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + /* active items like camera or material */ + icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -2147,19 +2836,36 @@ static void outliner_draw_tree_element(bContext *C, else { active = tree_element_type_active( C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + /* active collection*/ + icon_bgcolor[3] = 0.2f; + } + + /* Checkbox to enable collections. */ + if ((tselem->type == TSE_LAYER_COLLECTION) && + (soops->show_restrict_flags & SO_RESTRICT_ENABLE)) { + tselem_draw_layer_collection_enable_icon( + scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f); + offsx += UI_UNIT_X; } /* active circle */ if (active != OL_DRAWSEL_NONE) { UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_aa(true, - (float)startx + UI_UNIT_X + 1.0f * ufac, - (float)*starty + 1.0f * ufac, - (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac, - (float)*starty + UI_UNIT_Y - 1.0f * ufac, - UI_UNIT_Y / 2.0f - 1.0f * ufac, - color); + (float)startx + offsx + UI_UNIT_X, + (float)*starty + ufac, + (float)startx + offsx + 2.0f * UI_UNIT_X, + (float)*starty + UI_UNIT_Y - ufac, + UI_UNIT_Y / 4.0f, + icon_bgcolor); + /* border around it */ + UI_draw_roundbox_aa(false, + (float)startx + offsx + UI_UNIT_X, + (float)*starty + ufac, + (float)startx + offsx + 2.0f * UI_UNIT_X, + (float)*starty + UI_UNIT_Y - ufac, + UI_UNIT_Y / 4.0f, + icon_border); GPU_blend(true); /* roundbox disables it */ te->flag |= TE_ACTIVE; // for lookup in display hierarchies @@ -2190,7 +2896,6 @@ static void outliner_draw_tree_element(bContext *C, offsx += UI_UNIT_X; /* datatype icon */ - if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { tselem_draw_icon( block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true); @@ -2232,21 +2937,12 @@ static void outliner_draw_tree_element(bContext *C, /* name */ if ((tselem->flag & TSE_TEXTBUT) == 0) { - unsigned char text_col[4]; - - if (active == OL_DRAWSEL_NORMAL) { - UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); - } - else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col); - text_col[3] = 255; - } - else { - UI_GetThemeColor4ubv(TH_TEXT, text_col); + if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_color); + text_color[3] = 255; } - text_col[3] *= alpha_fac; - - UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col); + text_color[3] *= alpha_fac; + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_color); } offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); @@ -2306,6 +3002,7 @@ static void outliner_draw_tree_element(bContext *C, draw_childs_grayed_out, startx + UI_UNIT_X, starty, + restrict_column_width, te_edit); } } @@ -2513,11 +3210,15 @@ static void outliner_draw_highlights_recursive(unsigned pos, if (tselem->flag & TSE_DRAG_BEFORE) { immUniformColor4fv(col); - immRecti(pos, start_x, start_y + UI_UNIT_Y, end_x, start_y + UI_UNIT_Y); + immRecti(pos, + start_x, + start_y + UI_UNIT_Y - U.pixelsize, + end_x, + start_y + UI_UNIT_Y + U.pixelsize); } else if (tselem->flag & TSE_DRAG_AFTER) { immUniformColor4fv(col); - immRecti(pos, start_x, start_y, end_x, start_y); + immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize); } else { immUniformColor3fvAlpha(col, col[3] * 0.5f); @@ -2581,7 +3282,7 @@ static void outliner_draw_tree(bContext *C, ViewLayer *view_layer, ARegion *ar, SpaceOutliner *soops, - const bool has_restrict_icons, + const float restrict_column_width, TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; @@ -2603,8 +3304,8 @@ static void outliner_draw_tree(bContext *C, /* set scissor so tree elements or lines can't overlap restriction icons */ float scissor[4] = {0}; - if (has_restrict_icons) { - int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; + if (restrict_column_width > 0.0f) { + int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)restrict_column_width + 1; CLAMP_MIN(mask_x, 0); GPU_scissor_get_f(scissor); @@ -2632,10 +3333,11 @@ static void outliner_draw_tree(bContext *C, (te->flag & TE_DRAGGING) != 0, startx, &starty, + restrict_column_width, te_edit); } - if (has_restrict_icons) { + if (restrict_column_width > 0.0f) { /* reset scissor */ GPU_scissor(UNPACK4(scissor)); } @@ -2652,7 +3354,10 @@ static void outliner_back(ARegion *ar) uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShade(TH_BACK, 6); + + float col_alternating[4]; + UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating); + immUniformThemeColorBlend(TH_BACK, TH_ROW_ALTERNATE, col_alternating[3]); const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; float y1 = ystart, y2; @@ -2690,7 +3395,6 @@ void draw_outliner(const bContext *C) uiBlock *block; int sizey = 0, sizex = 0, sizex_rna = 0; TreeElement *te_edit = NULL; - bool has_restrict_icons; outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always @@ -2700,6 +3404,7 @@ void draw_outliner(const bContext *C) /* extend size to allow for horizontal scrollbar */ sizey += V2D_SCROLL_HEIGHT; + const float restrict_column_width = outliner_restrict_columns_width(soops); if (soops->outlinevis == SO_DATA_API) { /* RNA has two columns: * - column 1 is (max_width + OL_RNA_COL_SPACEX) or @@ -2715,7 +3420,6 @@ void draw_outliner(const bContext *C) /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; - has_restrict_icons = false; } else { /* width must take into account restriction columns (if visible) @@ -2724,13 +3428,8 @@ void draw_outliner(const bContext *C) // XXX should use outliner_width instead when te->xend will be set correctly... outliner_rna_width(soops, &soops->tree, &sizex, 0); - /* constant offset for restriction columns */ - // XXX this isn't that great yet... - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - sizex += OL_TOGW * 3; - } - - has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); + /* Constant offset for restriction columns */ + sizex += restrict_column_width; } /* adds vertical offset */ @@ -2748,7 +3447,7 @@ void draw_outliner(const bContext *C) outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); outliner_draw_tree( - (bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); + (bContext *)C, block, scene, view_layer, ar, soops, restrict_column_width, &te_edit); /* Default to no emboss for outliner UI. */ UI_block_emboss_set(block, UI_EMBOSS_NONE); @@ -2761,20 +3460,22 @@ void draw_outliner(const bContext *C) outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); UI_block_emboss_set(block, UI_EMBOSS_NONE); } - else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + else if (soops->outlinevis == SO_ID_ORPHANS) { /* draw user toggle columns */ outliner_draw_userbuts(block, ar, soops, &soops->tree); } - else if (has_restrict_icons) { + else if (restrict_column_width > 0.0f) { /* draw restriction columns */ - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree); + RestrictPropertiesActive props_active; + memset(&props_active, 1, sizeof(RestrictPropertiesActive)); + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree, props_active); } UI_block_emboss_set(block, UI_EMBOSS); - /* draw edit buttons if nessecery */ + /* Draw edit buttons if necessary. */ if (te_edit) { - outliner_buttons(C, block, ar, te_edit); + outliner_buttons(C, block, ar, restrict_column_width, te_edit); } UI_block_end(C, block); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index a943e972cf5..c32b2b051f8 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -88,6 +88,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { + /* stop highlighting if out of area */ + if (!ED_screen_area_active(C)) { + return OPERATOR_PASS_THROUGH; + } + /* Drag and drop does own highlighting. */ wmWindowManager *wm = CTX_wm_manager(C); if (wm->drags.first) { @@ -1025,8 +1030,8 @@ int common_restrict_check(bContext *C, Object *ob) Object *obedit = CTX_data_edit_object(C); if (obedit && obedit == ob) { /* found object is hidden, reset */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + ob->restrictflag &= ~OB_RESTRICT_VIEWPORT; } /* found object is unselectable, reset */ if (ob->restrictflag & OB_RESTRICT_SELECT) { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 8211e3005c7..15489c61230 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -156,11 +156,9 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_RESTRICT_RENDERX (UI_UNIT_X + V2D_SCROLL_WIDTH) - -#define OL_TOGW OL_TOG_RESTRICT_SELECTX +#define OL_TOG_USER_BUTS_USERS (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) +#define OL_TOG_USER_BUTS_STATUS (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) +#define OL_TOG_USER_BUTS_FAKEUSER (UI_UNIT_X + V2D_SCROLL_WIDTH) #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -449,5 +447,6 @@ bool outliner_tree_traverse(const SpaceOutliner *soops, int filter_tselem_flag, TreeTraversalFunc func, void *customdata); +float outliner_restrict_columns_width(const struct SpaceOutliner *soops); #endif /* __OUTLINER_INTERN_H__ */ diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 995f41382cd..ae17158829c 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -450,32 +450,6 @@ static eOLDrawState tree_element_active_material(bContext *C, return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_light(bContext *UNUSED(C), - Scene *UNUSED(scene), - ViewLayer *view_layer, - SpaceOutliner *soops, - TreeElement *te, - const eOLSetState set) -{ - Object *ob; - - /* we search for the object parent */ - ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == NULL || ob != OBACT(view_layer)) { - /* just paranoia */ - return OL_DRAWSEL_NONE; - } - - if (set != OL_SETSEL_NONE) { - // XXX extern_set_butspace(F5KEY, 0); - } - else { - return OL_DRAWSEL_NORMAL; - } - - return OL_DRAWSEL_NONE; -} - static eOLDrawState tree_element_active_camera(bContext *UNUSED(C), Scene *scene, ViewLayer *UNUSED(sl), @@ -1041,8 +1015,6 @@ eOLDrawState tree_element_active(bContext *C, return tree_element_active_material(C, scene, view_layer, soops, te, set); case ID_WO: return tree_element_active_world(C, scene, view_layer, soops, te, set); - case ID_LA: - return tree_element_active_light(C, scene, view_layer, soops, te, set); case ID_TXT: return tree_element_active_text(C, scene, view_layer, soops, te, set); case ID_CA: @@ -1271,8 +1243,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, const ARegion *ar, float view_co_x) { - return ((soops->outlinevis != SO_DATA_API) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); + return (view_co_x > ar->v2d.cur.xmax - outliner_restrict_columns_width(soops)); } /** diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 4e3fd6037bb..80424f021e2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -302,6 +302,9 @@ static void outliner_add_scene_contents(SpaceOutliner *soops, tenlay->directdata = view_layer; } + /* World */ + outliner_add_element(soops, lb, sce->world, te, 0, 0); + /* Collections */ ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); ten->name = IFACE_("Scene Collection"); @@ -1370,6 +1373,12 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, const bool show_objects) { for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { + const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; + + if (exclude && ((soops->show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) { + continue; + } + ID *id = &lc->collection->id; TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); @@ -1382,8 +1391,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops, tselem->flag &= ~TSE_CLOSED; } - const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; - if (exclude || ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0)) { + if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) { ten->flag |= TE_DISABLED; } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 03d15088380..f57dce97b38 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -31,6 +31,7 @@ #include "ED_armature.h" #include "UI_interface.h" +#include "UI_view2d.h" #include "outliner_intern.h" @@ -261,3 +262,41 @@ bool outliner_tree_traverse(const SpaceOutliner *soops, return true; } + +float outliner_restrict_columns_width(const SpaceOutliner *soops) +{ + int num_columns = 0; + + switch (soops->outlinevis) { + case SO_DATA_API: + case SO_SEQUENCE: + case SO_LIBRARIES: + return 0.0f; + case SO_ID_ORPHANS: + num_columns = 3; + break; + case SO_VIEW_LAYER: + if (soops->show_restrict_flags & SO_RESTRICT_HOLDOUT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) { + num_columns++; + } + ATTR_FALLTHROUGH; + case SO_SCENES: + if (soops->show_restrict_flags & SO_RESTRICT_SELECT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) { + num_columns++; + } + if (soops->show_restrict_flags & SO_RESTRICT_RENDER) { + num_columns++; + } + break; + } + return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH); +} diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index a8e3129b5b4..313e6014b88 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -302,6 +302,7 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED( soutliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner"); soutliner->spacetype = SPACE_OUTLINER; soutliner->filter_id_type = ID_GR; + soutliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for outliner"); @@ -383,6 +384,14 @@ static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, } } +static void outliner_deactivate(struct ScrArea *sa) +{ + /* Remove hover highlights */ + SpaceOutliner *soops = sa->spacedata.first; + outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false); + ED_region_tag_redraw(BKE_area_find_region_type(sa, RGN_TYPE_WINDOW)); +} + /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { @@ -400,6 +409,7 @@ void ED_spacetype_outliner(void) st->keymap = outliner_keymap; st->dropboxes = outliner_dropboxes; st->id_remap = outliner_id_remap; + st->deactivate = outliner_deactivate; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index b5bb79fb430..e8f18eeebc7 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -149,7 +149,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) int proximity = INT_MAX; if (!ed || !ed->seqbasep) { - return 1; + return 2; } for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -161,9 +161,9 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) } if (tgt) { - return tgt->machine; + return tgt->machine + 1; } - return 1; + return 2; } static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, int flag, int type) @@ -173,7 +173,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i int cfra = (int)CFRA; /* effect strips don't need a channel initialized from the mouse */ - if (!(flag & SEQPROP_NOCHAN)) { + if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) { RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type)); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 86bc315b994..fb875c8c4a4 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -60,6 +60,7 @@ #include "ED_mask.h" #include "ED_sequencer.h" #include "ED_screen.h" +#include "ED_time_scrub_ui.h" #include "ED_space_api.h" #include "BIF_glutil.h" @@ -960,7 +961,7 @@ static void draw_seq_strip(const bContext *C, x1 = seq->startdisp + handsize_clamped; x2 = seq->enddisp - handsize_clamped; - float scroller_vert_xoffs = (V2D_SCROLL_WIDTH_TEXT + SEQ_SCROLLER_TEXT_OFFSET) * pixelx; + float scroller_vert_xoffs = (V2D_SCROLL_WIDTH_HANDLES + SEQ_SCROLLER_TEXT_OFFSET) * pixelx; /* info text on the strip */ if (x1 < v2d->cur.xmin + scroller_vert_xoffs) { @@ -1120,8 +1121,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2]) r_viewrect[0] = (float)scene->r.xsch; r_viewrect[1] = (float)scene->r.ysch; - /* Aspect ratio seems to have no effect on output image*/ - /* r_viewrect[0] *= scene->r.xasp / scene->r.yasp; */ + r_viewrect[0] *= scene->r.xasp / scene->r.yasp; } static void sequencer_draw_gpencil(const bContext *C) @@ -1821,7 +1821,7 @@ typedef struct CacheDrawData { /* Called as a callback */ static bool draw_cache_view_cb( - void *userdata, struct Sequence *seq, int cfra, int cache_type, float UNUSED(cost)) + void *userdata, struct Sequence *seq, int nfra, int cache_type, float UNUSED(cost)) { CacheDrawData *drawdata = userdata; const bContext *C = drawdata->C; @@ -1847,8 +1847,7 @@ static bool draw_cache_view_cb( color[2] = 0.2f; stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; - ; - stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT); + stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_HANDLES); stripe_top = stripe_bot + stripe_ht; break; } @@ -1902,6 +1901,7 @@ static bool draw_cache_view_cb( } } + int cfra = seq->start + nfra; immUniformColor4f(color[0], color[1], color[2], color[3]); immRectf(pos, cfra, stripe_bot, cfra + 1, stripe_top); @@ -1922,12 +1922,16 @@ static void draw_cache_view(const bContext *C) uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - float stripe_bot, stripe_top, stripe_offs; + float stripe_bot, stripe_top; + float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; + CLAMP_MAX(stripe_ht, 0.2f); + CLAMP_MIN(stripe_offs, stripe_ht / 2); + if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) { - stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT); + stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_HANDLES); stripe_top = stripe_bot + stripe_ht; float bg_color[4] = {1.0f, 0.4f, 0.2f, 0.1f}; @@ -1944,10 +1948,6 @@ static void draw_cache_view(const bContext *C) continue; } - CLAMP_MAX(stripe_ht, 0.2f); - stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; - CLAMP_MIN(stripe_offs, stripe_ht / 2); - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; stripe_top = stripe_bot + stripe_ht; @@ -2086,19 +2086,22 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); + /* scrubbing region */ + ED_scrubbing_draw(ar, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); + /* scrollers */ scrollers = UI_view2d_scrollers_calc(v2d, NULL); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); - /* scale numbers */ - UI_view2d_draw_scale_x__discrete_frames_or_seconds( - ar, v2d, &v2d->hor, scene, !(sseq->flag & SEQ_DRAWFRAMES)); - UI_view2d_draw_scale_y__block(ar, v2d, &v2d->vert); - - /* draw current frame number-indicator on top of scrollers */ - if ((sseq->flag & SEQ_NO_DRAW_CFRANUM) == 0) { - UI_view2d_view_orthoSpecial(ar, v2d, 1); - ANIM_draw_cfra_number(C, v2d, cfra_flag); + /* channel numbers */ + { + rcti rect; + BLI_rcti_init(&rect, + 0, + 15 * UI_DPI_FAC, + 15 * UI_DPI_FAC, + UI_DPI_FAC * ar->sizey - UI_SCRUBBING_MARGIN_Y); + UI_view2d_draw_scale_y__block(ar, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 94437d4871a..a3030153e6c 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1343,7 +1343,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU void SEQUENCER_OT_snap(struct wmOperatorType *ot) { /* identifiers */ - ot->name = "Snap Strips to Frame"; + ot->name = "Snap Strips to Playhead"; ot->idname = "SEQUENCER_OT_snap"; ot->description = "Frame where selected strips will be snapped"; diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index e16029395bd..593dd86477a 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -108,6 +108,8 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy); + fx /= scene->r.xasp / scene->r.yasp; + fx += (float)scene->r.xsch / 2.0f; fy += (float)scene->r.ysch / 2.0f; fx *= (float)ibuf->x / (float)scene->r.xsch; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 2b0c29a02ad..6ab44ded046 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -157,8 +157,8 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene) ar->v2d.minzoom = 0.01f; ar->v2d.maxzoom = 100.0f; - ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); - ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES); ar->v2d.keepzoom = 0; ar->v2d.keeptot = 0; ar->v2d.align = V2D_ALIGN_NO_NEG_Y; @@ -729,6 +729,7 @@ static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); WM_event_add_keymap_handler_v2d_mask(&ar->handlers, keymap); + UI_panel_category_active_set_default(ar, "Strip"); ED_region_panels_init(wm, ar); } @@ -816,7 +817,7 @@ void ED_spacetype_sequencer(void) art->draw = sequencer_main_region_draw; art->listener = sequencer_main_region_listener; art->message_subscribe = sequencer_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; + art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; BLI_addhead(&st->regiontypes, art); @@ -832,7 +833,7 @@ void ED_spacetype_sequencer(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 220; // XXX + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = sequencer_buttons_region_listener; art->init = sequencer_buttons_region_init; diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index 243642b2e8c..c36175489b3 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -74,7 +74,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) /* Count the visible lines to the cursor */ for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) { - ; + /* pass */ } if (l < 0) { return 0; @@ -101,7 +101,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) /* Work out which of the items is at the top of the visible list */ for (i = 0, item = first; i < *top && item->next; i++, item = item->next) { - ; + /* pass */ } /* Work out the target item index in the visible list */ @@ -111,7 +111,7 @@ int text_do_suggest_select(SpaceText *st, ARegion *ar) } for (i = tgti; i > 0 && item->next; i--, item = item->next) { - ; + /* pass */ } if (item) { texttool_suggest_select(item); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index cdd691fe879..ac1fb4af1c2 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1186,7 +1186,7 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc /* Set the top 'item' of the visible list */ for (i = 0, item = first; i < *top && item->next; i++, item = item->next) { - ; + /* pass */ } for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) { @@ -1665,12 +1665,14 @@ void draw_text_main(SpaceText *st, ARegion *ar) immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + GPU_line_width(2.0f); + float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniformThemeColor(TH_GRID); /* same color as line number background */ + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniformThemeColor3(TH_GRID); /* same color as line number background */ immUniform1f("dash_width", 2.0f); immUniform1f("dash_factor", 0.5f); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 7b6e0ff8771..2593571d9a3 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -101,7 +101,7 @@ static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size) } /* Allocate output before with extra space for expanded tabs. */ - const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1); + const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1) + 1; char *out_buf = MEM_mallocN(out_size * sizeof(char), __func__); /* Fill output buffer. */ @@ -247,7 +247,7 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op)) if (prop) { RNA_id_pointer_create(&text->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr); + RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } else if (st) { @@ -326,7 +326,7 @@ static int text_open_exec(bContext *C, wmOperator *op) if (pprop->prop) { RNA_id_pointer_create(&text->id, &idptr); - RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); + RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); RNA_property_update(C, &pprop->ptr, pprop->prop); } else if (st) { @@ -1268,7 +1268,7 @@ static int text_convert_whitespace_exec(bContext *C, wmOperator *op) for (j = 1; (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' '); j++) { - ; + /* pass */ } if (j == tab_len) { diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 8b290009a97..725a49e417e 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -213,12 +213,15 @@ static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) { struct RecentFile *recent; uiLayout *layout = menu->layout; - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); if (!BLI_listbase_is_empty(&G.recent_files)) { for (recent = G.recent_files.first; (recent); recent = recent->next) { const char *file = BLI_path_basename(recent->filepath); const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP; - uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath); + PointerRNA ptr; + uiItemFullO(layout, "WM_OT_open_mainfile", file, icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "filepath", recent->filepath); + RNA_boolean_set(&ptr, "display_file_selector", false); } } else { diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 2237e8b02bc..4c6f2231cc1 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -249,7 +249,7 @@ void ED_spacetype_userpref(void) art->init = userpref_navigation_region_init; art->draw = userpref_navigation_region_draw; art->listener = userpref_navigation_region_listener; - art->keymapflag = ED_KEYMAP_UI; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_NAVBAR; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index a67e6c27acb..04ef2ed8118 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -48,7 +48,7 @@ static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) UI_theme_init_default(); UI_style_init_default(); WM_event_add_notifier(C, NC_WINDOW, NULL); - + U.runtime.is_dirty = true; return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 638c77fc3cb..cc76c151a29 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -41,7 +41,6 @@ #include "GPU_batch.h" #include "GPU_matrix.h" #include "GPU_state.h" -#include "GPU_framebuffer.h" #include "ED_mesh.h" @@ -51,8 +50,6 @@ #include "view3d_intern.h" /* bad level include */ -#include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */ - int view3d_effective_drawtype(const struct View3D *v3d) { if (v3d->shading.type == OB_RENDER) { @@ -61,24 +58,6 @@ int view3d_effective_drawtype(const struct View3D *v3d) return v3d->shading.type; } -static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) -{ - if ((sce->toolsettings->selectmode & SCE_SELECT_FACE) == 0) { - return false; - } - - if (G.f & G_FLAG_BACKBUFSEL) { - return false; - } - - /* if its drawing textures with zbuf sel, then don't draw dots */ - if (dt == OB_TEXTURE && vd->shading.type == OB_TEXTURE) { - return false; - } - - return true; -} - /* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */ /* 32 values of sin function (still same result!) */ #define CIRCLE_RESOL 32 @@ -138,216 +117,6 @@ bool view3d_camera_border_hack_test = false; /* ***************** BACKBUF SEL (BBS) ********* */ -/** See #DRW_shgroup_world_clip_planes_from_rv3d, same function for draw manager. */ -static void bbs_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_clip_planes[6][4]) -{ - GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes[0]); -} - -static void bbs_mesh_verts(GPUBatch *batch, int offset, const float world_clip_planes[6][4]) -{ - GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); - - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", offset); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); -} - -static void bbs_mesh_wire(GPUBatch *batch, int offset, const float world_clip_planes[6][4]) -{ - GPU_line_width(1.0f); - glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); - - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", offset); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - - glProvokingVertex(GL_LAST_VERTEX_CONVENTION); -} - -/* two options, facecolors or black */ -static void bbs_mesh_face(GPUBatch *batch, - const bool use_select, - const float world_clip_planes[6][4]) -{ - if (use_select) { - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", 1); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - } - else { - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_UNIFORM_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "id", 0); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); - } -} - -static void bbs_mesh_face_dot(GPUBatch *batch, const float world_clip_planes[6][4]) -{ - const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_FLAT_SELECT_ID, sh_cfg); - GPU_batch_uniform_1ui(batch, "offset", 1); - if (world_clip_planes != NULL) { - bbs_world_clip_planes_from_rv3d(batch, world_clip_planes); - } - GPU_batch_draw(batch); -} - -static void bbs_mesh_solid_verts(Depsgraph *UNUSED(depsgraph), - Scene *UNUSED(scene), - Object *ob, - const float world_clip_planes[6][4]) -{ - Mesh *me = ob->data; - - GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - GPUBatch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true); - - /* Only draw faces to mask out verts, we don't want their selection ID's. */ - bbs_mesh_face(geom_faces, false, world_clip_planes); - bbs_mesh_verts(geom_verts, 1, world_clip_planes); - - bm_vertoffs = me->totvert + 1; -} - -static void bbs_mesh_solid_faces(Scene *UNUSED(scene), - Object *ob, - const float world_clip_planes[6][4]) -{ - Mesh *me = ob->data; - Mesh *me_orig = DEG_get_original_object(ob)->data; - - const bool use_hide = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL); - GPUBatch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, use_hide); - - bbs_mesh_face(geom_faces, true, world_clip_planes); -} - -void draw_object_select_id(Depsgraph *depsgraph, - Scene *scene, - View3D *v3d, - RegionView3D *rv3d, - Object *ob, - short select_mode) -{ - ToolSettings *ts = scene->toolsettings; - if (select_mode == -1) { - select_mode = ts->selectmode; - } - - GPU_matrix_mul(ob->obmat); - GPU_depth_test(true); - - const float(*world_clip_planes)[4] = NULL; - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_local(rv3d, ob->obmat); - world_clip_planes = rv3d->clip_local; - } - - switch (ob->type) { - case OB_MESH: - if (ob->mode & OB_MODE_EDIT) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_mesh; - const bool draw_facedot = check_ob_drawface_dot(scene, v3d, ob->dt); - const bool use_faceselect = (select_mode & SCE_SELECT_FACE) != 0; - - BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); - - GPUBatch *geom_faces, *geom_edges, *geom_verts, *geom_facedots; - geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(me); - if (select_mode & SCE_SELECT_EDGE) { - geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(me); - } - if (select_mode & SCE_SELECT_VERTEX) { - geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(me); - } - if (draw_facedot) { - geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(me); - } - DRW_mesh_batch_cache_create_requested(ob, me, NULL, false, true); - - bbs_mesh_face(geom_faces, use_faceselect, world_clip_planes); - - if (use_faceselect && draw_facedot) { - bbs_mesh_face_dot(geom_facedots, world_clip_planes); - } - - if (select_mode & SCE_SELECT_FACE) { - bm_solidoffs = 1 + em->bm->totface; - } - else { - bm_solidoffs = 1; - } - - ED_view3d_polygon_offset(rv3d, 1.0); - - /* we draw edges if edge select mode */ - if (select_mode & SCE_SELECT_EDGE) { - bbs_mesh_wire(geom_edges, bm_solidoffs, world_clip_planes); - bm_wireoffs = bm_solidoffs + em->bm->totedge; - } - else { - /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */ - bm_wireoffs = bm_solidoffs; - } - - ED_view3d_polygon_offset(rv3d, 1.1); - - /* we draw verts if vert select mode. */ - if (select_mode & SCE_SELECT_VERTEX) { - bbs_mesh_verts(geom_verts, bm_wireoffs, world_clip_planes); - bm_vertoffs = bm_wireoffs + em->bm->totvert; - } - else { - bm_vertoffs = bm_wireoffs; - } - - ED_view3d_polygon_offset(rv3d, 0.0); - } - else { - Mesh *me = DEG_get_original_object(ob)->data; - if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && - /* currently vertex select supports weight paint and vertex paint*/ - ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { - bbs_mesh_solid_verts(depsgraph, scene, ob, world_clip_planes); - } - else { - bbs_mesh_solid_faces(scene, ob, world_clip_planes); - } - } - break; - case OB_CURVE: - case OB_SURF: - break; - } - - GPU_matrix_set(rv3d->viewmat); -} - void ED_draw_object_facemap(Depsgraph *depsgraph, Object *ob, const float col[4], diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 9ee7bb3066d..c1891865d6d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1131,6 +1131,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win), ED_region_tag_redraw(ar); } break; + case NC_BRUSH: + ED_region_tag_redraw(ar); + break; } /* From topbar, which ones are needed? split per header? */ @@ -1200,9 +1203,106 @@ static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void view3d_buttons_region_draw(const bContext *C, ARegion *ar) +void ED_view3d_buttons_region_layout_ex(const bContext *C, + ARegion *ar, + const char *category_override) { - ED_region_panels_ex(C, ar, (const char *[]){CTX_data_mode_string(C), NULL}, -1, true); + const enum eContextObjectMode mode = CTX_data_mode_enum(C); + + const char *contexts_base[4] = {NULL}; + contexts_base[0] = CTX_data_mode_string(C); + + const char **contexts = &contexts_base[1]; + + switch (mode) { + case CTX_MODE_EDIT_MESH: + ARRAY_SET_ITEMS(contexts, ".mesh_edit"); + break; + case CTX_MODE_EDIT_CURVE: + ARRAY_SET_ITEMS(contexts, ".curve_edit"); + break; + case CTX_MODE_EDIT_SURFACE: + ARRAY_SET_ITEMS(contexts, ".curve_edit"); + break; + case CTX_MODE_EDIT_TEXT: + ARRAY_SET_ITEMS(contexts, ".text_edit"); + break; + case CTX_MODE_EDIT_ARMATURE: + ARRAY_SET_ITEMS(contexts, ".armature_edit"); + break; + case CTX_MODE_EDIT_METABALL: + ARRAY_SET_ITEMS(contexts, ".mball_edit"); + break; + case CTX_MODE_EDIT_LATTICE: + ARRAY_SET_ITEMS(contexts, ".lattice_edit"); + break; + case CTX_MODE_POSE: + ARRAY_SET_ITEMS(contexts, ".posemode"); + break; + case CTX_MODE_SCULPT: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".sculpt_mode"); + break; + case CTX_MODE_PAINT_WEIGHT: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".weightpaint"); + break; + case CTX_MODE_PAINT_VERTEX: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".vertexpaint"); + break; + case CTX_MODE_PAINT_TEXTURE: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".imagepaint"); + break; + case CTX_MODE_PARTICLE: + ARRAY_SET_ITEMS(contexts, ".paint_common", ".particlemode"); + break; + case CTX_MODE_OBJECT: + ARRAY_SET_ITEMS(contexts, ".objectmode"); + break; + case CTX_MODE_PAINT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_SCULPT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_WEIGHT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; + default: + break; + } + + switch (mode) { + case CTX_MODE_PAINT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_SCULPT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_WEIGHT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; + case CTX_MODE_EDIT_GPENCIL: + ARRAY_SET_ITEMS(contexts, ".greasepencil_edit"); + break; + default: + break; + } + + ListBase *paneltypes = &ar->type->paneltypes; + + /* Allow drawing 3D view toolbar from non 3D view space type. */ + if (category_override != NULL) { + SpaceType *st = BKE_spacetype_from_id(SPACE_VIEW3D); + ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_UI); + paneltypes = &art->paneltypes; + } + + const bool vertical = true; + ED_region_panels_layout_ex(C, ar, paneltypes, contexts_base, -1, vertical, category_override); +} + +static void view3d_buttons_region_layout(const bContext *C, ARegion *ar) +{ + ED_view3d_buttons_region_layout_ex(C, ar, NULL); } static void view3d_buttons_region_listener(wmWindow *UNUSED(win), @@ -1507,11 +1607,13 @@ void ED_spacetype_view3d(void) /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d buttons region"); art->regionid = RGN_TYPE_UI; - art->prefsizex = 180; /* XXX */ + art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = view3d_buttons_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_ui; art->init = view3d_buttons_region_init; - art->draw = view3d_buttons_region_draw; + art->layout = view3d_buttons_region_layout; + art->draw = ED_region_panels_draw; BLI_addhead(&st->regiontypes, art); view3d_buttons_register(art); @@ -1535,9 +1637,9 @@ void ED_spacetype_view3d(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = view3d_header_region_listener; + art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header; art->init = view3d_header_region_init; art->draw = view3d_header_region_draw; - art->message_subscribe = view3d_header_region_message_subscribe; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -1546,9 +1648,9 @@ void ED_spacetype_view3d(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = view3d_header_region_listener; + art->message_subscribe = view3d_header_region_message_subscribe; art->init = view3d_header_region_init; art->draw = view3d_header_region_draw; - art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header; BLI_addhead(&st->regiontypes, art); /* regions: hud */ diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 8c5f1c16438..2ce67bfbe4c 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -105,7 +105,8 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, ARegion *ar, float viewmat[4][4], float winmat[4][4], - const rcti *rect) + const rcti *rect, + bool offscreen) { RegionView3D *rv3d = ar->regiondata; @@ -138,7 +139,7 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, /* calculate GLSL view dependent values */ /* store window coordinates scaling/offset */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (!offscreen && rv3d->persp == RV3D_CAMOB && v3d->camera) { rctf cameraborder; ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); @@ -184,7 +185,22 @@ static void view3d_main_region_setup_view(Depsgraph *depsgraph, { RegionView3D *rv3d = ar->regiondata; - ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect, false); + + /* set for opengl */ + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); +} + +static void view3d_main_region_setup_offscreen(Depsgraph *depsgraph, + Scene *scene, + View3D *v3d, + ARegion *ar, + float viewmat[4][4], + float winmat[4][4]) +{ + RegionView3D *rv3d = ar->regiondata; + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, NULL, true); /* set for opengl */ GPU_matrix_projection_set(rv3d->winmat); @@ -1480,14 +1496,14 @@ static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph, const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ float viewmat[4][4]; Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } } @@ -1503,7 +1519,6 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, bool do_sky, bool UNUSED(is_persp), const char *viewname, - GPUFXSettings *UNUSED(fx_settings), const bool do_color_management, GPUOffScreen *ofs, GPUViewport *viewport) @@ -1546,7 +1561,7 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph, view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, ar, winmat, viewname); } else { - view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); + view3d_main_region_setup_offscreen(depsgraph, scene, v3d, ar, viewmat, winmat); } /* main drawing call */ @@ -1580,7 +1595,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, int sizex, int sizey, uint flag, - uint draw_flags, int alpha_mode, int samples, const char *viewname, @@ -1590,10 +1604,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, { RegionView3D *rv3d = ar->regiondata; const bool draw_sky = (alpha_mode == R_ADDSKY); - const bool use_full_sample = (draw_flags & V3D_OFSDRAW_USE_FULL_SAMPLE); /* view state */ - GPUFXSettings fx_settings = v3d->fx_settings; bool is_ortho = false; float winmat[4][4]; @@ -1613,7 +1625,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out); + ofs = GPU_offscreen_create(sizex, sizey, samples, true, false, err_out); if (ofs == NULL) { DRW_opengl_context_disable(); return NULL; @@ -1640,8 +1652,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); BKE_camera_params_compute_matrix(¶ms); - BKE_camera_to_gpu_dof(camera, &fx_settings); - is_ortho = params.is_ortho; copy_m4_m4(winmat, params.winmat); } @@ -1671,123 +1681,28 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, } } - if ((samples && use_full_sample) == 0) { - const bool do_color_management = (ibuf->rect_float == NULL); - /* Single-pass render, common case */ - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - do_color_management, - ofs, - NULL); - - if (ibuf->rect_float) { - GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); - } - else if (ibuf->rect) { - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); - } - } - else { - /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling. - * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ - static float jit_ofs[32][2]; - float winmat_jitter[4][4]; - float *rect_temp = (ibuf->rect_float) ? - ibuf->rect_float : - MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp"); - float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer"); - GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs); - - BLI_jitter_init(jit_ofs, samples); - - /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - false, - ofs, - viewport); - GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); - - /* skip the first sample */ - for (int j = 1; j < samples; j++) { - copy_m4_m4(winmat_jitter, winmat); - window_translate_m4(winmat_jitter, - rv3d->persmat, - (jit_ofs[j][0] * 2.0f) / sizex, - (jit_ofs[j][1] * 2.0f) / sizey); - - ED_view3d_draw_offscreen(depsgraph, - scene, - drawtype, - v3d, - ar, - sizex, - sizey, - NULL, - winmat_jitter, - draw_sky, - !is_ortho, - viewname, - &fx_settings, - false, - ofs, - viewport); - GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); - - uint i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] += rect_temp[i]; - } - } - - { - /* don't free data owned by 'ofs' */ - GPU_viewport_clear_from_offscreen(viewport); - GPU_viewport_free(viewport); - } - - if (ibuf->rect_float == NULL) { - MEM_freeN(rect_temp); - } - - if (ibuf->rect_float) { - float *rect_float = ibuf->rect_float; - uint i = sizex * sizey * 4; - while (i--) { - rect_float[i] = accum_buffer[i] / samples; - } - } - else { - uchar *rect_ub = (uchar *)ibuf->rect; - uint i = sizex * sizey * 4; - while (i--) { - rect_ub[i] = (uchar)(255.0f * accum_buffer[i] / samples); - } - } + const bool do_color_management = (ibuf->rect_float == NULL); + ED_view3d_draw_offscreen(depsgraph, + scene, + drawtype, + v3d, + ar, + sizex, + sizey, + NULL, + winmat, + draw_sky, + !is_ortho, + viewname, + do_color_management, + ofs, + NULL); - MEM_freeN(accum_buffer); + if (ibuf->rect_float) { + GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); + } + else if (ibuf->rect) { + GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect); } /* unbind */ @@ -1896,7 +1811,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, width, height, flag, - draw_flags, alpha_mode, samples, viewname, diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index b0cee18f8e3..755852a2e18 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -77,6 +77,7 @@ #include "ED_armature.h" #include "ED_keyframing.h" #include "ED_gpencil.h" +#include "ED_mesh.h" #include "ED_screen.h" #include "ED_space_api.h" #include "ED_screen_types.h" @@ -151,13 +152,11 @@ void ED_view3d_clipping_enable(void) /* *********************** backdraw for selection *************** */ -static void validate_object_select_id(struct Depsgraph *depsgraph, - Scene *scene, - ARegion *ar, - View3D *v3d, - Object *obact, - Object *obedit, - short select_mode) +/** + * \note Only use in object mode. + */ +static void validate_object_select_id( + struct Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d, Object *obact) { RegionView3D *rv3d = ar->regiondata; Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); @@ -177,9 +176,6 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) && !XRAY_ENABLED(v3d)) { /* do nothing */ } - else if ((obedit && (obedit->mode & OB_MODE_EDIT)) && !XRAY_FLAG_ENABLED(v3d)) { - /* do nothing */ - } else { v3d->flag &= ~V3D_INVALID_BACKBUF; return; @@ -189,34 +185,25 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, return; } -#if 0 - if (test) { - if (qtest()) { - addafterqueue(ar->win, BACKBUFDRAW, 1); - return; - } - } -#endif - -#if 0 /* v3d->zbuf deprecated */ - if (v3d->shading.type > OB_WIRE) { - v3d->zbuf = true; - } -#endif - - G.f |= G_FLAG_BACKBUFSEL; - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + uint dummy_vert_ofs, dummy_edge_ofs, dummy_face_ofs; DRW_framebuffer_select_id_setup(ar, true); - draw_object_select_id(depsgraph, scene_eval, v3d, rv3d, obact_eval, select_mode); + DRW_draw_select_id_object(scene_eval, + rv3d, + obact_eval, + scene->toolsettings->selectmode, + false, + 1, + &dummy_vert_ofs, + &dummy_edge_ofs, + &dummy_face_ofs); + DRW_framebuffer_select_id_release(ar); } /* TODO: Create a flag in `DRW_manager` because the drawing is no longer * made on the backbuffer in this case. */ v3d->flag &= ~V3D_INVALID_BACKBUF; - - G.f &= ~G_FLAG_BACKBUFSEL; } /* TODO: Creating, attaching texture, and destroying a framebuffer is quite slow. @@ -241,21 +228,15 @@ static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void GPU_framebuffer_free(tmp_fb); } -void ED_view3d_select_id_validate_with_select_mode(ViewContext *vc, short select_mode) +void ED_view3d_select_id_validate(ViewContext *vc) { /* TODO: Create a flag in `DRW_manager` because the drawing is no longer * made on the backbuffer in this case. */ if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - validate_object_select_id( - vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode); + validate_object_select_id(vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact); } } -void ED_view3d_select_id_validate(ViewContext *vc) -{ - ED_view3d_select_id_validate_with_select_mode(vc, -1); -} - void ED_view3d_backbuf_depth_validate(ViewContext *vc) { if (vc->v3d->flag & V3D_INVALID_BACKBUF) { @@ -271,10 +252,8 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) } } -uint *ED_view3d_select_id_read_rect(ViewContext *vc, const rcti *clip, uint *r_buf_len) +uint *ED_view3d_select_id_read_rect(const rcti *clip, uint *r_buf_len) { - ED_view3d_select_id_validate(vc); - uint width = BLI_rcti_size_x(clip); uint height = BLI_rcti_size_y(clip); uint buf_len = width * height; @@ -298,25 +277,8 @@ int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); } -/* samples a single pixel (copied from vpaint) */ -uint ED_view3d_select_id_sample(ViewContext *vc, int x, int y) -{ - if (x >= vc->ar->winx || y >= vc->ar->winy) { - return 0; - } - - uint buf_len; - uint *buf = ED_view3d_select_id_read(vc, x, y, x, y, &buf_len); - BLI_assert(0 != buf_len); - uint ret = buf[0]; - MEM_freeN(buf); - - return ret; -} - /* reads full rect, converts indices */ -uint *ED_view3d_select_id_read( - ViewContext *vc, int xmin, int ymin, int xmax, int ymax, uint *r_buf_len) +uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len) { if (UNLIKELY((xmin > xmax) || (ymin > ymax))) { return NULL; @@ -330,7 +292,7 @@ uint *ED_view3d_select_id_read( }; uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, &rect, &buf_len); + uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len); if (r_buf_len) { *r_buf_len = buf_len; @@ -339,85 +301,6 @@ uint *ED_view3d_select_id_read( return buf; } -/* smart function to sample a rect spiralling outside, nice for backbuf selection */ -uint ED_view3d_select_id_read_nearest(struct ViewContext *UNUSED(vc), - const int mval[2], - const uint id_min, - const uint id_max, - uint *r_dist) -{ - /* Create region around mouse cursor. This must be square and have an odd - * width, the spiraling algorithm does not work with arbitrary rectangles. */ - rcti rect; - BLI_rcti_init_pt_radius(&rect, mval, *r_dist); - rect.xmax += 1; - rect.ymax += 1; - - int width = BLI_rcti_size_x(&rect); - int height = width; - BLI_assert(width == height); - - /* Read from selection framebuffer. */ - uint *buf = MEM_mallocN(width * height * sizeof(*buf), __func__); - DRW_framebuffer_select_id_read(&rect, buf); - - /* Spiral, starting from center of buffer. */ - int spiral_offset = height * (int)(width / 2) + (height / 2); - int spiral_direction = 0; - - uint index = 0; - - for (int nr = 1; nr <= height; nr++) { - for (int a = 0; a < 2; a++) { - for (int b = 0; b < nr; b++) { - /* Find hit within the specified range. */ - uint hit_id = buf[spiral_offset]; - - if (hit_id && hit_id >= id_min && hit_id < id_max) { - /* Get x/y from spiral offset. */ - int hit_x = spiral_offset % width; - int hit_y = spiral_offset / width; - - int center_x = width / 2; - int center_y = height / 2; - - /* Manhatten distance in keeping with other screen-based selection. */ - *r_dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); - - /* Indices start at 1 here. */ - index = (hit_id - id_min) + 1; - goto exit; - } - - /* Next spiral step. */ - if (spiral_direction == 0) { - spiral_offset += 1; /* right */ - } - else if (spiral_direction == 1) { - spiral_offset -= width; /* down */ - } - else if (spiral_direction == 2) { - spiral_offset -= 1; /* left */ - } - else { - spiral_offset += width; /* up */ - } - - /* Stop if we are outside the buffer. */ - if (spiral_offset < 0 || spiral_offset >= width * height) { - goto exit; - } - } - - spiral_direction = (spiral_direction + 1) % 4; - } - } - -exit: - MEM_freeN(buf); - return index; -} - /* ************************************************************* */ static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c index 0b8c3b8cd28..5fe62a74d4b 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -154,7 +154,7 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) /* need to set property here for undo. TODO would prefer to do this in _init */ WM_gizmo_target_property_def_rna( - cagzgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1); + cagzgroup->dop_dist, "offset", &camera_ptr, "dof.focus_distance", -1); } else { WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, true); @@ -262,7 +262,7 @@ static void WIDGETGROUP_camera_message_subscribe(const bContext *C, }; { - extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_CameraDOFSettings_focus_distance; extern PropertyRNA rna_Camera_display_size; extern PropertyRNA rna_Camera_ortho_scale; extern PropertyRNA rna_Camera_sensor_fit; @@ -273,7 +273,7 @@ static void WIDGETGROUP_camera_message_subscribe(const bContext *C, extern PropertyRNA rna_Camera_type; extern PropertyRNA rna_Camera_lens; const PropertyRNA *props[] = { - &rna_Camera_dof_distance, + &rna_CameraDOFSettings_focus_distance, &rna_Camera_display_size, &rna_Camera_ortho_scale, &rna_Camera_sensor_fit, diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 6f35c0aa748..9cbf179ab49 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -304,15 +304,14 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const em_setup_viewcontext(C, &vc); copy_v2_v2_int(vc.mval, mval); - for (uint base_index = 0; base_index < gz_ring->bases_len; base_index++) { - Object *ob_iter = gz_ring->bases[base_index]->object; - ED_view3d_viewcontext_init_object(&vc, ob_iter); - BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, &best.dist, NULL, false, false, NULL); - if (eed_test) { - best.ob = ob_iter; - best.eed = eed_test; - best.base_index = base_index; - } + uint base_index; + BMEdge *eed_test = EDBM_edge_find_nearest_ex( + &vc, &best.dist, NULL, false, false, NULL, gz_ring->bases, gz_ring->bases_len, &base_index); + + if (eed_test) { + best.ob = gz_ring->bases[base_index]->object; + best.eed = eed_test; + best.base_index = base_index; } BMesh *bm = NULL; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 9075909a6fe..e499672acc1 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -127,13 +127,6 @@ void VIEW3D_OT_fly(struct wmOperatorType *ot); void VIEW3D_OT_walk(struct wmOperatorType *ot); /* drawobject.c */ -void draw_object_select_id(struct Depsgraph *depsgraph, - Scene *scene, - View3D *v3d, - RegionView3D *rv3d, - struct Object *ob, - short select_mode); - int view3d_effective_drawtype(const struct View3D *v3d); /* view3d_draw.c */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2ce23486476..b3b4910c525 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_lasso_2d.h" #include "BLI_rect.h" @@ -57,6 +58,7 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_armature.h" #include "BKE_context.h" @@ -87,6 +89,7 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_buffer_utils.h" #include "ED_select_utils.h" #include "ED_sculpt.h" #include "ED_mball.h" @@ -134,9 +137,6 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) if (vc->obedit) { BLI_assert(BKE_object_is_in_editmode(obact)); vc->obedit = obact; - /* previous selections are now invalid. */ - vc->v3d->flag |= V3D_INVALID_BACKBUF; - if (vc->em) { vc->em = BKE_editmesh_from_object(vc->obedit); } @@ -181,20 +181,96 @@ static bool object_deselect_all_except(ViewLayer *view_layer, Base *b) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Internal Edit-Mesh Select Buffer Wrapper + * + * Avoid duplicate code when using edit-mode selection, + * actual logic is handled outside of this function. + * + * \note Currently this #EDBMSelectID_Context which is mesh specific + * however the logic could also be used for non-meshes too. + * + * \{ */ + +struct EditSelectBuf_Cache { + Base **bases; + uint bases_len; + struct EDBMSelectID_Context *sel_id_ctx; + BLI_bitmap *select_bitmap; +}; + +static void editselect_buf_cache_init(struct EditSelectBuf_Cache *esel, ViewContext *vc) +{ + if (vc->obedit) { + esel->bases = BKE_view_layer_array_from_bases_in_edit_mode( + vc->view_layer, vc->v3d, &esel->bases_len); + } + else { + /* Use for paint modes, currently only a single object at a time. */ + if (vc->obact) { + esel->bases = MEM_mallocN(sizeof(esel->bases), __func__); + esel->bases[0] = BKE_view_layer_base_find(vc->view_layer, vc->obact); + esel->bases_len = 1; + } + else { + esel->bases = NULL; + esel->bases_len = 0; + } + } + esel->sel_id_ctx = EDBM_select_id_context_create( + vc, esel->bases, esel->bases_len, vc->scene->toolsettings->selectmode); + for (int i = 0; i < esel->bases_len; i++) { + esel->bases[i]->object->runtime.select_id = i; + } +} + +static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel) +{ + if (esel->sel_id_ctx) { + EDBM_select_id_context_destroy(esel->sel_id_ctx); + } + MEM_SAFE_FREE(esel->select_bitmap); + MEM_SAFE_FREE(esel->bases); +} + +static void editselect_buf_cache_free_voidp(void *esel_voidp) +{ + editselect_buf_cache_free(esel_voidp); + MEM_freeN(esel_voidp); +} + +static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *wm_userdata, + ViewContext *vc) +{ + struct EditSelectBuf_Cache *esel = MEM_callocN(sizeof(*esel), __func__); + wm_userdata->data = esel; + wm_userdata->free_fn = editselect_buf_cache_free_voidp; + wm_userdata->use_free = true; + editselect_buf_cache_init(esel, vc); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Internal Edit-Mesh Utilities * \{ */ -static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMVert *eve; BMIter iter; - uint index = bm_wireoffs; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_VERT); + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_vert_select_set(em->bm, eve, sel_op_result); @@ -206,17 +282,23 @@ static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp return changed; } -static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMEdge *eed; BMIter iter; - uint index = bm_solidoffs; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_EDGE); + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(em->bm, eed, sel_op_result); @@ -228,17 +310,23 @@ static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp return changed; } -static bool edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel, + Object *ob, + BMEditMesh *em, + const eSelectOp sel_op) { BMFace *efa; BMIter iter; - uint index = 1; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + uint index = EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, ob->runtime.select_id, BM_FACE); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_face_select_set(em->bm, efa, sel_op_result); @@ -251,17 +339,21 @@ static bool edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp } /* object mode, edbm_ prefix is confusing here, rename? */ -static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, + struct EditSelectBuf_Cache *esel, + const eSelectOp sel_op) { MVert *mv = me->mvert; uint index; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + if (mv) { - for (index = 1; index <= me->totvert; index++, mv++) { + for (index = 0; index < me->totvert; index++, mv++) { if (!(mv->flag & ME_HIDE)) { const bool is_select = mv->flag & SELECT; - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); @@ -274,17 +366,21 @@ static bool edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp } /* object mode, edbm_ prefix is confusing here, rename? */ -static bool edbm_backbuf_check_and_select_tfaces(Mesh *me, const eSelectOp sel_op) +static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, + struct EditSelectBuf_Cache *esel, + const eSelectOp sel_op) { MPoly *mpoly = me->mpoly; uint index; bool changed = false; + const BLI_bitmap *select_bitmap = esel->select_bitmap; + if (mpoly) { - for (index = 1; index <= me->totpoly; index++, mpoly++) { + for (index = 0; index < me->totpoly; index++, mpoly++) { if (!(mpoly->flag & ME_HIDE)) { const bool is_select = mpoly->flag & ME_FACE_SEL; - const bool is_inside = EDBM_backbuf_check(index); + const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); @@ -623,14 +719,26 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, data->is_changed = true; } } -static void do_lasso_select_mesh__doSelectEdge_pass0( - void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) -{ - LassoSelectUserData *data = userData; +struct LassoSelectUserData_ForMeshEdge { + LassoSelectUserData *data; + struct EditSelectBuf_Cache *esel; + uint backbuf_offset; +}; +static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index) +{ + struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = - (EDBM_backbuf_check(bm_solidoffs + index) && - edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && + (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -640,15 +748,24 @@ static void do_lasso_select_mesh__doSelectEdge_pass0( data->is_changed = true; } } -static void do_lasso_select_mesh__doSelectEdge_pass1( - void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, + BMEdge *eed, + const float screen_co_a[2], + const float screen_co_b[2], + int index) { - LassoSelectUserData *data = userData; + struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data; + LassoSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = - (EDBM_backbuf_check(bm_solidoffs + index) && - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); + const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords, + data->moves, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -674,6 +791,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, } static bool do_lasso_select_mesh(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -681,7 +799,6 @@ static bool do_lasso_select_mesh(ViewContext *vc, LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; rcti rect; - int bbsel; /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); @@ -701,12 +818,22 @@ static bool do_lasso_select_mesh(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); GPU_matrix_set(vc->rv3d->viewmat); - bbsel = EDBM_backbuf_border_mask_init( - vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + } if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenVert( @@ -714,18 +841,26 @@ static bool do_lasso_select_mesh(ViewContext *vc, } } if (ts->selectmode & SCE_SELECT_EDGE) { - /* Does both bbsel and non-bbsel versions (need screen cos for both) */ + /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ + struct LassoSelectUserData_ForMeshEdge data_for_edge = { + .data = &data, + .esel = use_zbuf ? esel : NULL, + .backbuf_offset = use_zbuf ? + EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) : + 0, + }; mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { mesh_foreachScreenEdge( - vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenFace( @@ -733,8 +868,6 @@ static bool do_lasso_select_mesh(ViewContext *vc, } } - EDBM_backbuf_free(); - if (data.is_changed) { EDBM_selectmode_flush(vc->em); } @@ -975,6 +1108,7 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, } } static bool do_lasso_select_paintvert(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -996,14 +1130,20 @@ static bool do_lasso_select_paintvert(ViewContext *vc, BLI_lasso_boundbox(&rect, mcords, moves); + struct EditSelectBuf_Cache *esel = wm_userdata->data; if (use_zbuf) { - bm_vertoffs = me->totvert + 1; /* max index array */ - - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - - changed |= edbm_backbuf_check_and_select_verts_obmode(me, sel_op); + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + } - EDBM_backbuf_free(); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); + } } else { LassoSelectUserData data; @@ -1025,9 +1165,11 @@ static bool do_lasso_select_paintvert(ViewContext *vc, paintvert_flush_flags(ob); paintvert_tag_select_update(vc->C, ob); } + return changed; } static bool do_lasso_select_paintface(ViewContext *vc, + wmGenericUserData *wm_userdata, const int mcords[][2], short moves, const eSelectOp sel_op) @@ -1040,19 +1182,25 @@ static bool do_lasso_select_paintface(ViewContext *vc, return false; } - bm_vertoffs = me->totpoly + 1; /* max index array */ - - BLI_lasso_boundbox(&rect, mcords, moves); - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { /* flush selection at the end */ changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - changed |= edbm_backbuf_check_and_select_tfaces(me, sel_op); - EDBM_backbuf_free(); + BLI_lasso_boundbox(&rect, mcords, moves); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (esel == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect); + } + + if (esel->select_bitmap) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + } if (changed) { paintface_flush_flags(vc->C, ob, SELECT); @@ -1100,12 +1248,15 @@ static bool view3d_lasso_select( Object *ob = CTX_data_active_object(C); bool changed_multi = false; + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = &wm_userdata_buf; + if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - changed_multi |= do_lasso_select_paintface(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - changed_multi |= do_lasso_select_paintvert(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { @@ -1122,14 +1273,13 @@ static bool view3d_lasso_select( } } else { /* Edit Mode */ - FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) { ED_view3d_viewcontext_init_object(vc, ob_iter); bool changed = false; switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, mcords, moves, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op); break; case OB_CURVE: case OB_SURF: @@ -1157,6 +1307,9 @@ static bool view3d_lasso_select( } FOREACH_OBJECT_IN_MODE_END; } + + WM_generic_user_data_free(wm_userdata); + return changed_multi; } @@ -1170,6 +1323,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) if (mcords) { view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); @@ -1337,7 +1491,7 @@ static Base *object_mouse_select_menu( if (buffer) { for (int a = 0; a < hits; a++) { /* index was converted */ - if (base->object->select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { ok = true; break; } @@ -1609,7 +1763,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, else { /* only exclude active object when it is selected... */ if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) { - notcol = BASACT(view_layer)->object->select_id; + notcol = BASACT(view_layer)->object->runtime.select_id; } for (a = 0; a < hits; a++) { @@ -1623,7 +1777,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, base = FIRSTBASE(view_layer); while (base) { if (BASE_SELECTABLE(v3d, base)) { - if (base->object->select_id == selcol) { + if (base->object->runtime.select_id == selcol) { break; } } @@ -1654,13 +1808,13 @@ static Base *mouse_select_eval_buffer(ViewContext *vc, if (has_bones) { /* skip non-bone objects */ if ((buffer[4 * a + 3] & 0xFFFF0000)) { - if (base->object->select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { basact = base; } } } else { - if (base->object->select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { + if (base->object->runtime.select_id == (buffer[(4 * a) + 3] & 0xFFFF)) { basact = base; } } @@ -1693,6 +1847,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); ED_view3d_viewcontext_init(C, &vc); @@ -1878,7 +2033,7 @@ static bool ed_object_select_pick(bContext *C, /* if there's bundles in buffer select bundles first, * so non-camera elements should be ignored in buffer */ - if (basact->object->select_id != (hitresult & 0xFFFF)) { + if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) { continue; } @@ -2129,6 +2284,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) RNA_int_get_array(op->ptr, "location", location); view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); if (object) { obedit = NULL; @@ -2335,9 +2491,13 @@ static void do_paintvert_box_select__doSelectVert(void *userData, data->is_changed = true; } } -static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op) +static bool do_paintvert_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + const eSelectOp sel_op) { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); + Mesh *me; me = vc->obact->data; @@ -2354,48 +2514,16 @@ static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSe /* pass */ } else if (use_zbuf) { - MVert *mvert; - unsigned int *rt; - int a, index; - char *selar; - - selar = MEM_callocN(me->totvert + 1, "selar"); - - uint buf_len; - uint *buf = ED_view3d_select_id_read_rect(vc, rect, &buf_len); - - rt = buf; - - a = buf_len; - while (a--) { - if (*rt) { - index = *rt; - if (index <= me->totvert) { - selar[index] = 1; - } - } - rt++; + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); } - - mvert = me->mvert; - for (a = 1; a <= me->totvert; a++, mvert++) { - if ((mvert->flag & ME_HIDE) == 0) { - const bool is_select = mvert->flag & SELECT; - const bool is_inside = (selar[a] != 0); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - SET_FLAG_FROM_TEST(mvert->flag, sel_op_result, SELECT); - changed = true; - } - } + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); } - - MEM_freeN(buf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif } else { BoxSelectUserData data; @@ -2419,6 +2547,46 @@ static bool do_paintvert_box_select(ViewContext *vc, const rcti *rect, const eSe return changed; } +static bool do_paintface_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + int sel_op) +{ + Object *ob = vc->obact; + Mesh *me; + + me = BKE_mesh_from_object(ob); + if ((me == NULL) || (me->totpoly == 0)) { + return false; + } + + bool changed = false; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + changed |= paintface_deselect_all_visible(vc->C, vc->obact, SEL_DESELECT, false); + } + + if (BLI_rcti_is_empty(rect)) { + /* pass */ + } + else { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); + } + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + } + } + + if (changed) { + paintface_flush_flags(vc->C, vc->obact, SELECT); + } + return changed; +} + static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, @@ -2519,12 +2687,22 @@ static void do_mesh_box_select__doSelectVert(void *userData, data->is_changed = true; } } +struct BoxSelectUserData_ForMeshEdge { + BoxSelectUserData *data; + struct EditSelectBuf_Cache *esel; + uint backbuf_offset; +}; static void do_mesh_box_select__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - BoxSelectUserData *data = userData; + struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) && + const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { @@ -2536,10 +2714,14 @@ static void do_mesh_box_select__doSelectEdge_pass0( static void do_mesh_box_select__doSelectEdge_pass1( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - BoxSelectUserData *data = userData; + struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData; + BoxSelectUserData *data = data_for_edge->data; + const bool is_visible = (data_for_edge->esel ? + BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, + data_for_edge->backbuf_offset + index) : + true); const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) && - edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -2560,11 +2742,13 @@ static void do_mesh_box_select__doSelectFace(void *userData, data->is_changed = true; } } -static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) +static bool do_mesh_box_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + const rcti *rect, + const eSelectOp sel_op) { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; - int bbsel; view3d_userdata_boxselect_init(&data, vc, rect, sel_op); @@ -2579,11 +2763,22 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); GPU_matrix_set(vc->rv3d->viewmat); - bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + struct EditSelectBuf_Cache *esel = wm_userdata->data; + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect); + } + } if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenVert( @@ -2591,18 +2786,26 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ } } if (ts->selectmode & SCE_SELECT_EDGE) { - /* Does both bbsel and non-bbsel versions (need screen cos for both) */ + /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ + struct BoxSelectUserData_ForMeshEdge cb_data = { + .data = &data, + .esel = use_zbuf ? esel : NULL, + .backbuf_offset = use_zbuf ? + EDBM_select_id_context_offset_for_object_elem( + esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) : + 0, + }; mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { mesh_foreachScreenEdge( - vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); + vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op); + if (use_zbuf) { + data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op); } else { mesh_foreachScreenFace( @@ -2610,8 +2813,6 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_ } } - EDBM_backbuf_free(); - if (data.is_changed) { EDBM_selectmode_flush(vc->em); } @@ -2652,7 +2853,7 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO } const uint hit_object = hitresult & 0xFFFF; - if (vc->obedit->select_id != hit_object) { + if (vc->obedit->runtime.select_id != hit_object) { continue; } @@ -2803,7 +3004,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { - if ((base->object->select_id & 0x0000FFFF) != 0) { + if ((base->object->runtime.select_id & 0x0000FFFF) != 0) { BLI_array_append(bases, base); } } @@ -2893,7 +3094,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e /* Select the next bone if we're not switching bases. */ if (col + 4 != col_end) { - if ((base->object->select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { + if ((base->object->runtime.select_id & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { break; } if (base->object->pose != NULL) { @@ -2929,7 +3130,11 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) rcti rect; bool changed_multi = false; + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = &wm_userdata_buf; + view3d_operator_needs_opengl(C); + BKE_object_update_select_id(CTX_data_main(C)); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); @@ -2938,7 +3143,6 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) WM_operator_properties_border_to_rcti(op, &rect); if (vc.obedit) { - FOREACH_OBJECT_IN_MODE_BEGIN ( vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); @@ -2947,7 +3151,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) switch (vc.obedit->type) { case OB_MESH: vc.em = BKE_editmesh_from_object(vc.obedit); - changed = do_mesh_box_select(&vc, &rect, sel_op); + changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op); if (changed) { DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); @@ -2997,10 +3201,10 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) C, &vc, &rect, sel_op == SEL_OP_ADD ? true : false); } else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { - changed_multi = do_paintface_box_select(&vc, &rect, sel_op); + changed_multi = do_paintface_box_select(&vc, wm_userdata, &rect, sel_op); } else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { - changed_multi = do_paintvert_box_select(&vc, &rect, sel_op); + changed_multi = do_paintvert_box_select(&vc, wm_userdata, &rect, sel_op); } else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { changed_multi = PE_box_select(C, &rect, sel_op); @@ -3013,6 +3217,8 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) } } + WM_generic_user_data_free(wm_userdata); + if (changed_multi) { return OPERATOR_FINISHED; } @@ -3118,10 +3324,13 @@ static void mesh_circle_doSelectFace(void *userData, } } -static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval[2], float rad) +static bool mesh_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, + eSelectOp sel_op, + const int mval[2], + float rad) { ToolSettings *ts = vc->scene->toolsettings; - int bbsel; CircleSelectUserData data; vc->em = BKE_editmesh_from_object(vc->obedit); @@ -3134,14 +3343,30 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } const bool select = (sel_op != SEL_OP_SUB); - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + + if (use_zbuf) { + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } + } + struct EditSelectBuf_Cache *esel = wm_userdata->data; + + if (use_zbuf) { + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + } + if (ts->selectmode & SCE_SELECT_VERTEX) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -3149,8 +3374,11 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } if (ts->selectmode & SCE_SELECT_EDGE) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_edges( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); @@ -3158,17 +3386,25 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } if (ts->selectmode & SCE_SELECT_FACE) { - if (bbsel) { - changed |= edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces( + esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + } } else { mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } } - changed |= data.is_changed; + if (use_zbuf) { + if (esel->select_bitmap != NULL) { + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; + } + } - EDBM_backbuf_free(); + changed |= data.is_changed; if (changed) { EDBM_selectmode_flush(vc->em); @@ -3177,6 +3413,7 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval } static bool paint_facesel_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) @@ -3184,7 +3421,6 @@ static bool paint_facesel_circle_select(ViewContext *vc, BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); Object *ob = vc->obact; Mesh *me = ob->data; - bool bbsel; bool changed = false; if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -3192,13 +3428,21 @@ static bool paint_facesel_circle_select(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - bm_vertoffs = me->totpoly + 1; /* max index array */ + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); - if (bbsel) { - changed |= edbm_backbuf_check_and_select_tfaces(me, sel_op); - EDBM_backbuf_free(); + { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces_obmode(me, esel, sel_op); + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; + } } + if (changed) { paintface_flush_flags(vc->C, ob, SELECT); } @@ -3218,6 +3462,7 @@ static void paint_vertsel_circle_select_doSelectVert(void *userData, } } static bool paint_vertsel_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) @@ -3226,7 +3471,6 @@ static bool paint_vertsel_circle_select(ViewContext *vc, const bool use_zbuf = !XRAY_ENABLED(vc->v3d); Object *ob = vc->obact; Mesh *me = ob->data; - bool bbsel; /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ bool changed = false; @@ -3238,12 +3482,19 @@ static bool paint_vertsel_circle_select(ViewContext *vc, const bool select = (sel_op != SEL_OP_SUB); if (use_zbuf) { - bm_vertoffs = me->totvert + 1; /* max index array */ + if (wm_userdata->data == NULL) { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc); + } + } - bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); - if (bbsel) { - changed |= edbm_backbuf_check_and_select_verts_obmode(me, sel_op); - EDBM_backbuf_free(); + if (use_zbuf) { + struct EditSelectBuf_Cache *esel = wm_userdata->data; + const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx); + esel->select_bitmap = ED_select_buffer_bitmap_from_circle(buffer_len, mval, (int)(rad + 1.0f)); + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_verts_obmode(me, esel, sel_op); + MEM_freeN(esel->select_bitmap); + esel->select_bitmap = NULL; } } else { @@ -3591,27 +3842,40 @@ static bool mball_circle_select(ViewContext *vc, /** Callbacks for circle selection in Editmode */ static bool obedit_circle_select(ViewContext *vc, + wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], float rad) { + bool changed = false; BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); switch (vc->obedit->type) { case OB_MESH: - return mesh_circle_select(vc, sel_op, mval, rad); + changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad); + break; case OB_CURVE: case OB_SURF: - return nurbscurve_circle_select(vc, sel_op, mval, rad); + changed = nurbscurve_circle_select(vc, sel_op, mval, rad); + break; case OB_LATTICE: - return lattice_circle_select(vc, sel_op, mval, rad); + changed = lattice_circle_select(vc, sel_op, mval, rad); + break; case OB_ARMATURE: - return armature_circle_select(vc, sel_op, mval, rad); + changed = armature_circle_select(vc, sel_op, mval, rad); + break; case OB_MBALL: - return mball_circle_select(vc, sel_op, mval, rad); + changed = mball_circle_select(vc, sel_op, mval, rad); + break; default: BLI_assert(0); - return false; + break; } + + if (changed) { + DEG_id_tag_update(vc->obact->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, vc->obact->data); + } + return changed; } static bool object_circle_select(ViewContext *vc, @@ -3660,8 +3924,13 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) const int radius = RNA_int_get(op->ptr, "radius"); const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")}; + /* Allow each selection type to allocate their own data thats used between executions. */ + wmGesture *gesture = op->customdata; /* NULL when non-modal. */ + wmGenericUserData wm_userdata_buf = {0}; + wmGenericUserData *wm_userdata = gesture ? &gesture->user_data : &wm_userdata_buf; + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), - WM_gesture_is_modal_first(op->customdata)); + WM_gesture_is_modal_first(gesture)); ED_view3d_viewcontext_init(C, &vc); @@ -3670,6 +3939,9 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & OB_MODE_POSE))) { view3d_operator_needs_opengl(C); + if (obedit == NULL) { + BKE_object_update_select_id(CTX_data_main(C)); + } FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) { ED_view3d_viewcontext_init_object(&vc, ob_iter); @@ -3678,16 +3950,13 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) obedit = vc.obedit; if (obedit) { - if (obedit_circle_select(&vc, sel_op, mval, (float)radius)) { - DEG_id_tag_update(obact->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); - } + obedit_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (BKE_paint_select_face_test(obact)) { - paint_facesel_circle_select(&vc, sel_op, mval, (float)radius); + paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (BKE_paint_select_vert_test(obact)) { - paint_vertsel_circle_select(&vc, sel_op, mval, (float)radius); + paint_vertsel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); } else if (obact->mode & OB_MODE_POSE) { pose_circle_select(&vc, sel_op, mval, (float)radius); @@ -3714,6 +3983,11 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) } } + /* Otherwise this is freed by the gesture. */ + if (wm_userdata == &wm_userdata_buf) { + WM_generic_user_data_free(wm_userdata); + } + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 91313657f59..bb8c1a40a05 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -86,21 +86,6 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float UI_GetThemeColor3fv(TH_BACK, r_color); } -void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3]) -{ - const View3DCursor *cursor = &scene->cursor; - BKE_scene_cursor_rot_to_mat3(cursor, mat); -} - -void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4]) -{ - const View3DCursor *cursor = &scene->cursor; - float mat3[3][3]; - BKE_scene_cursor_rot_to_mat3(cursor, mat3); - copy_m4_m3(mat, mat3); - copy_v3_v3(mat[3], cursor->location); -} - Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) { /* establish the camera object, diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 2454358b687..5865efa0ffa 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -428,7 +428,7 @@ void ED_view3d_smooth_view_force_finish(bContext *C, View3D *v3d, ARegion *ar) * can use them without redrawing first */ Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); - ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL, false); } } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 81405b55ac2..c3acd604ee1 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4835,6 +4835,7 @@ static void initNormalRotation(TransInfo *t) BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMesh *bm = em->bm; + BKE_editmesh_ensure_autosmooth(em); BKE_editmesh_lnorspace_update(em); storeCustomLNorValue(tc, bm); @@ -4917,8 +4918,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3]) } else if (t->spacetype == SPACE_NODE) { r_snap[0] = 0.0f; - r_snap[1] = ED_node_grid_size(); - r_snap[2] = ED_node_grid_size(); + r_snap[1] = r_snap[2] = ED_node_grid_size(); } else if (t->spacetype == SPACE_GRAPH) { r_snap[0] = 0.0f; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 50fc1a276b9..b0f720bfdf7 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -383,6 +383,30 @@ typedef struct BoneInitData { float zwidth; } BoneInitData; +typedef struct PoseInitData_Mirror { + /** Points to the bone which this info is initialized & restored to. + * A NULL value is used to terminate the array. */ + struct bPoseChannel *pchan; + struct { + float loc[3]; + float size[3]; + union { + float eul[3]; + float quat[4]; + float axis_angle[4]; + }; + float curve_in_x; + float curve_out_x; + float roll1; + float roll2; + } orig; + /** + * An extra offset to apply after mirroring. + * Use with #POSE_MIRROR_RELATIVE. + */ + float offset_mtx[4][4]; +} PoseInitData_Mirror; + typedef struct TransData { /** Distance needed to affect element (for Proportionnal Editing). */ float dist; @@ -501,7 +525,7 @@ typedef struct TransDataContainer { struct Object *obedit; /** - * Use when #T_LOCAL_MATRIX is set. + * Store matrix, this avoids having to have duplicate check all over * Typically: 'obedit->obmat' or 'poseobj->obmat', but may be used elsewhere too. */ bool use_local_mat; @@ -715,10 +739,8 @@ enum { T_CURSOR = 1 << 5, /** Transform points, having no rotation/scale. */ T_POINTS = 1 << 6, - /** - * Apply matrix #TransDataContainer.matrix, this avoids having to have duplicate check all over - * that happen to apply to specific modes (edit & pose for eg). */ - T_LOCAL_MATRIX = 1 << 7, + + /* empty slot - (1 << 7) */ /** restrictions flags */ T_NO_CONSTRAINT = 1 << 8, @@ -892,6 +914,7 @@ void flushTransSeq(TransInfo *t); void flushTransTracking(TransInfo *t); void flushTransMasking(TransInfo *t); void flushTransPaintCurve(TransInfo *t); +void restoreMirrorPoseBones(TransDataContainer *tc); void restoreBones(TransDataContainer *tc); /*********************** transform_gizmo.c ********** */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 6c1da5ae825..4037fab2b68 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -198,7 +198,10 @@ void sort_trans_data_dist(TransInfo *t) } } -static void sort_trans_data_container(TransDataContainer *tc) +/** + * Make #TD_SELECTED first in the array. + */ +static void sort_trans_data_selected_first_container(TransDataContainer *tc) { TransData *sel, *unsel; TransData temp; @@ -225,10 +228,10 @@ static void sort_trans_data_container(TransDataContainer *tc) unsel++; } } -static void sort_trans_data(TransInfo *t) +static void sort_trans_data_selected_first(TransInfo *t) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { - sort_trans_data_container(tc); + sort_trans_data_selected_first_container(tc); } } @@ -1201,6 +1204,74 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) return (tot_ik) ? 1 : 0; } +static void pose_mirror_info_init(PoseInitData_Mirror *pid, + bPoseChannel *pchan, + bPoseChannel *pchan_orig, + bool is_mirror_relative) +{ + pid->pchan = pchan; + copy_v3_v3(pid->orig.loc, pchan->loc); + copy_v3_v3(pid->orig.size, pchan->size); + pid->orig.curve_in_x = pchan->curve_in_x; + pid->orig.curve_out_x = pchan->curve_out_x; + pid->orig.roll1 = pchan->roll1; + pid->orig.roll2 = pchan->roll2; + + if (pchan->rotmode > 0) { + copy_v3_v3(pid->orig.eul, pchan->eul); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + copy_v3_v3(pid->orig.axis_angle, pchan->rotAxis); + pid->orig.axis_angle[3] = pchan->rotAngle; + } + else { + copy_qt_qt(pid->orig.quat, pchan->quat); + } + + if (is_mirror_relative) { + float pchan_mtx[4][4]; + float pchan_mtx_mirror[4][4]; + + float flip_mtx[4][4]; + unit_m4(flip_mtx); + flip_mtx[0][0] = -1; + + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_mirror); + BKE_pchan_to_mat4(pchan, pchan_mtx); + + mul_m4_m4m4(pchan_mtx_mirror, pchan_mtx_mirror, flip_mtx); + mul_m4_m4m4(pchan_mtx_mirror, flip_mtx, pchan_mtx_mirror); + + invert_m4(pchan_mtx_mirror); + mul_m4_m4m4(pid->offset_mtx, pchan_mtx, pchan_mtx_mirror); + } + else { + unit_m4(pid->offset_mtx); + } +} + +static void pose_mirror_info_restore(const PoseInitData_Mirror *pid) +{ + bPoseChannel *pchan = pid->pchan; + copy_v3_v3(pchan->loc, pid->orig.loc); + copy_v3_v3(pchan->size, pid->orig.size); + pchan->curve_in_x = pid->orig.curve_in_x; + pchan->curve_out_x = pid->orig.curve_out_x; + pchan->roll1 = pid->orig.roll1; + pchan->roll2 = pid->orig.roll2; + + if (pchan->rotmode > 0) { + copy_v3_v3(pchan->eul, pid->orig.eul); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + copy_v3_v3(pchan->rotAxis, pid->orig.axis_angle); + pchan->rotAngle = pid->orig.axis_angle[3]; + } + else { + copy_qt_qt(pchan->quat, pid->orig.quat); + } +} + /** * When objects array is NULL, use 't->data_container' as is. */ @@ -1215,16 +1286,19 @@ static void createTransPose(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; + bPose *pose = ob->pose; bArmature *arm; short ik_on = 0; /* check validity of state */ arm = BKE_armature_from_object(tc->poseobj); - if ((arm == NULL) || (ob->pose == NULL)) { + if ((arm == NULL) || (pose == NULL)) { continue; } + const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); + /* set flags and count total */ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); if (tc->data_len == 0) { @@ -1240,13 +1314,32 @@ static void createTransPose(TransInfo *t) } /* do we need to add temporal IK chains? */ - if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) { + if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { ik_on = pose_grab_with_ik(bmain, ob); if (ik_on) { t->flag |= T_AUTOIK; has_translate_rotate[0] = true; } } + + if (mirror) { + int total_mirrored = 0; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone->flag & BONE_TRANSFORM) && + BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) { + total_mirrored++; + } + } + + PoseInitData_Mirror *pid = MEM_mallocN((total_mirrored + 1) * sizeof(PoseInitData_Mirror), + "PoseInitData_Mirror"); + + /* Trick to terminate iteration. */ + pid[total_mirrored].pchan = NULL; + + tc->custom.type.data = pid; + tc->custom.type.use_free = true; + } } /* if there are no translatable bones, do rotation */ @@ -1269,6 +1362,17 @@ static void createTransPose(TransInfo *t) short ik_on = 0; int i; + PoseInitData_Mirror *pid = tc->custom.type.data; + int pid_index = 0; + bPose *pose = ob->pose; + + if (pose == NULL) { + continue; + } + + const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); + const bool is_mirror_relative = ((pose->flag & POSE_MIRROR_RELATIVE) != 0); + tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */ /* init trans data */ @@ -1285,6 +1389,15 @@ static void createTransPose(TransInfo *t) for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone->flag & BONE_TRANSFORM) { add_pose_transdata(t, pchan, ob, tc, td); + + if (mirror) { + bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name); + if (pchan_mirror) { + pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative); + pid_index++; + } + } + td++; } } @@ -1304,6 +1417,19 @@ static void createTransPose(TransInfo *t) t->flag &= ~T_PROP_EDIT_ALL; } +void restoreMirrorPoseBones(TransDataContainer *tc) +{ + bPose *pose = tc->poseobj->pose; + + if (!(pose->flag & POSE_MIRROR_EDIT)) { + return; + } + + for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) { + pose_mirror_info_restore(pid); + } +} + void restoreBones(TransDataContainer *tc) { bArmature *arm; @@ -9253,7 +9379,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9267,7 +9393,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9281,7 +9407,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, true); sort_trans_data_dist(t); } @@ -9304,7 +9430,7 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_EDIT; if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9321,7 +9447,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); /* don't do that, distance has been set in createTransActionData already */ // set_prop_dist(t, false); sort_trans_data_dist(t); @@ -9351,7 +9477,7 @@ void createTransData(bContext *C, TransInfo *t) if (t->data_len_all && (t->flag & T_PROP_EDIT)) { /* makes selected become first in array */ - sort_trans_data(t); + sort_trans_data_selected_first(t); /* don't do that, distance has been set in createTransGraphEditData already */ set_prop_dist(t, false); @@ -9367,7 +9493,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } @@ -9386,7 +9512,7 @@ void createTransData(bContext *C, TransInfo *t) countAndCleanTransDataContainer(t); if (t->data_len_all && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, true); sort_trans_data_dist(t); } @@ -9426,21 +9552,30 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_EDIT | T_POINTS; - if (t->data_len_all && t->flag & T_PROP_EDIT) { - if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) { - sort_trans_data(t); // makes selected become first in array - if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) { - /* already calculated by editmesh_set_connectivity_distance */ + if (t->data_len_all) { + if (t->flag & T_PROP_EDIT) { + if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) { + sort_trans_data_selected_first(t); + if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) { + /* already calculated by editmesh_set_connectivity_distance */ + } + else { + set_prop_dist(t, 0); + } + sort_trans_data_dist(t); } else { - set_prop_dist(t, 0); + sort_trans_data_selected_first(t); + set_prop_dist(t, 1); + sort_trans_data_dist(t); } - sort_trans_data_dist(t); } else { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); + if (ELEM(t->obedit_type, OB_CURVE)) { + /* Needed because bezier handles can be partially selected + * and are still added into transform data. */ + sort_trans_data_selected_first(t); + } } } @@ -9494,7 +9629,7 @@ void createTransData(bContext *C, TransInfo *t) t->flag |= T_POINTS; if (t->data_len_all && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array + sort_trans_data_selected_first(t); set_prop_dist(t, 1); sort_trans_data_dist(t); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 8ddc5461e9a..758551be0b5 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -781,6 +781,49 @@ static void recalcData_spaceclip(TransInfo *t) } } +/** + * if pose bone (partial) selected, copy data. + * context; posemode armature, with mirror editing enabled. + * + * \param pid: Optional, apply relative transform when set. + */ +static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) +{ + float flip_mtx[4][4]; + unit_m4(flip_mtx); + flip_mtx[0][0] = -1; + + for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; + pchan_orig = pchan_orig->next) { + /* no layer check, correct mirror is more important */ + if (pchan_orig->bone->flag & BONE_TRANSFORM) { + bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); + + if (pchan) { + /* also do bbone scaling */ + pchan->bone->xwidth = pchan_orig->bone->xwidth; + pchan->bone->zwidth = pchan_orig->bone->zwidth; + + /* we assume X-axis flipping for now */ + pchan->curve_in_x = pchan_orig->curve_in_x * -1; + pchan->curve_out_x = pchan_orig->curve_out_x * -1; + pchan->roll1 = pchan_orig->roll1 * -1; // XXX? + pchan->roll2 = pchan_orig->roll2 * -1; // XXX? + + float pchan_mtx_final[4][4]; + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); + mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); + mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); + if (pid) { + mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); + pid++; + } + BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); + } + } + } +} + /* helper for recalcData() - for object transforms, typically in the 3D view */ static void recalcData_objects(TransInfo *t) { @@ -975,12 +1018,22 @@ static void recalcData_objects(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; bArmature *arm = ob->data; - if (arm->flag & ARM_MIRROR_EDIT) { - if (t->state != TRANS_CANCEL) { - ED_armature_edit_transform_mirror_update(ob); + if (ob->mode == OB_MODE_EDIT) { + if (arm->flag & ARM_MIRROR_EDIT) { + if (t->state != TRANS_CANCEL) { + ED_armature_edit_transform_mirror_update(ob); + } + else { + restoreBones(tc); + } } - else { - restoreBones(tc); + } + else if (ob->mode == OB_MODE_POSE) { + /* actually support TFM_BONESIZE in posemode as well */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + bPose *pose = ob->pose; + if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { + pose_transform_mirror_update(ob, NULL); } } } @@ -991,6 +1044,20 @@ static void recalcData_objects(TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { Object *ob = tc->poseobj; bArmature *arm = ob->data; + bPose *pose = ob->pose; + + if (pose->flag & POSE_MIRROR_EDIT) { + if (t->state != TRANS_CANCEL) { + PoseInitData_Mirror *pid = NULL; + if (pose->flag & POSE_MIRROR_RELATIVE) { + pid = tc->custom.type.data; + } + pose_transform_mirror_update(ob, pid); + } + else { + restoreMirrorPoseBones(tc); + } + } /* if animtimer is running, and the object already has animation data, * check if the auto-record feature means that we should record 'samples' @@ -1309,7 +1376,9 @@ void initTransDataContainers_FromObjectData(TransInfo *t, BLI_assert((t->flag & T_2D_EDIT) == 0); copy_m4_m4(tc->mat, objects[i]->obmat); copy_m3_m4(tc->mat3, tc->mat); - invert_m4_m4(tc->imat, tc->mat); + /* for non-invertible scale matrices, invert_m4_m4_fallback() + * can still provide a valid pivot */ + invert_m4_m4_fallback(tc->imat, tc->mat); invert_m3_m3(tc->imat3, tc->mat3); normalize_m3_m3(tc->mat3_unit, tc->mat3); } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 50610f1b3da..e43379dc358 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -703,7 +703,7 @@ void ED_transform_calc_orientation_from_type_ex(const bContext *C, break; } case V3D_ORIENT_CURSOR: { - ED_view3d_cursor3d_calc_mat3(scene, r_mat); + BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); ok = true; break; } @@ -1762,6 +1762,15 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) } } MAN_ITER_AXES_END; + + /* Ensure rotate disks don't overlap scale arrows, especially in ortho view. */ + float rotate_select_bias = 0.0f; + if ((ggd->twtype & V3D_GIZMO_SHOW_OBJECT_SCALE) && ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) { + rotate_select_bias = -2.0f; + } + for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) { + ggd->gizmos[i]->select_bias = rotate_select_bias; + } } static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 8606cd19c96..cdd0896ab66 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -1170,7 +1170,7 @@ static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editmesh_auto_smooth; + ot->poll = ED_operator_editmesh; RNA_def_float_rotation( ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index e16579aba64..70bb2bf98a6 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -485,7 +485,7 @@ void initTransformOrientation(bContext *C, TransInfo *t) break; case V3D_ORIENT_CURSOR: { BLI_strncpy(t->spacename, IFACE_("cursor"), sizeof(t->spacename)); - ED_view3d_cursor3d_calc_mat3(t->scene, t->spacemtx); + BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); break; } case V3D_ORIENT_CUSTOM_MATRIX: diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 49b5cada04a..99143cd71f9 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -392,6 +392,15 @@ static bool ed_undo_redo_poll(bContext *C) WM_operator_check_ui_enabled(C, last_op->type->name)); } +static bool ed_undo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL); +} + void ED_OT_undo(wmOperatorType *ot) { /* identifiers */ @@ -401,7 +410,7 @@ void ED_OT_undo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_undo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_undo_poll; } void ED_OT_undo_push(wmOperatorType *ot) @@ -426,6 +435,15 @@ void ED_OT_undo_push(wmOperatorType *ot) ""); } +static bool ed_redo_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL); +} + void ED_OT_redo(wmOperatorType *ot) { /* identifiers */ @@ -435,7 +453,7 @@ void ED_OT_redo(wmOperatorType *ot) /* api callbacks */ ot->exec = ed_redo_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = ed_redo_poll; } void ED_OT_undo_redo(wmOperatorType *ot) @@ -569,7 +587,7 @@ static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) item_tmp.identifier = us->name; item_tmp.name = IFACE_(us->name); if (us == wm->undo_stack->step_active) { - item_tmp.icon = ICON_HIDE_OFF; + item_tmp.icon = ICON_LAYER_ACTIVE; } else { item_tmp.icon = ICON_NONE; @@ -633,6 +651,16 @@ static int undo_history_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +static bool undo_history_poll(bContext *C) +{ + if (!ed_undo_is_init_and_screenactive_poll(C)) { + return false; + } + UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; + /* more than just original state entry */ + return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1; +} + void ED_OT_undo_history(wmOperatorType *ot) { /* identifiers */ @@ -643,7 +671,7 @@ void ED_OT_undo_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; - ot->poll = ed_undo_is_init_and_screenactive_poll; + ot->poll = undo_history_poll; RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 3b49784d5eb..c09237d825d 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -41,6 +41,7 @@ set(SRC ed_util.c gizmo_utils.c numinput.c + select_buffer_utils.c select_utils.c # general includes @@ -79,11 +80,13 @@ set(SRC ../include/ED_screen.h ../include/ED_screen_types.h ../include/ED_sculpt.h + ../include/ED_select_buffer_utils.h ../include/ED_select_utils.h ../include/ED_sequencer.h ../include/ED_sound.h ../include/ED_space_api.h ../include/ED_text.h + ../include/ED_time_scrub_ui.h ../include/ED_transform.h ../include/ED_transform_snap_object_context.h ../include/ED_transverts.h diff --git a/source/blender/editors/util/select_buffer_utils.c b/source/blender/editors/util/select_buffer_utils.c new file mode 100644 index 00000000000..130f6819e34 --- /dev/null +++ b/source/blender/editors/util/select_buffer_utils.c @@ -0,0 +1,303 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edutil + * + * Generic utilities for handling buffer selection where selection ID's are drawn onto + * an off screen buffer. + * + * All coordinates are relative to the current region. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_bitmap_draw_2d.h" +#include "BLI_rect.h" +#include "BLI_utildefines.h" + +#include "ED_select_buffer_utils.h" + +/* Only for #ED_view3d_select_id_read, + * note that this file shouldn't have 3D view specific logic in it, we could have a more general + * way to read from selection buffers that doesn't depend on the view3d API. */ +#include "ED_view3d.h" + +/* -------------------------------------------------------------------- */ +/** \name Select Bitmap from ID's + * + * Given a buffer of select ID's, fill in a booleans (true/false) per index. + * #BLI_bitmap is used for memory effeciency. + * + * \{ */ + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param rect: The rectangle to sample indices from (min/max inclusive). + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const rcti *rect) +{ + uint buf_len; + const uint *buf = ED_view3d_select_id_read( + rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len); + if (buf == NULL) { + return NULL; + } + + const uint *buf_iter = buf; + + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + + while (buf_len--) { + const uint index = *buf_iter - 1; + if (index < bitmap_len) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + buf_iter++; + } + MEM_freeN((void *)buf); + return bitmap_buf; +} + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param center: Circle center. + * \param radius: Circle radius. + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len, + const int center[2], + const int radius) +{ + if (bitmap_len == 0) { + return NULL; + } + + const int xmin = center[0] - radius; + const int xmax = center[0] + radius; + const int ymin = center[1] - radius; + const int ymax = center[1] + radius; + + const uint *buf = ED_view3d_select_id_read(xmin, ymin, xmax, ymax, NULL); + if (buf == NULL) { + return NULL; + } + + const uint *buf_iter = buf; + + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + const int radius_sq = radius * radius; + for (int yc = -radius; yc <= radius; yc++) { + for (int xc = -radius; xc <= radius; xc++, buf_iter++) { + if (xc * xc + yc * yc < radius_sq) { + /* Intentionally wrap to max value if this is zero. */ + const uint index = *buf_iter - 1; + if (index < bitmap_len) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + } + } + } + MEM_freeN((void *)buf); + return bitmap_buf; +} + +struct PolyMaskData { + BLI_bitmap *px; + int width; +}; + +static void ed_select_buffer_mask_px_cb(int x, int x_end, int y, void *user_data) +{ + struct PolyMaskData *data = user_data; + BLI_bitmap *px = data->px; + int i = (y * data->width) + x; + do { + BLI_BITMAP_ENABLE(px, i); + i++; + } while (++x != x_end); +} + +/** + * \param bitmap_len: Number of indices in the selection id buffer. + * \param center: Circle center. + * \param radius: Circle radius. + * \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure. + */ +uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len, + const int poly[][2], + const int poly_len, + const rcti *rect) + +{ + if (bitmap_len == 0) { + return NULL; + } + + struct PolyMaskData poly_mask_data; + uint buf_len; + const uint *buf = ED_view3d_select_id_read( + rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len); + if (buf == NULL) { + return NULL; + } + + BLI_bitmap *buf_mask = BLI_BITMAP_NEW(buf_len, __func__); + poly_mask_data.px = buf_mask; + poly_mask_data.width = (rect->xmax - rect->xmin) + 1; + + BLI_bitmap_draw_2d_poly_v2i_n(rect->xmin, + rect->ymin, + rect->xmax + 1, + rect->ymax + 1, + poly, + poly_len, + ed_select_buffer_mask_px_cb, + &poly_mask_data); + + /* Build selection lookup. */ + const uint *buf_iter = buf; + BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__); + int i = 0; + while (buf_len--) { + const uint index = *buf_iter - 1; + if (index < bitmap_len && BLI_BITMAP_TEST(buf_mask, i)) { + BLI_BITMAP_ENABLE(bitmap_buf, index); + } + buf_iter++; + i++; + } + MEM_freeN((void *)buf); + MEM_freeN(buf_mask); + + return bitmap_buf; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Find Single Select ID's + * + * Given a buffer of select ID's, find the a single select id. + * + * \{ */ + +/** + * Samples a single pixel. + */ +uint ED_select_buffer_sample_point(const int center[2]) +{ + uint buf_len; + uint *buf = ED_view3d_select_id_read(center[0], center[1], center[0], center[1], &buf_len); + BLI_assert(0 != buf_len); + uint ret = buf[0]; + MEM_freeN(buf); + return ret; +} + +/** + * Find the selection id closest to \a center. + * \param dist[in,out]: Use to initalize the distance, + * when found, this value is set to the distance of the selection thats returned. + */ +uint ED_select_buffer_find_nearest_to_point(const int center[2], + const uint id_min, + const uint id_max, + uint *dist) +{ + /* Smart function to sample a rect spiralling outside, nice for selection ID. */ + + /* Create region around center (typically the mouse cursor). + * This must be square and have an odd width, + * the spiraling algorithm does not work with arbitrary rectangles. */ + rcti rect; + BLI_rcti_init_pt_radius(&rect, center, *dist); + rect.xmax += 1; + rect.ymax += 1; + + int width = BLI_rcti_size_x(&rect); + int height = width; + BLI_assert(width == height); + + /* Read from selection framebuffer. */ + + uint buf_len; + const uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len); + BLI_assert(width * height == buf_len); + + /* Spiral, starting from center of buffer. */ + int spiral_offset = height * (int)(width / 2) + (height / 2); + int spiral_direction = 0; + + uint index = 0; + + for (int nr = 1; nr <= height; nr++) { + for (int a = 0; a < 2; a++) { + for (int b = 0; b < nr; b++) { + /* Find hit within the specified range. */ + uint hit_id = buf[spiral_offset]; + + if (hit_id && hit_id >= id_min && hit_id < id_max) { + /* Get x/y from spiral offset. */ + int hit_x = spiral_offset % width; + int hit_y = spiral_offset / width; + + int center_x = width / 2; + int center_y = height / 2; + + /* Manhatten distance in keeping with other screen-based selection. */ + *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); + + /* Indices start at 1 here. */ + index = (hit_id - id_min) + 1; + goto exit; + } + + /* Next spiral step. */ + if (spiral_direction == 0) { + spiral_offset += 1; /* right */ + } + else if (spiral_direction == 1) { + spiral_offset -= width; /* down */ + } + else if (spiral_direction == 2) { + spiral_offset -= 1; /* left */ + } + else { + spiral_offset += width; /* up */ + } + + /* Stop if we are outside the buffer. */ + if (spiral_offset < 0 || spiral_offset >= buf_len) { + goto exit; + } + } + + spiral_direction = (spiral_direction + 1) % 4; + } + } + +exit: + MEM_freeN((void *)buf); + return index; +} + +/** \} */ diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 804b9c22104..7f9b90f4496 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -170,6 +170,7 @@ static void uvedit_get_batches(Object *ob, const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0; + DRW_mesh_batch_cache_validate(ob->data); *edges = DRW_mesh_batch_cache_get_edituv_edges(ob->data); *verts = DRW_mesh_batch_cache_get_edituv_verts(ob->data); @@ -206,6 +207,7 @@ static void draw_uvs_shadow(SpaceImage *UNUSED(sima), float col[4]; UI_GetThemeColor4fv(TH_UV_SHADOW, col); + DRW_mesh_batch_cache_validate(me); GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me); DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); @@ -228,6 +230,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) return; } + DRW_mesh_batch_cache_validate(me); GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me); DRW_mesh_batch_cache_create_requested(eval_ob, me, scene->toolsettings, false, false); @@ -243,6 +246,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); GPU_matrix_bind(geom->interface); + GPU_batch_bind(geom); /* TODO(fclem): If drawcall count becomes a problem in the future * we can use multi draw indirect drawcalls for this. @@ -251,7 +255,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1)); if (ma_match != prev_ma_match) { if (ma_match == false) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); } else { draw_start = idx; @@ -261,7 +265,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph) prev_ma_match = ma_match; } if (prev_ma_match == true) { - GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false); + GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0); } GPU_batch_program_use_end(geom); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 85393925802..717bc347cf7 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -386,6 +386,10 @@ static ParamHandle *construct_param_handle_multi(Scene *scene, const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + if (cd_loop_uv_offset == -1) { + continue; + } + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 06a356dd232..ee13583e67a 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -23,6 +23,7 @@ #include "BLI_utildefines.h" #include "BKE_global.h" +#include "BKE_object.h" #include <sstream> @@ -98,14 +99,11 @@ NodeGroup *BlenderFileLoader::Load() continue; } - bool apply_modifiers = false; - bool calc_undeformed = false; - Mesh *mesh = BKE_mesh_new_from_object( - _depsgraph, _re->main, _re->scene, ob, apply_modifiers, calc_undeformed); + Mesh *mesh = BKE_object_to_mesh(ob); if (mesh) { insertShapeNode(ob, mesh, ++id); - BKE_id_free_ex(_re->main, &mesh->id, LIB_ID_FREE_NO_UI_USER, true); + BKE_object_to_mesh_clear(ob); } } DEG_OBJECT_ITER_END; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 082ed34c353..8a3cdd575fe 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -125,13 +125,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str /* Render with transparent background. */ freestyle_scene->r.alphamode = R_ALPHAPREMUL; - if (STREQ(freestyle_scene->r.engine, RE_engine_id_CYCLES)) { - PointerRNA freestyle_scene_ptr; - RNA_id_pointer_create(&freestyle_scene->id, &freestyle_scene_ptr); - PointerRNA freestyle_cycles_ptr = RNA_pointer_get(&freestyle_scene_ptr, "cycles"); - RNA_boolean_set(&freestyle_cycles_ptr, "film_transparent", 1); - } - if (G.debug & G_DEBUG_FREESTYLE) { printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r)); } @@ -270,6 +263,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, } ma->nodetree = ntree; ma->use_nodes = 1; + ma->blend_method = MA_BM_HASHED; bNode *input_attr_color = nodeAddStaticNode(NULL, ntree, SH_NODE_ATTRIBUTE); input_attr_color->locx = 0.0f; diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index 09c29025d15..8b81660fd58 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -24,6 +24,9 @@ #include <stdlib.h> #include <time.h> +#include "BLI_compiler_attrs.h" +#include "BLI_rand.h" + #include "Noise.h" namespace Freestyle { @@ -40,9 +43,7 @@ namespace Freestyle { ((s) * (RTable[m] * 0.5 + RTable[m + 1] * (x) + RTable[m + 2] * (y) + RTable[m + 3] * (z))) # define MAXSIZE 500 -# define NRAND() ((float)rand() / (float)RAND_MAX) #endif -#define SEEDNRAND(x) (srand(x * RAND_MAX)) #define BM 0xff #define N 0x1000 @@ -236,25 +237,26 @@ float Noise::smoothNoise3(Vec3f &vec) Noise::Noise(long seed) { + /* Use Blender RNG for repeatable results across platforms. */ + RNG *rng = BLI_rng_new(seed); int i, j, k; - SEEDNRAND((seed < 0) ? time(NULL) : seed); for (i = 0; i < _NOISE_B; i++) { p[i] = i; - g1[i] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; + g1[i] = (float)((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; for (j = 0; j < 2; j++) - g2[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; + g2[i][j] = (float)((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; normalize2(g2[i]); for (j = 0; j < 3; j++) - g3[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; + g3[i][j] = (float)((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; normalize3(g3[i]); } while (--i) { k = p[i]; - p[i] = p[j = rand() % _NOISE_B]; + p[i] = p[j = BLI_rng_get_int(rng) % _NOISE_B]; p[j] = k; } @@ -268,6 +270,8 @@ Noise::Noise(long seed) for (j = 0; j < 3; j++) g3[_NOISE_B + i][j] = g3[i][j]; } + + BLI_rng_free(rng); } } /* namespace Freestyle */ diff --git a/source/blender/freestyle/intern/system/RandGen.cpp b/source/blender/freestyle/intern/system/RandGen.cpp index 77eb9a8c10a..719287b102f 100644 --- a/source/blender/freestyle/intern/system/RandGen.cpp +++ b/source/blender/freestyle/intern/system/RandGen.cpp @@ -49,7 +49,8 @@ namespace Freestyle { long l = (long)(x) * (long)(y); \ (z)[0] = LOW(l); \ (z)[1] = HIGH(l); \ - } + } \ + ((void)0) #define CARRY(x, y) ((unsigned long)((long)(x) + (long)(y)) > MASK) #define ADDEQU(x, y, z) (z = CARRY(x, (y)), x = LOW(x + (y))) diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5a42c4d3d1b..f30eff1484b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -178,7 +178,6 @@ data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_normal_smooth_color_vert.glsl SRC) @@ -225,14 +224,6 @@ data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_selection_id_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_selection_id_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_overlay_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_overlay_geom.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_overlay_simple_geom.glsl SRC) -data_to_c_simple(shaders/gpu_shader_edges_overlay_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_text_simple_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_text_simple_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index 856148563f2..3b0d72831c0 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -33,6 +33,7 @@ #include "GPU_shader.h" typedef enum { + GPU_BATCH_UNUSED, GPU_BATCH_READY_TO_FORMAT, GPU_BATCH_READY_TO_BUILD, GPU_BATCH_BUILDING, @@ -131,7 +132,7 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch, void GPU_batch_program_use_begin(GPUBatch *); /* call before Batch_Uniform (temp hack?) */ void GPU_batch_program_use_end(GPUBatch *); -void GPU_batch_uniform_1ui(GPUBatch *, const char *name, int value); +void GPU_batch_uniform_1ui(GPUBatch *, const char *name, uint value); void GPU_batch_uniform_1i(GPUBatch *, const char *name, int value); void GPU_batch_uniform_1b(GPUBatch *, const char *name, bool value); void GPU_batch_uniform_1f(GPUBatch *, const char *name, float value); @@ -147,8 +148,10 @@ void GPU_batch_uniform_mat4(GPUBatch *, const char *name, const float data[4][4] void GPU_batch_draw(GPUBatch *); +/* Needs to be called before GPU_batch_draw_advanced. */ +void GPU_batch_bind(GPUBatch *); /* This does not bind/unbind shader and does not call GPU_matrix_bind() */ -void GPU_batch_draw_range_ex(GPUBatch *, int v_first, int v_count, bool force_instance); +void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count); /* Does not even need batch */ void GPU_draw_primitive(GPUPrimType, int v_count); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 20047174bb1..9009c134837 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -32,10 +32,10 @@ struct CCGKey; struct DMFlagMat; struct GSet; struct MLoop; +struct MLoopCol; struct MLoopTri; struct MPoly; struct MVert; -struct MLoopCol; struct PBVH; /* Buffers for drawing from PBVH grids. */ @@ -88,10 +88,9 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, /* draw */ struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires); -bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers); +short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers); -/* debug PBVH draw */ -void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos); +bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers); void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 300fc7c65a2..8b830aadbba 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -84,17 +84,13 @@ void GPU_create_gl_tex(unsigned int *bind, int recth, int textarget, bool mipmap, - bool use_hight_bit_depth, + bool use_srgb, struct Image *ima); void GPU_create_gl_tex_compressed(unsigned int *bind, - unsigned int *pix, - int x, - int y, - int mipmap, int textarget, struct Image *ima, struct ImBuf *ibuf); -bool GPU_upload_dxt_texture(struct ImBuf *ibuf); +bool GPU_upload_dxt_texture(struct ImBuf *ibuf, bool use_srgb); void GPU_free_image(struct Image *ima); void GPU_free_images(struct Main *bmain); void GPU_free_images_anim(struct Main *bmain); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index da61dc76422..dd5292d9c58 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -107,7 +107,7 @@ typedef enum eGPUBuiltin { GPU_VOLUME_TEMPERATURE = (1 << 18), GPU_BARYCENTRIC_TEXCO = (1 << 19), GPU_BARYCENTRIC_DIST = (1 << 20), - GPU_INVERSE_NORMAL_MATRIX = (1 << 21), + GPU_WORLD_NORMAL = (1 << 21), } eGPUBuiltin; typedef enum eGPUMatFlag { @@ -145,7 +145,7 @@ typedef enum eGPUMaterialStatus { GPUNodeLink *GPU_attribute(CustomDataType type, const char *name); GPUNodeLink *GPU_constant(float *num); GPUNodeLink *GPU_uniform(float *num); -GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data); +GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer); GPUNodeLink *GPU_builtin(eGPUBuiltin builtin); @@ -177,6 +177,7 @@ GPUMaterial *GPU_material_from_nodetree_find(struct ListBase *gpumaterials, const void *engine_type, int options); GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, + struct Material *ma, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, @@ -194,6 +195,7 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); struct ListBase *GPU_material_get_inputs(GPUMaterial *material); +struct Material *GPU_material_get_material(GPUMaterial *material); eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material); @@ -202,7 +204,6 @@ struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void); void GPU_material_vertex_attrs(GPUMaterial *material, struct GPUVertAttrLayers *attrs); -bool GPU_material_do_color_management(GPUMaterial *mat); bool GPU_material_use_domain_surface(GPUMaterial *mat); bool GPU_material_use_domain_volume(GPUMaterial *mat); diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h index 67fb2bb2bd4..6f7d25dafa7 100644 --- a/source/blender/gpu/GPU_matrix.h +++ b/source/blender/gpu/GPU_matrix.h @@ -106,6 +106,11 @@ bool GPU_matrix_unproject(const float win[3], const float proj[4][4], const int view[4], float world[3]); +void GPU_matrix_unproject_model_inverted(const float win[3], + const float model_inverted[4][4], + const float proj[4][4], + const int view[4], + float world[3]); /* 2D Projection Matrix */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index d174aafacce..00570bd7ebc 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -100,10 +100,6 @@ typedef enum eGPUBuiltinShader { /* specialized drawing */ GPU_SHADER_TEXT, GPU_SHADER_TEXT_SIMPLE, - GPU_SHADER_EDGES_FRONT_BACK_PERSP, - GPU_SHADER_EDGES_FRONT_BACK_ORTHO, - GPU_SHADER_EDGES_OVERLAY_SIMPLE, - GPU_SHADER_EDGES_OVERLAY, GPU_SHADER_KEYFRAME_DIAMOND, GPU_SHADER_SIMPLE_LIGHTING, GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR, @@ -402,10 +398,7 @@ void GPU_shader_free_builtin_shaders(void); typedef struct GPUVertAttrLayers { struct { - int type; - int glindex; - int glinfoindoex; - int gltexco; + int type; /* CustomDataType */ int attr_id; char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ } layer[GPU_MAX_ATTR]; diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index ace8832303b..441f7290cc5 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -44,14 +44,10 @@ typedef enum { GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */ GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ - GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */ - GPU_UNIFORM_NORMAL_INV, /* mat3 NormalMatrixInverse */ - GPU_UNIFORM_WORLDNORMAL, /* mat3 WorldNormalMatrix */ - GPU_UNIFORM_CAMERATEXCO, /* vec4 CameraTexCoFactors */ - GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */ + GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */ + GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */ GPU_UNIFORM_COLOR, /* vec4 color */ - GPU_UNIFORM_EYE, /* vec3 eye */ GPU_UNIFORM_CALLID, /* int callId */ GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 3527398a396..3fb7dfc6331 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -186,10 +186,7 @@ GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert); GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer); GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode); -GPUTexture *GPU_texture_from_blender(struct Image *ima, - struct ImageUser *iuser, - int textarget, - bool is_data); +GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, int textarget); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); void GPU_texture_add_mipmap(GPUTexture *tex, diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index 6d88460964d..3e178e193dc 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -48,12 +48,17 @@ typedef enum { typedef struct GPUVertBuf { GPUVertFormat format; - uint vertex_len; /* number of verts we want to draw */ - uint vertex_alloc; /* number of verts data */ - bool dirty; + /** Number of verts we want to draw. */ + uint vertex_len; + /** Number of verts data. */ + uint vertex_alloc; + /** 0 indicates not yet allocated. */ + uint32_t vbo_id; + /** Usage hint for GL optimisation. */ + uint usage : 2; + /** Data has been touched and need to be reuploaded to GPU. */ + uint dirty : 1; unsigned char *data; /* NULL indicates data in VRAM (unmapped) */ - uint32_t vbo_id; /* 0 indicates not yet allocated */ - GPUUsageType usage; /* usage hint for GL optimisation */ } GPUVertBuf; GPUVertBuf *GPU_vertbuf_create(GPUUsageType); @@ -62,6 +67,7 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp #define GPU_vertbuf_create_with_format(format) \ GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_STATIC) +void GPU_vertbuf_clear(GPUVertBuf *verts); void GPU_vertbuf_discard(GPUVertBuf *); void GPU_vertbuf_init(GPUVertBuf *, GPUUsageType); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index 7f1934431cf..43eec55bca2 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -27,6 +27,8 @@ #define __GPU_VERTEX_FORMAT_H__ #include "GPU_common.h" +#include "BLI_compiler_compat.h" +#include "BLI_assert.h" #define GPU_VERT_ATTR_MAX_LEN 16 #define GPU_VERT_ATTR_MAX_NAMES 4 @@ -54,28 +56,41 @@ typedef enum { } GPUVertFetchMode; typedef struct GPUVertAttr { - GPUVertFetchMode fetch_mode; - GPUVertCompType comp_type; + uint fetch_mode : 2; + uint comp_type : 3; + /* 1 to 4 or 8 or 12 or 16 */ + uint comp_len : 5; + /* size in bytes, 1 to 64 */ + uint sz : 7; + /* from beginning of vertex, in bytes */ + uint offset : 11; + /* up to GPU_VERT_ATTR_MAX_NAMES */ + uint name_len : 3; uint gl_comp_type; - uint comp_len; /* 1 to 4 or 8 or 12 or 16 */ - uint sz; /* size in bytes, 1 to 64 */ - uint offset; /* from beginning of vertex, in bytes */ - uint name_len; /* up to GPU_VERT_ATTR_MAX_NAMES */ - const char *name[GPU_VERT_ATTR_MAX_NAMES]; + /* -- 8 Bytes -- */ + uchar names[GPU_VERT_ATTR_MAX_NAMES]; } GPUVertAttr; +BLI_STATIC_ASSERT(GPU_VERT_ATTR_NAMES_BUF_LEN <= 256, + "We use uchar as index inside the name buffer " + "so GPU_VERT_ATTR_NAMES_BUF_LEN needs to be be " + "smaller than GPUVertFormat->name_offset and " + "GPUVertAttr->names maximum value"); + typedef struct GPUVertFormat { /** 0 to 16 (GPU_VERT_ATTR_MAX_LEN). */ - uint attr_len; + uint attr_len : 5; /** Total count of active vertex attribute. */ - uint name_len; - /** Stride in bytes, 1 to 256. */ - uint stride; - uint name_offset; - bool packed; - char names[GPU_VERT_ATTR_NAMES_BUF_LEN]; - /** TODO: variable-size array */ + uint name_len : 5; + /** Stride in bytes, 1 to 1024. */ + uint stride : 11; + /** Has the format been packed. */ + uint packed : 1; + /** Current offset in names[]. */ + uint name_offset : 8; + GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]; + char names[GPU_VERT_ATTR_NAMES_BUF_LEN]; } GPUVertFormat; struct GPUShaderInterface; @@ -88,18 +103,15 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, uint GPU_vertformat_attr_add( GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode); void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias); + int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name); -/** - * This makes the "virtual" attributes with suffixes "0", "1", "2" - * to access triangle data in the vertex shader. - * - * IMPORTANT: - * - Call this before creating the vertex buffer and after creating all attributes - * - Only first vertex out of 3 has the correct information. - * Use flat output with #GL_FIRST_VERTEX_CONVENTION. - */ -void GPU_vertformat_triple_load(GPUVertFormat *format); +BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format, + const GPUVertAttr *attr, + uint n_idx) +{ + return format->names + attr->names[n_idx]; +} /* format conversion */ diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index 198a9ec98e2..e7600279d6f 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -37,12 +37,14 @@ typedef struct GPUViewport GPUViewport; /* Contains memory pools information */ typedef struct ViewportMemoryPool { - struct BLI_mempool *calls; - struct BLI_mempool *states; - struct BLI_mempool *shgroups; - struct BLI_mempool *uniforms; - struct BLI_mempool *passes; - struct BLI_mempool *images; + struct BLI_memblock *calls; + struct BLI_memblock *states; + struct BLI_memblock *cullstates; + struct BLI_memblock *shgroups; + struct BLI_memblock *uniforms; + struct BLI_memblock *views; + struct BLI_memblock *passes; + struct BLI_memblock *images; } ViewportMemoryPool; /* All FramebufferLists are just the same pointers with different names */ @@ -118,7 +120,7 @@ GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport); GPUTexture *GPU_viewport_texture_pool_query( GPUViewport *viewport, void *engine, int width, int height, int format); -bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash); +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, void **engine_handle_array); void GPU_viewport_cache_release(GPUViewport *viewport); #endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.c index e280b77f661..802b15a0c4e 100644 --- a/source/blender/gpu/intern/gpu_attr_binding.c +++ b/source/blender/gpu/intern/gpu_attr_binding.c @@ -70,7 +70,8 @@ void get_attr_locations(const GPUVertFormat *format, for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) { const GPUVertAttr *a = &format->attrs[a_idx]; for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { - const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, a->name[n_idx]); + const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); + const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name); #if TRUST_NO_ONE assert(input != NULL); /* TODO: make this a recoverable runtime error? diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index f179f9ef22c..933bcb2ed8e 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -139,6 +139,7 @@ void GPU_batch_clear(GPUBatch *batch) } } GPU_batch_vao_cache_clear(batch); + batch->phase = GPU_BATCH_UNUSED; } void GPU_batch_discard(GPUBatch *batch) @@ -369,7 +370,8 @@ static void create_bindings(GPUVertBuf *verts, const GLvoid *pointer = (const GLubyte *)0 + a->offset + v_first * stride; for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) { - const GPUShaderInput *input = GPU_shaderinterface_attr(interface, a->name[n_idx]); + const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); + const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name); if (input == NULL) { continue; @@ -459,7 +461,7 @@ void GPU_batch_program_use_end(GPUBatch *batch) const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); #endif -void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, int value) +void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, uint value) { GET_UNIFORM glUniform1ui(uniform->location, value); @@ -575,10 +577,14 @@ static void *elem_offset(const GPUIndexBuf *el, int v_first) else if (el->index_type == GPU_INDEX_U16) { return (GLushort *)0 + v_first; } - else { #endif - return (GLuint *)0 + v_first; - } + return (GLuint *)0 + v_first; +} + +/* Use when drawing with GPU_batch_draw_advanced */ +void GPU_batch_bind(GPUBatch *batch) +{ + glBindVertexArray(batch->vao_id); } void GPU_batch_draw(GPUBatch *batch) @@ -590,103 +596,76 @@ void GPU_batch_draw(GPUBatch *batch) GPU_batch_program_use_begin(batch); GPU_matrix_bind(batch->interface); // external call. - GPU_batch_draw_range_ex(batch, 0, 0, false); + GPU_batch_bind(batch); + GPU_batch_draw_advanced(batch, 0, 0, 0, 0); GPU_batch_program_use_end(batch); } -void GPU_batch_draw_range_ex(GPUBatch *batch, int v_first, int v_count, bool force_instance) +void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count) { #if TRUST_NO_ONE - assert(!(force_instance && (batch->inst == NULL)) || - v_count > 0); // we cannot infer length if force_instance + BLI_assert(batch->program_in_use); + /* TODO could assert that VAO is bound. */ #endif - const bool do_instance = (force_instance || batch->inst); - - // If using offset drawing, use the default VAO and redo bindings. - if (v_first != 0 && do_instance) { - glBindVertexArray(GPU_vao_default()); - batch_update_program_bindings(batch, v_first); + if (v_count == 0) { + v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; } - else { - glBindVertexArray(batch->vao_id); + if (i_count == 0) { + i_count = (batch->inst) ? batch->inst->vertex_len : 1; } - if (do_instance) { - /* Infer length if vertex count is not given */ - if (v_count == 0) { - v_count = batch->inst->vertex_len; + if (!GLEW_ARB_base_instance) { + if (i_first > 0 && i_count > 0) { + /* If using offset drawing with instancing, we must + * use the default VAO and redo bindings. */ + glBindVertexArray(GPU_vao_default()); + batch_update_program_bindings(batch, v_first); } + else { + /* Previous call could have bind the default vao + * see above. */ + glBindVertexArray(batch->vao_id); + } + } - if (batch->elem) { - const GPUIndexBuf *el = batch->elem; - - if (el->use_prim_restart) { - primitive_restart_enable(el); - } + if (batch->elem) { + const GPUIndexBuf *el = batch->elem; #if GPU_TRACK_INDEX_RANGE - glDrawElementsInstancedBaseVertex( - batch->gl_prim_type, el->index_len, el->gl_index_type, 0, v_count, el->base_index); + GLenum index_type = el->gl_index_type; + GLint base_index = el->base_index; #else - glDrawElementsInstanced(batch->gl_prim_type, el->index_len, GL_UNSIGNED_INT, 0, v_count); + GLenum index_type = GL_UNSIGNED_INT; + GLint base_index = 0; #endif - if (el->use_prim_restart) { - primitive_restart_disable(); - } + void *v_first_ofs = elem_offset(el, v_first); + + if (el->use_prim_restart) { + primitive_restart_enable(el); + } + + if (GLEW_ARB_base_instance) { + glDrawElementsInstancedBaseVertexBaseInstance( + batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first); } else { - glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_len, v_count); + glDrawElementsInstancedBaseVertex( + batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index); + } + + if (el->use_prim_restart) { + primitive_restart_disable(); } } else { - /* Infer length if vertex count is not given */ - if (v_count == 0) { - v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len; - } - - if (batch->elem) { - const GPUIndexBuf *el = batch->elem; - - if (el->use_prim_restart) { - primitive_restart_enable(el); - } - - void *v_first_ofs = elem_offset(el, v_first); - -#if GPU_TRACK_INDEX_RANGE - if (el->base_index) { - glDrawRangeElementsBaseVertex(batch->gl_prim_type, - el->min_index, - el->max_index, - v_count, - el->gl_index_type, - v_first_ofs, - el->base_index); - } - else { - glDrawRangeElements(batch->gl_prim_type, - el->min_index, - el->max_index, - v_count, - el->gl_index_type, - v_first_ofs); - } -#else - glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, v_first_ofs); -#endif - if (el->use_prim_restart) { - primitive_restart_disable(); - } + if (GLEW_ARB_base_instance) { + glDrawArraysInstancedBaseInstance(batch->gl_prim_type, v_first, v_count, i_count, i_first); } else { - glDrawArrays(batch->gl_prim_type, v_first, v_count); + glDrawArraysInstanced(batch->gl_prim_type, v_first, v_count, i_count); } } - - /* Performance hog if you are drawing with the same vao multiple time. - * Only activate for debugging. */ - // glBindVertexArray(0); } /* just draw some vertices and let shader place them where we want. */ diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 9290d073295..e30fccbf29d 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -83,6 +83,8 @@ struct GPU_PBVH_Buffers { uint tot_tri, tot_quad; + short material_index; + /* The PBVH ensures that either all faces in the node are * smooth-shaded or all faces are flat-shaded */ bool smooth; @@ -289,6 +291,11 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, } } + /* Get material index from the first face of this buffer. */ + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; + buffers->material_index = mp->mat_nr; + buffers->show_mask = !empty_mask; buffers->mvert = mvert; } @@ -538,7 +545,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, int i, j, k, x, y; const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - static char vcol[4] = {255, 255, 255, 255}; /* Build VBO */ const int has_mask = key->has_mask; @@ -603,6 +609,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, } if (show_vcol) { + char vcol[4] = {255, 255, 255, 255}; GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol); } @@ -652,6 +659,8 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &fmask); empty_mask = empty_mask && (fmask == 0.0f); } + + char vcol[4] = {255, 255, 255, 255}; GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol); GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol); GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol); @@ -666,14 +675,15 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); } + /* Get material index from the first face of this buffer. */ + buffers->material_index = grid_flag_mats[grid_indices[0]].mat_nr; + buffers->grids = grids; buffers->grid_indices = grid_indices; buffers->totgrid = totgrid; buffers->grid_flag_mats = grid_flag_mats; buffers->gridkey = *key; buffers->show_mask = !empty_mask; - - // printf("node updated %p\n", buffers); } GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden) @@ -793,6 +803,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; int tottri, totvert, maxvert = 0; bool empty_mask = true; + BMFace *f; /* TODO, make mask layer optional for bmesh buffer */ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); @@ -864,7 +875,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); GSET_ITER (gs_iter, bm_faces) { - BMFace *f = BLI_gsetIterator_getKey(&gs_iter); + f = BLI_gsetIterator_getKey(&gs_iter); BLI_assert(f->len == 3); @@ -922,7 +933,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, GSetIterator gs_iter; GSET_ITER (gs_iter, bm_faces) { - BMFace *f = BLI_gsetIterator_getKey(&gs_iter); + f = BLI_gsetIterator_getKey(&gs_iter); if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { BMVert *v[3]; @@ -952,6 +963,9 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, } } + /* Get material index from the last face we iterated on. */ + buffers->material_index = f->mat_nr; + buffers->show_mask = !empty_mask; gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); @@ -990,6 +1004,11 @@ bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers) return buffers->show_mask; } +short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) +{ + return buffers->material_index; +} + void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { @@ -1009,70 +1028,6 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Debug - * \{ */ - -/* debug function, draws the pbvh BB */ -void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, uint pos) -{ - if (leaf) { - immUniformColor4f(0.0, 1.0, 0.0, 0.5); - } - else { - immUniformColor4f(1.0, 0.0, 0.0, 0.5); - } - - /* TODO(merwin): revisit this after we have mutable VertexBuffers - * could keep a static batch & index buffer, change the VBO contents per draw - */ - - immBegin(GPU_PRIM_LINES, 24); - - /* top */ - immVertex3f(pos, min[0], min[1], max[2]); - immVertex3f(pos, min[0], max[1], max[2]); - - immVertex3f(pos, min[0], max[1], max[2]); - immVertex3f(pos, max[0], max[1], max[2]); - - immVertex3f(pos, max[0], max[1], max[2]); - immVertex3f(pos, max[0], min[1], max[2]); - - immVertex3f(pos, max[0], min[1], max[2]); - immVertex3f(pos, min[0], min[1], max[2]); - - /* bottom */ - immVertex3f(pos, min[0], min[1], min[2]); - immVertex3f(pos, min[0], max[1], min[2]); - - immVertex3f(pos, min[0], max[1], min[2]); - immVertex3f(pos, max[0], max[1], min[2]); - - immVertex3f(pos, max[0], max[1], min[2]); - immVertex3f(pos, max[0], min[1], min[2]); - - immVertex3f(pos, max[0], min[1], min[2]); - immVertex3f(pos, min[0], min[1], min[2]); - - /* sides */ - immVertex3f(pos, min[0], min[1], min[2]); - immVertex3f(pos, min[0], min[1], max[2]); - - immVertex3f(pos, min[0], max[1], min[2]); - immVertex3f(pos, min[0], max[1], max[2]); - - immVertex3f(pos, max[0], max[1], min[2]); - immVertex3f(pos, max[0], max[1], max[2]); - - immVertex3f(pos, max[0], min[1], min[2]); - immVertex3f(pos, max[0], min[1], max[2]); - - immEnd(); -} - -/** \} */ - void GPU_pbvh_fix_linking() { } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index a77bba5ab86..8dda98ab990 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -520,9 +520,6 @@ const char *GPU_builtin_name(eGPUBuiltin builtin) else if (builtin == GPU_INVERSE_OBJECT_MATRIX) { return "unfinvobmat"; } - else if (builtin == GPU_INVERSE_NORMAL_MATRIX) { - return "unfinvnormat"; - } else if (builtin == GPU_LOC_TO_VIEW_MATRIX) { return "unflocaltoviewmat"; } @@ -532,6 +529,9 @@ const char *GPU_builtin_name(eGPUBuiltin builtin) else if (builtin == GPU_VIEW_POSITION) { return "varposition"; } + else if (builtin == GPU_WORLD_NORMAL) { + return "varwnormal"; + } else if (builtin == GPU_VIEW_NORMAL) { return "varnormal"; } @@ -786,15 +786,15 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) { BLI_dynstr_append(ds, "objinv"); } - else if (input->builtin == GPU_INVERSE_NORMAL_MATRIX) { - BLI_dynstr_append(ds, "norinv"); - } else if (input->builtin == GPU_VIEW_POSITION) { BLI_dynstr_append(ds, "viewposition"); } else if (input->builtin == GPU_VIEW_NORMAL) { BLI_dynstr_append(ds, "facingnormal"); } + else if (input->builtin == GPU_WORLD_NORMAL) { + BLI_dynstr_append(ds, "facingwnormal"); + } else { BLI_dynstr_append(ds, GPU_builtin_name(input->builtin)); } @@ -879,17 +879,15 @@ static char *code_generate_fragment(GPUMaterial *material, if (builtins & GPU_INVERSE_OBJECT_MATRIX) { BLI_dynstr_append(ds, "\t#define objinv ModelMatrixInverse\n"); } - if (builtins & GPU_INVERSE_NORMAL_MATRIX) { - BLI_dynstr_append(ds, "\t#define norinv NormalMatrixInverse\n"); - } if (builtins & GPU_INVERSE_VIEW_MATRIX) { BLI_dynstr_append(ds, "\t#define viewinv ViewMatrixInverse\n"); } if (builtins & GPU_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, "\t#define localtoviewmat ModelViewMatrix\n"); + BLI_dynstr_append(ds, "\t#define localtoviewmat (ViewMatrix * ModelMatrix)\n"); } if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) { - BLI_dynstr_append(ds, "\t#define invlocaltoviewmat ModelViewMatrixInverse\n"); + BLI_dynstr_append(ds, + "\t#define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n"); } if (builtins & GPU_VIEW_NORMAL) { BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); @@ -897,9 +895,22 @@ static char *code_generate_fragment(GPUMaterial *material, BLI_dynstr_append(ds, "\tworld_normals_get(n);\n"); BLI_dynstr_append(ds, "\tvec3 facingnormal = transform_direction(ViewMatrix, n);\n"); BLI_dynstr_append(ds, "#else\n"); - BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n"); + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n"); BLI_dynstr_append(ds, "#endif\n"); } + if (builtins & GPU_WORLD_NORMAL) { + BLI_dynstr_append(ds, "\tvec3 facingwnormal;\n"); + if (builtins & GPU_VIEW_NORMAL) { + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + BLI_dynstr_append(ds, "\tfacingwnormal = n;\n"); + BLI_dynstr_append(ds, "#else\n"); + BLI_dynstr_append(ds, "\tworld_normals_get(facingwnormal);\n"); + BLI_dynstr_append(ds, "#endif\n"); + } + else { + BLI_dynstr_append(ds, "\tworld_normals_get(facingwnormal);\n"); + } + } if (builtins & GPU_VIEW_POSITION) { BLI_dynstr_append(ds, "\t#define viewposition viewPosition\n"); } @@ -1024,13 +1035,39 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "out vec3 barycentricPosg;\n"); } + BLI_dynstr_append(ds, "\n#define USE_ATTR\n"); + + /* Prototype, defined later (this is because of matrices definition). */ + BLI_dynstr_append(ds, "void pass_attr(in vec3 position);\n"); + + BLI_dynstr_append(ds, "\n"); + + if (use_geom) { + /* XXX HACK: Eevee specific. */ + char *vert_new, *vert_new2; + vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong"); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg"); + MEM_freeN(vert_new2); + + BLI_dynstr_append(ds, vert_new); + + MEM_freeN(vert_new); + } + else { + BLI_dynstr_append(ds, vert_code); + } + BLI_dynstr_append(ds, "\n"); BLI_dynstr_append(ds, "#define USE_ATTR\n" - "uniform mat3 NormalMatrix;\n" - "uniform mat4 ModelMatrixInverse;\n" - "uniform mat4 ModelMatrix;\n" "vec3 srgb_to_linear_attr(vec3 c) {\n" "\tc = max(c, vec3(0.0));\n" "\tvec3 c1 = c * (1.0 / 12.92);\n" @@ -1108,7 +1145,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u if (input->source == GPU_SOURCE_ATTR && input->attr_first) { if (input->attr_type == CD_TANGENT) { /* silly exception */ BLI_dynstr_appendf(ds, - "\tvar%d%s.xyz = NormalMatrix * att%d.xyz;\n", + "\tvar%d%s.xyz = transpose(mat3(ModelMatrixInverse)) * att%d.xyz;\n", input->attr_id, use_geom ? "g" : "", input->attr_id); @@ -1167,28 +1204,6 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "}\n"); - if (use_geom) { - /* XXX HACK: Eevee specific. */ - char *vert_new, *vert_new2; - vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong"); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong"); - MEM_freeN(vert_new2); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg"); - MEM_freeN(vert_new2); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg"); - MEM_freeN(vert_new2); - - BLI_dynstr_append(ds, vert_new); - - MEM_freeN(vert_new); - } - else { - BLI_dynstr_append(ds, vert_code); - } - code = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -1494,7 +1509,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->source = GPU_SOURCE_TEX; input->ima = link->ima; input->iuser = link->iuser; - input->image_isdata = link->image_isdata; break; case GPU_NODE_LINK_ATTR: input->source = GPU_SOURCE_ATTR; @@ -1739,13 +1753,12 @@ GPUNodeLink *GPU_uniform(float *num) return link; } -GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) +GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser) { GPUNodeLink *link = GPU_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_BLENDER; link->ima = ima; link->iuser = iuser; - link->image_isdata = is_data; return link; } diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 73155c3aafa..d1bb3f26920 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -99,7 +99,6 @@ struct GPUNodeLink { struct { struct Image *ima; struct ImageUser *iuser; - bool image_isdata; }; }; }; @@ -137,7 +136,6 @@ typedef struct GPUInput { struct GPUTexture **coba; /* input texture, only set at runtime */ struct Image *ima; /* image */ struct ImageUser *iuser; /* image user */ - bool image_isdata; /* image does not contain color data */ bool bindtex; /* input is responsible for binding the texture? */ int texid; /* number for multitexture, starting from zero */ eGPUType textype; /* texture type (2D, 1D Array ...) */ diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index edc2f2171a5..638729d027c 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -50,6 +50,7 @@ #include "MEM_guardedalloc.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -207,53 +208,231 @@ static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget) return NULL; } -typedef struct VerifyThreadData { - ImBuf *ibuf; - float *srgb_frect; -} VerifyThreadData; +static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, int textarget) +{ + uint bindcode = 0; + const bool mipmap = GPU_get_mipmap(); + +#ifdef WITH_DDS + if (ibuf->ftype == IMB_FTYPE_DDS) { + /* DDS is loaded directly in compressed form. */ + GPU_create_gl_tex_compressed(&bindcode, textarget, ima, ibuf); + return bindcode; + } +#endif + + /* Regular uncompressed texture. */ + float *rect_float = ibuf->rect_float; + uchar *rect = (uchar *)ibuf->rect; + bool compress_as_srgb = false; + + if (rect_float == NULL) { + /* Byte image is in original colorspace from the file. If the file is sRGB + * scene linear, or non-color data no conversion is needed. Otherwise we + * compress as scene linear + sRGB transfer function to avoid precision loss + * in common cases. + * + * We must also convert to premultiplied for correct texture interpolation + * and consistency with float images. */ + if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { + compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace); + + rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__); + if (rect == NULL) { + return bindcode; + } + + IMB_colormanagement_imbuf_to_srgb_texture( + rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb); + } + } + else if (ibuf->channels != 4) { + /* Float image is already in scene linear colorspace or non-color data by + * convention, no colorspace conversion needed. But we do require 4 channels + * currently. */ + rect_float = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__); + if (rect_float == NULL) { + return bindcode; + } + + IMB_buffer_float_from_float(rect_float, + ibuf->rect_float, + ibuf->channels, + IB_PROFILE_LINEAR_RGB, + IB_PROFILE_LINEAR_RGB, + false, + ibuf->x, + ibuf->y, + ibuf->x, + ibuf->x); + } + + /* Create OpenGL texture. */ + GPU_create_gl_tex(&bindcode, + (uint *)rect, + rect_float, + ibuf->x, + ibuf->y, + textarget, + mipmap, + compress_as_srgb, + ima); + + /* Free buffers if needed. */ + if (rect && rect != (uchar *)ibuf->rect) { + MEM_freeN(rect); + } + if (rect_float && rect_float != ibuf->rect_float) { + MEM_freeN(rect_float); + } -static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect, - ImBuf *ibuf, - const int start_line, - const int height) + return bindcode; +} + +static void gpu_texture_update_scaled( + uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h) { - size_t offset = ibuf->channels * start_line * ibuf->x; - float *current_srgb_frect = srgb_frect + offset; - float *current_rect_float = ibuf->rect_float + offset; - IMB_buffer_float_from_float(current_srgb_frect, - current_rect_float, - ibuf->channels, - IB_PROFILE_SRGB, - IB_PROFILE_LINEAR_RGB, - true, - ibuf->x, - height, - ibuf->x, - ibuf->x); - IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height); + /* Partial update with scaling. */ + int limit_w = smaller_power_of_2_limit(full_w); + int limit_h = smaller_power_of_2_limit(full_h); + float xratio = limit_w / (float)full_w; + float yratio = limit_h / (float)full_h; + + /* Find sub coordinates in scaled image. Take ceiling because we will be + * losing 1 pixel due to rounding errors in x,y. */ + int sub_x = x * xratio; + int sub_y = y * yratio; + int sub_w = (int)ceil(xratio * w); + int sub_h = (int)ceil(yratio * h); + + /* ...but take back if we are over the limit! */ + if (sub_w + sub_x > limit_w) { + sub_w--; + } + if (sub_h + sub_y > limit_h) { + sub_h--; + } + + /* Scale pixels. */ + ImBuf *ibuf = IMB_allocFromBuffer((uint *)rect, rect_float, w, h); + IMB_scaleImBuf(ibuf, sub_w, sub_h); + + if (ibuf->rect_float) { + glTexSubImage2D( + GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_FLOAT, ibuf->rect_float); + } + else { + glTexSubImage2D( + GL_TEXTURE_2D, 0, sub_x, sub_y, sub_w, sub_h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + } + + IMB_freeImBuf(ibuf); } -static void verify_thread_do(void *data_v, int start_scanline, int num_scanlines) +static void gpu_texture_update_unscaled( + uchar *rect, float *rect_float, int x, int y, int w, int h, GLint tex_stride, GLint tex_offset) { - VerifyThreadData *data = (VerifyThreadData *)data_v; - gpu_verify_high_bit_srgb_buffer_slice( - data->srgb_frect, data->ibuf, start_scanline, num_scanlines); + /* Partial update without scaling. Stride and offset are used to copy only a + * subset of a possible larger buffer than what we are updating. */ + GLint row_length; + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length); + glPixelStorei(GL_UNPACK_ROW_LENGTH, tex_stride); + + if (rect_float == NULL) { + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset); + } + else { + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); } -static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect, ImBuf *ibuf) +static void gpu_texture_update_from_ibuf(ImBuf *ibuf, int x, int y, int w, int h) { - if (ibuf->y < 64) { - gpu_verify_high_bit_srgb_buffer_slice(srgb_frect, ibuf, 0, ibuf->y); + /* Partial update of texture for texture painting. This is often much + * quicker than fully updating the texture for high resolution images. + * Assumes the OpenGL texture is bound to 0. */ + const bool scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y); + + if (scaled) { + /* Extra padding to account for bleed from neighboring pixels. */ + const int padding = 4; + const int xmax = min_ii(x + w + padding, ibuf->x); + const int ymax = min_ii(y + h + padding, ibuf->y); + x = max_ii(x - padding, 0); + y = max_ii(y - padding, 0); + w = xmax - x; + h = ymax - y; + } + + /* Get texture data pointers. */ + float *rect_float = ibuf->rect_float; + uchar *rect = (uchar *)ibuf->rect; + GLint tex_stride = ibuf->x; + GLint tex_offset = ibuf->channels * (y * ibuf->x + x); + + if (rect_float == NULL) { + /* Byte pixels. */ + if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) { + const bool compress_as_srgb = !IMB_colormanagement_space_is_scene_linear( + ibuf->rect_colorspace); + + rect = MEM_mallocN(sizeof(uchar) * 4 * w * h, __func__); + if (rect == NULL) { + return; + } + + tex_stride = w; + tex_offset = 0; + + /* Convert to scene linear with sRGB compression, and premultiplied for + * correct texture interpolation. */ + IMB_colormanagement_imbuf_to_srgb_texture(rect, x, y, w, h, ibuf, compress_as_srgb); + } + } + else if (ibuf->channels != 4 || scaled) { + /* Float pixels. */ + rect_float = MEM_mallocN(sizeof(float) * 4 * x * y, __func__); + if (rect_float == NULL) { + return; + } + + tex_stride = w; + tex_offset = 0; + + size_t ibuf_offset = (y * ibuf->x + x) * ibuf->channels; + IMB_buffer_float_from_float(rect_float, + ibuf->rect_float + ibuf_offset, + ibuf->channels, + IB_PROFILE_LINEAR_RGB, + IB_PROFILE_LINEAR_RGB, + false, + w, + h, + x, + ibuf->x); + } + + if (scaled) { + /* Slower update where we first have to scale the input pixels. */ + gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h); } else { - VerifyThreadData data; - data.ibuf = ibuf; - data.srgb_frect = srgb_frect; - IMB_processor_apply_threaded_scanlines(ibuf->y, verify_thread_do, &data); + /* Fast update at same resolution. */ + gpu_texture_update_unscaled(rect, rect_float, x, y, w, h, tex_stride, tex_offset); + } + + /* Free buffers if needed. */ + if (rect && rect != (uchar *)ibuf->rect) { + MEM_freeN(rect); + } + if (rect_float && rect_float != ibuf->rect_float) { + MEM_freeN(rect_float); } } -GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data) +GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget) { if (ima == NULL) { return NULL; @@ -286,62 +465,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget return *tex; } - /* flag to determine whether deep format is used */ - bool use_high_bit_depth = false, do_color_management = false; - - if (ibuf->rect_float) { - use_high_bit_depth = true; - - /* TODO unneeded when float images are correctly treated as linear always */ - if (!is_data) { - do_color_management = true; - } - } - - const int rectw = ibuf->x; - const int recth = ibuf->y; - uint *rect = ibuf->rect; - float *frect = NULL; - float *srgb_frect = NULL; - - if (use_high_bit_depth) { - if (do_color_management) { - frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, - "floar_buf_col_cor"); - gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf); - } - else { - frect = ibuf->rect_float; - } - } - - const bool mipmap = GPU_get_mipmap(); - -#ifdef WITH_DDS - if (ibuf->ftype == IMB_FTYPE_DDS) { - GPU_create_gl_tex_compressed(&bindcode, rect, rectw, recth, textarget, mipmap, ima, ibuf); - } - else -#endif - { - GPU_create_gl_tex( - &bindcode, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima); - } - - /* mark as non-color data texture */ - if (bindcode) { - if (is_data) { - ima->gpuflag |= IMA_GPU_IS_DATA; - } - else { - ima->gpuflag &= ~IMA_GPU_IS_DATA; - } - } - - /* clean up */ - if (srgb_frect) { - MEM_freeN(srgb_frect); - } + bindcode = gpu_texture_create_from_ibuf(ima, ibuf, textarget); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -349,15 +473,14 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget return *tex; } -static void **gpu_gen_cube_map( - uint *rect, float *frect, int rectw, int recth, bool use_high_bit_depth) +static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth) { - size_t block_size = use_high_bit_depth ? sizeof(float[4]) : sizeof(uchar[4]); + size_t block_size = frect ? sizeof(float[4]) : sizeof(uchar[4]); void **sides = NULL; int h = recth / 2; int w = rectw / 3; - if ((use_high_bit_depth && frect == NULL) || (!use_high_bit_depth && rect == NULL) || w != h) { + if (w != h) { return sides; } @@ -376,7 +499,7 @@ static void **gpu_gen_cube_map( * | NegZ | PosZ | PosY | * |______|______|______| */ - if (use_high_bit_depth) { + if (frect) { float(*frectb)[4] = (float(*)[4])frect; float(**fsides)[4] = (float(**)[4])sides; @@ -430,7 +553,7 @@ void GPU_create_gl_tex(uint *bind, int recth, int textarget, bool mipmap, - bool use_high_bit_depth, + bool use_srgb, Image *ima) { ImBuf *ibuf = NULL; @@ -441,7 +564,7 @@ void GPU_create_gl_tex(uint *bind, rectw = smaller_power_of_2_limit(rectw); recth = smaller_power_of_2_limit(recth); - if (use_high_bit_depth) { + if (frect) { ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); IMB_scaleImBuf(ibuf, rectw, recth); @@ -459,12 +582,15 @@ void GPU_create_gl_tex(uint *bind, glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); + GLenum internal_format = (frect) ? GL_RGBA16F : (use_srgb) ? GL_SRGB8_ALPHA8 : GL_RGBA8; + if (textarget == GL_TEXTURE_2D) { - if (use_high_bit_depth) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + if (frect) { + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); + glTexImage2D( + GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); @@ -484,15 +610,14 @@ void GPU_create_gl_tex(uint *bind, int w = rectw / 3, h = recth / 2; if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) { - void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth); - GLenum informat = use_high_bit_depth ? GL_RGBA16F : GL_RGBA8; - GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE; + void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth); + GLenum type = frect ? GL_FLOAT : GL_UNSIGNED_BYTE; if (cube_map) { for (int i = 0; i < 6; i++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, - informat, + internal_format, w, h, 0, @@ -542,7 +667,7 @@ void GPU_create_gl_tex(uint *bind, * This is so the viewport and the BGE can share some code. * Returns false if the provided ImBuf doesn't have a supported DXT compression format */ -bool GPU_upload_dxt_texture(ImBuf *ibuf) +bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb) { #ifdef WITH_DDS GLint format = 0; @@ -553,13 +678,16 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) if (GLEW_EXT_texture_compression_s3tc) { if (ibuf->dds_data.fourcc == FOURCC_DXT1) { - format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : + GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; } else if (ibuf->dds_data.fourcc == FOURCC_DXT3) { - format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; } else if (ibuf->dds_data.fourcc == FOURCC_DXT5) { - format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } } @@ -606,25 +734,30 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) return true; #else - (void)ibuf; + UNUSED_VARS(ibuf, use_srgb); return false; #endif } -void GPU_create_gl_tex_compressed( - uint *bind, uint *pix, int x, int y, int textarget, int mipmap, Image *ima, ImBuf *ibuf) +void GPU_create_gl_tex_compressed(unsigned int *bind, int textarget, Image *ima, ImBuf *ibuf) { + /* For DDS we only support data, scene linear and sRGB. Converting to + * different colorspace would break the compression. */ + const bool use_srgb = !(IMB_colormanagement_space_is_data(ibuf->rect_colorspace) || + IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)); + const bool mipmap = GPU_get_mipmap(); + #ifndef WITH_DDS (void)ibuf; /* Fall back to uncompressed if DDS isn't enabled */ - GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima); + GPU_create_gl_tex(bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, use_srgb, ima); #else glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); - if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf) == 0) { + if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf, use_srgb) == 0) { glDeleteTextures(1, (GLuint *)bind); - GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima); + GPU_create_gl_tex(bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, use_srgb, ima); } glBindTexture(textarget, 0); @@ -680,146 +813,20 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) } } -/* check if image has been downscaled and do scaled partial update */ -static bool gpu_check_scaled_image( - ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) -{ - if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) { - int x_limit = smaller_power_of_2_limit(ibuf->x); - int y_limit = smaller_power_of_2_limit(ibuf->y); - - float xratio = x_limit / (float)ibuf->x; - float yratio = y_limit / (float)ibuf->y; - - /* find new width, height and x,y gpu texture coordinates */ - - /* take ceiling because we will be losing 1 pixel due to rounding errors in x,y... */ - int rectw = (int)ceil(xratio * w); - int recth = (int)ceil(yratio * h); - - x *= xratio; - y *= yratio; - - /* ...but take back if we are over the limit! */ - if (rectw + x > x_limit) { - rectw--; - } - if (recth + y > y_limit) { - recth--; - } - - GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0); - - /* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */ - if (frect) { - ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h); - IMB_scaleImBuf(ibuf_scale, rectw, recth); - - glTexSubImage2D( - GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA, GL_FLOAT, ibuf_scale->rect_float); - - IMB_freeImBuf(ibuf_scale); - } - /* byte images are not continuous in memory so do manual interpolation */ - else { - uchar *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect"); - uint *p = (uint *)scalerect; - int i, j; - float inv_xratio = 1.0f / xratio; - float inv_yratio = 1.0f / yratio; - for (i = 0; i < rectw; i++) { - float u = (x + i) * inv_xratio; - for (j = 0; j < recth; j++) { - float v = (y + j) * inv_yratio; - bilinear_interpolation_color_wrap(ibuf, (uchar *)(p + i + j * (rectw)), NULL, u, v); - } - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, scalerect); - - MEM_freeN(scalerect); - } - - if (GPU_get_mipmap()) { - glGenerateMipmap(GL_TEXTURE_2D); - } - else { - ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; - } - - GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]); - - return true; - } - - return false; -} - void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if ((ima->gputexture[TEXTARGET_TEXTURE_2D] == NULL) || (ibuf == NULL) || (w == 0) || (h == 0)) { - /* these cases require full reload still */ + /* Full reload of texture. */ GPU_free_image(ima); } else { - /* for the special case, we can do a partial update - * which is much quicker for painting */ - GLint row_length, skip_pixels, skip_rows; - - /* if color correction is needed, we must update the part that needs updating. */ - if (ibuf->rect_float) { - float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf"); - bool is_data = (ima->gpuflag & IMA_GPU_IS_DATA) != 0; - IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - - if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { - MEM_freeN(buffer); - BKE_image_release_ibuf(ima, ibuf, NULL); - return; - } - - GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer); - - MEM_freeN(buffer); - - if (GPU_get_mipmap()) { - glGenerateMipmap(GL_TEXTURE_2D); - } - else { - ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE; - } - - GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]); - - BKE_image_release_ibuf(ima, ibuf, NULL); - return; - } - - if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - return; - } - + /* Partial update of texture. */ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0); - glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length); - glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels); - glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); - glPixelStorei(GL_UNPACK_SKIP_ROWS, y); - - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); + gpu_texture_update_from_ibuf(ibuf, x, y, w, h); - /* see comment above as to why we are using gpu mipmap generation here */ if (GPU_get_mipmap()) { glGenerateMipmap(GL_TEXTURE_2D); } @@ -1242,7 +1249,7 @@ static void gpu_free_image_immediate(Image *ima) } } - ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE | IMA_GPU_IS_DATA); + ima->gpuflag &= ~(IMA_GPU_MIPMAP_COMPLETE); } void GPU_free_image(Image *ima) diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 1a668a48eed..fde60fd387d 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -36,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BKE_main.h" #include "BKE_node.h" @@ -125,7 +126,6 @@ struct GPUMaterial { enum { GPU_DOMAIN_SURFACE = (1 << 0), GPU_DOMAIN_VOLUME = (1 << 1), - GPU_DOMAIN_SSS = (1 << 2), }; /* Functions */ @@ -231,6 +231,12 @@ ListBase *GPU_material_get_inputs(GPUMaterial *material) return &material->inputs; } +/* Return can be NULL if it's a world material. */ +Material *GPU_material_get_material(GPUMaterial *material) +{ + return material->ma; +} + GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material) { return material->ubo; @@ -597,15 +603,6 @@ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) /* Code generation */ -bool GPU_material_do_color_management(GPUMaterial *mat) -{ - if (!BKE_scene_check_color_management_enabled(mat->scene)) { - return false; - } - - return true; -} - bool GPU_material_use_domain_surface(GPUMaterial *mat) { return (mat->domain & GPU_DOMAIN_SURFACE); @@ -646,6 +643,7 @@ GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials, * so only do this when they are needed. */ GPUMaterial *GPU_material_from_nodetree(Scene *scene, + struct Material *ma, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, @@ -664,6 +662,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, /* allocate material */ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); + mat->ma = ma; mat->scene = scene; mat->engine_type = engine_type; mat->options = options; @@ -679,14 +678,14 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, gpu_material_ramp_texture_build(mat); - if (has_surface_output) { - mat->domain |= GPU_DOMAIN_SURFACE; - } - if (has_volume_output) { - mat->domain |= GPU_DOMAIN_VOLUME; - } + SET_FLAG_FROM_TEST(mat->domain, has_surface_output, GPU_DOMAIN_SURFACE); + SET_FLAG_FROM_TEST(mat->domain, has_volume_output, GPU_DOMAIN_VOLUME); if (mat->outlink) { + /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */ + if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) { + defines = BLI_string_joinN(defines, "#define USE_SSS\n"); + } /* Prune the unused nodes and extract attributes before compiling so the * generated VBOs are ready to accept the future shader. */ GPU_nodes_prune(&mat->nodes, mat->outlink); @@ -702,6 +701,10 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, frag_lib, defines); + if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) { + MEM_freeN((char *)defines); + } + if (mat->pass == NULL) { /* We had a cache hit and the shader has already failed to compile. */ mat->status = GPU_MAT_FAILED; diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 5d65861c1e2..cc89da19705 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -502,19 +502,13 @@ static void gpu_mul_invert_projmat_m4_unmapped_v3(const float projmat[4][4], flo co[2] *= -1; } -bool GPU_matrix_unproject(const float win[3], - const float model[4][4], - const float proj[4][4], - const int view[4], - float world[3]) +void GPU_matrix_unproject_model_inverted(const float win[3], + const float model_inverted[4][4], + const float proj[4][4], + const int view[4], + float world[3]) { float in[3]; - float viewinv[4][4]; - - if (!invert_m4_m4(viewinv, model)) { - zero_v3(world); - return false; - } copy_v3_v3(in, win); @@ -523,8 +517,22 @@ bool GPU_matrix_unproject(const float win[3], in[1] = (in[1] - view[1]) / view[3]; gpu_mul_invert_projmat_m4_unmapped_v3(proj, in); - mul_v3_m4v3(world, viewinv, in); + mul_v3_m4v3(world, model_inverted, in); +} +bool GPU_matrix_unproject(const float win[3], + const float model[4][4], + const float proj[4][4], + const int view[4], + float world[3]) +{ + float model_inverted[4][4]; + + if (!invert_m4_m4(model_inverted, model)) { + zero_v3(world); + return false; + } + GPU_matrix_unproject_model_inverted(win, model_inverted, proj, view, world); return true; } diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 010087e5536..119aed2f5ed 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -229,12 +229,18 @@ void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_ const int dst_x = BLI_rcti_size_x(dst); const int dst_y = BLI_rcti_size_y(dst); - int last_px_written = dst_x * dst_y - 1; int last_px_id = src_x * (y + dst_y - 1) + (x + dst_x - 1); - const int skip = src_x - dst_x; - memset(&r_buf[last_px_id + 1], 0, (src_x * src_y - (last_px_id + 1)) * sizeof(*r_buf)); + if (last_px_id < 0) { + /* Nothing to write. */ + BLI_assert(last_px_id == -1); + return; + } + + int last_px_written = dst_x * dst_y - 1; + const int skip = src_x - dst_x; + while (true) { for (int i = dst_x; i--;) { r_buf[last_px_id--] = r_buf[last_px_written--]; diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 3fbc24d6089..56f9ef69221 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -104,8 +104,11 @@ void gpu_select_query_begin( /* occlusion queries operates on fragments that pass tests and since we are interested on all * objects in the view frustum independently of their order, we need to disable the depth test */ if (mode == GPU_SELECT_ALL) { - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); + /* glQueries on Windows+Intel drivers only works with depth testing turned on. + * See T62947 for details */ + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); } else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { glClear(GL_DEPTH_BUFFER_BIT); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 3d5b0dda5e4..7201025ad8a 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -145,17 +145,8 @@ extern char datatoc_gpu_shader_selection_id_frag_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[]; -extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl[]; extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl[]; -extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[]; -extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[]; -extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[]; -extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[]; -extern char datatoc_gpu_shader_edges_overlay_vert_glsl[]; -extern char datatoc_gpu_shader_edges_overlay_geom_glsl[]; -extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[]; -extern char datatoc_gpu_shader_edges_overlay_frag_glsl[]; extern char datatoc_gpu_shader_text_vert_glsl[]; extern char datatoc_gpu_shader_text_geom_glsl[]; extern char datatoc_gpu_shader_text_frag_glsl[]; @@ -729,23 +720,28 @@ void GPU_shader_uniform_vector( return; } - if (length == 1) { - glUniform1fv(location, arraysize, value); - } - else if (length == 2) { - glUniform2fv(location, arraysize, value); - } - else if (length == 3) { - glUniform3fv(location, arraysize, value); - } - else if (length == 4) { - glUniform4fv(location, arraysize, value); - } - else if (length == 9) { - glUniformMatrix3fv(location, arraysize, 0, value); - } - else if (length == 16) { - glUniformMatrix4fv(location, arraysize, 0, value); + switch (length) { + case 1: + glUniform1fv(location, arraysize, value); + break; + case 2: + glUniform2fv(location, arraysize, value); + break; + case 3: + glUniform3fv(location, arraysize, value); + break; + case 4: + glUniform4fv(location, arraysize, value); + break; + case 9: + glUniformMatrix3fv(location, arraysize, 0, value); + break; + case 16: + glUniformMatrix4fv(location, arraysize, 0, value); + break; + default: + BLI_assert(0); + break; } } @@ -756,17 +752,22 @@ void GPU_shader_uniform_vector_int( return; } - if (length == 1) { - glUniform1iv(location, arraysize, value); - } - else if (length == 2) { - glUniform2iv(location, arraysize, value); - } - else if (length == 3) { - glUniform3iv(location, arraysize, value); - } - else if (length == 4) { - glUniform4iv(location, arraysize, value); + switch (length) { + case 1: + glUniform1iv(location, arraysize, value); + break; + case 2: + glUniform2iv(location, arraysize, value); + break; + case 3: + glUniform3iv(location, arraysize, value); + break; + case 4: + glUniform4iv(location, arraysize, value); + break; + default: + BLI_assert(0); + break; } } @@ -832,30 +833,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_keyframe_diamond_vert_glsl, .frag = datatoc_gpu_shader_keyframe_diamond_frag_glsl, }, - /* This version is magical but slow! */ - [GPU_SHADER_EDGES_FRONT_BACK_PERSP] = - { - .vert = datatoc_gpu_shader_edges_front_back_persp_vert_glsl, - .geom = datatoc_gpu_shader_edges_front_back_persp_geom_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] = - { - .vert = datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_EDGES_OVERLAY_SIMPLE] = - { - .vert = datatoc_gpu_shader_3D_vert_glsl, - .geom = datatoc_gpu_shader_edges_overlay_simple_geom_glsl, - .frag = datatoc_gpu_shader_edges_overlay_frag_glsl, - }, - [GPU_SHADER_EDGES_OVERLAY] = - { - .vert = datatoc_gpu_shader_edges_overlay_vert_glsl, - .geom = datatoc_gpu_shader_edges_overlay_geom_glsl, - .frag = datatoc_gpu_shader_edges_overlay_frag_glsl, - }, [GPU_SHADER_SIMPLE_LIGHTING] = { .vert = datatoc_gpu_shader_3D_normal_vert_glsl, @@ -1322,28 +1299,8 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, GPUShader **sh_p = &builtin_shaders[sh_cfg][shader]; if (*sh_p == NULL) { - GPUShaderStages stages_legacy = {NULL}; const GPUShaderStages *stages = &builtin_shader_stages[shader]; - if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP) { - /* TODO: remove after switch to core profile (maybe) */ - if (!GLEW_VERSION_3_2) { - stages_legacy.vert = datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl; - stages_legacy.frag = datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl; - stages = &stages_legacy; - } - } - else if (shader == GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR) { - /* Dashed need geometry shader, which are not supported by legacy OpenGL, - * fallback to solid lines. */ - /* TODO: remove after switch to core profile (maybe) */ - if (!GLEW_VERSION_3_2) { - stages_legacy.vert = datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl; - stages_legacy.frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl; - stages = &stages_legacy; - } - } - /* common case */ if (sh_cfg == GPU_SHADER_CFG_DEFAULT) { *sh_p = GPU_shader_create( diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 698499af1ab..3993ee4df24 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -61,13 +61,9 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse", [GPU_UNIFORM_NORMAL] = "NormalMatrix", - [GPU_UNIFORM_NORMAL_INV] = "NormalMatrixInverse", - [GPU_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix", - [GPU_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors", [GPU_UNIFORM_ORCO] = "OrcoTexCoFactors", [GPU_UNIFORM_COLOR] = "color", - [GPU_UNIFORM_EYE] = "eye", [GPU_UNIFORM_CALLID] = "callId", [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo", diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 61f86e70898..58d0dd5576f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -544,6 +544,8 @@ static bool gpu_texture_check_capacity( return false; } ATTR_FALLTHROUGH; + default: + break; } return true; @@ -1079,7 +1081,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) /* this binds a texture, so that's why we restore it to 0 */ if (bindcode == 0) { GPU_create_gl_tex( - &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, 0, NULL); + &bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, false, NULL); } if (tex) { tex->bindcode = bindcode; diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c index f9823c18723..2f854fe03ea 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.c +++ b/source/blender/gpu/intern/gpu_vertex_buffer.c @@ -85,17 +85,24 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, } } -void GPU_vertbuf_discard(GPUVertBuf *verts) +/** Same as discard but does not free. */ +void GPU_vertbuf_clear(GPUVertBuf *verts) { if (verts->vbo_id) { GPU_buf_free(verts->vbo_id); + verts->vbo_id = 0; #if VRAM_USAGE vbo_memory_usage -= GPU_vertbuf_size_get(verts); #endif } if (verts->data) { - MEM_freeN(verts->data); + MEM_SAFE_FREE(verts->data); } +} + +void GPU_vertbuf_discard(GPUVertBuf *verts) +{ + GPU_vertbuf_clear(verts); MEM_freeN(verts); } diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index 388773afbbc..37e1f9cf9da 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -58,12 +58,6 @@ void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src) { /* copy regular struct fields */ memcpy(dest, src, sizeof(GPUVertFormat)); - - for (uint i = 0; i < dest->attr_len; i++) { - for (uint j = 0; j < dest->attrs[i].name_len; j++) { - dest->attrs[i].name[j] = (char *)dest + (src->attrs[i].name[j] - ((char *)src)); - } - } } static GLenum convert_comp_type_to_gl(GPUVertCompType type) @@ -122,32 +116,20 @@ uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len) return format->stride * vertex_len; } -static const char *copy_attr_name(GPUVertFormat *format, const char *name, const char *suffix) +static uchar copy_attr_name(GPUVertFormat *format, const char *name) { /* strncpy does 110% of what we need; let's do exactly 100% */ - char *name_copy = format->names + format->name_offset; - uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - format->name_offset; + uchar name_offset = format->name_offset; + char *name_copy = format->names + name_offset; + uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - name_offset; bool terminated = false; for (uint i = 0; i < available; ++i) { const char c = name[i]; name_copy[i] = c; if (c == '\0') { - if (suffix) { - for (uint j = 0; j < available; ++j) { - const char s = suffix[j]; - name_copy[i + j] = s; - if (s == '\0') { - terminated = true; - format->name_offset += (i + j + 1); - break; - } - } - } - else { - terminated = true; - format->name_offset += (i + 1); - } + terminated = true; + format->name_offset += (i + 1); break; } } @@ -157,7 +139,7 @@ static const char *copy_attr_name(GPUVertFormat *format, const char *name, const #else (void)terminated; #endif - return name_copy; + return name_offset; } uint GPU_vertformat_attr_add(GPUVertFormat *format, @@ -196,7 +178,7 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format, const uint attr_id = format->attr_len++; GPUVertAttr *attr = &format->attrs[attr_id]; - attr->name[attr->name_len++] = copy_attr_name(format, name, NULL); + attr->names[attr->name_len++] = copy_attr_name(format, name); attr->comp_type = comp_type; attr->gl_comp_type = convert_comp_type_to_gl(comp_type); attr->comp_len = (comp_type == GPU_COMP_I10) ? @@ -217,7 +199,7 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias) assert(attr->name_len < GPU_VERT_ATTR_MAX_NAMES); #endif format->name_len++; /* multiname support */ - attr->name[attr->name_len++] = copy_attr_name(format, alias, NULL); + attr->names[attr->name_len++] = copy_attr_name(format, alias); } int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name) @@ -225,7 +207,8 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name) for (int i = 0; i < format->attr_len; i++) { const GPUVertAttr *attr = &format->attrs[i]; for (int j = 0; j < attr->name_len; j++) { - if (STREQ(name, attr->name[j])) { + const char *attr_name = GPU_vertformat_attr_name_get(format, attr, j); + if (STREQ(name, attr_name)) { return i; } } @@ -233,41 +216,6 @@ int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name) return -1; } -void GPU_vertformat_triple_load(GPUVertFormat *format) -{ -#if TRUST_NO_ONE - assert(!format->packed); - assert(format->attr_len * 3 < GPU_VERT_ATTR_MAX_LEN); - assert(format->name_len + format->attr_len * 3 < GPU_VERT_ATTR_MAX_LEN); -#endif - - VertexFormat_pack(format); - - uint old_attr_len = format->attr_len; - for (uint a_idx = 0; a_idx < old_attr_len; ++a_idx) { - GPUVertAttr *attr = &format->attrs[a_idx]; - /* Duplicate attr twice */ - for (int i = 1; i < 3; ++i) { - GPUVertAttr *dst_attr = &format->attrs[format->attr_len]; - memcpy(dst_attr, attr, sizeof(GPUVertAttr)); - /* Increase offset to the next vertex. */ - dst_attr->offset += format->stride * i; - /* Only copy first name for now. */ - dst_attr->name_len = 0; - dst_attr->name[dst_attr->name_len++] = copy_attr_name( - format, attr->name[0], (i == 1) ? "1" : "2"); - format->attr_len++; - } - -#if TRUST_NO_ONE - assert(attr->name_len < GPU_VERT_ATTR_MAX_NAMES); -#endif - /* Add alias to first attr. */ - format->name_len++; - attr->name[attr->name_len++] = copy_attr_name(format, attr->name[0], "0"); - } -} - uint padding(uint offset, uint alignment) { const uint mod = offset % alignment; @@ -364,7 +312,6 @@ static uint calc_input_component_size(const GPUShaderInput *input) static void get_fetch_mode_and_comp_type(int gl_type, GPUVertCompType *r_comp_type, - uint *r_gl_comp_type, GPUVertFetchMode *r_fetch_mode) { switch (gl_type) { @@ -382,7 +329,6 @@ static void get_fetch_mode_and_comp_type(int gl_type, case GL_FLOAT_MAT4x2: case GL_FLOAT_MAT4x3: *r_comp_type = GPU_COMP_F32; - *r_gl_comp_type = GL_FLOAT; *r_fetch_mode = GPU_FETCH_FLOAT; break; case GL_INT: @@ -390,7 +336,6 @@ static void get_fetch_mode_and_comp_type(int gl_type, case GL_INT_VEC3: case GL_INT_VEC4: *r_comp_type = GPU_COMP_I32; - *r_gl_comp_type = GL_INT; *r_fetch_mode = GPU_FETCH_INT; break; case GL_UNSIGNED_INT: @@ -398,7 +343,6 @@ static void get_fetch_mode_and_comp_type(int gl_type, case GL_UNSIGNED_INT_VEC3: case GL_UNSIGNED_INT_VEC4: *r_comp_type = GPU_COMP_U32; - *r_gl_comp_type = GL_UNSIGNED_INT; *r_fetch_mode = GPU_FETCH_INT; break; default: @@ -424,15 +368,19 @@ void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterfa format->name_len++; /* multiname support */ format->attr_len++; + GPUVertCompType comp_type; + GPUVertFetchMode fetch_mode; + get_fetch_mode_and_comp_type(input->gl_type, &comp_type, &fetch_mode); + GPUVertAttr *attr = &format->attrs[input->location]; - attr->name[attr->name_len++] = copy_attr_name( - format, name_buffer + input->name_offset, NULL); + attr->names[attr->name_len++] = copy_attr_name(format, name_buffer + input->name_offset); attr->offset = 0; /* offsets & stride are calculated later (during pack) */ attr->comp_len = calc_input_component_size(input); attr->sz = attr->comp_len * 4; - get_fetch_mode_and_comp_type( - input->gl_type, &attr->comp_type, &attr->gl_comp_type, &attr->fetch_mode); + attr->fetch_mode = fetch_mode; + attr->comp_type = comp_type; + attr->gl_comp_type = convert_comp_type_to_gl(comp_type); } } } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 558b3f025a8..4fd439f4203 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -27,7 +27,7 @@ #include "BLI_listbase.h" #include "BLI_rect.h" -#include "BLI_mempool.h" +#include "BLI_memblock.h" #include "BIF_gl.h" @@ -48,6 +48,8 @@ static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *); static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *); +#define MAX_ENABLE_ENGINE 8 + /* Maximum number of simultaneous engine enabled at the same time. * Setting it lower than the real number will do lead to * higher VRAM usage due to sub-efficient buffer reuse. */ @@ -64,8 +66,11 @@ struct GPUViewport { int samples; int flag; - ListBase data; /* ViewportEngineData wrapped in LinkData */ - uint data_hash; /* If hash mismatch we free all ViewportEngineData in this viewport */ + /* If engine_handles mismatch we free all ViewportEngineData in this viewport */ + struct { + void *handle; + ViewportEngineData *data; + } engine_data[MAX_ENABLE_ENGINE]; DefaultFramebufferList *fbl; DefaultTextureList *txl; @@ -172,7 +177,6 @@ void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) { - LinkData *ld = MEM_callocN(sizeof(LinkData), "LinkData"); ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData"); int fbl_len, txl_len, psl_len, stl_len; @@ -185,20 +189,25 @@ void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList"); data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList"); - ld->data = data; - BLI_addtail(&viewport->data, ld); + for (int i = 0; i < MAX_ENABLE_ENGINE; i++) { + if (viewport->engine_data[i].handle == NULL) { + viewport->engine_data[i].handle = engine_type; + viewport->engine_data[i].data = data; + return data; + } + } - return data; + BLI_assert(!"Too many draw engines enabled at the same time"); + return NULL; } static void gpu_viewport_engines_data_free(GPUViewport *viewport) { int fbl_len, txl_len, psl_len, stl_len; - LinkData *next; - for (LinkData *link = viewport->data.first; link; link = next) { - next = link->next; - ViewportEngineData *data = link->data; + for (int i = 0; i < MAX_ENABLE_ENGINE && viewport->engine_data[i].handle; i++) { + ViewportEngineData *data = viewport->engine_data[i].data; + DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); @@ -219,19 +228,20 @@ static void gpu_viewport_engines_data_free(GPUViewport *viewport) MEM_freeN(data); - BLI_remlink(&viewport->data, link); - MEM_freeN(link); + /* Mark as unused*/ + viewport->engine_data[i].handle = NULL; } gpu_viewport_texture_pool_free(viewport); } -void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type) +void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_handle) { - for (LinkData *link = viewport->data.first; link; link = link->next) { - ViewportEngineData *vdata = link->data; - if (vdata->engine_type == engine_type) { - return vdata; + BLI_assert(engine_handle != NULL); + + for (int i = 0; i < MAX_ENABLE_ENGINE; i++) { + if (viewport->engine_data[i].handle == engine_handle) { + return viewport->engine_data[i].data; } } return NULL; @@ -352,24 +362,22 @@ static void gpu_viewport_texture_pool_free(GPUViewport *viewport) BLI_freelistN(&viewport->tex_pool); } -bool GPU_viewport_engines_data_validate(GPUViewport *viewport, uint hash) +/* Takes an NULL terminated array of engine_handle. Returns true is data is still valid. */ +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, void **engine_handle_array) { - bool dirty = false; - - if (viewport->data_hash != hash) { - gpu_viewport_engines_data_free(viewport); - dirty = true; + for (int i = 0; i < MAX_ENABLE_ENGINE && engine_handle_array[i]; i++) { + if (viewport->engine_data[i].handle != engine_handle_array[i]) { + gpu_viewport_engines_data_free(viewport); + return false; + } } - - viewport->data_hash = hash; - - return dirty; + return true; } void GPU_viewport_cache_release(GPUViewport *viewport) { - for (LinkData *link = viewport->data.first; link; link = link->next) { - ViewportEngineData *data = link->data; + for (int i = 0; i < MAX_ENABLE_ENGINE && viewport->engine_data[i].handle; i++) { + ViewportEngineData *data = viewport->engine_data[i].data; int psl_len; DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL); gpu_viewport_passes_free(data->psl, psl_len); @@ -468,8 +476,8 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) (TextureList *)viewport->txl, default_txl_len); - for (LinkData *link = viewport->data.first; link; link = link->next) { - ViewportEngineData *data = link->data; + for (int i = 0; i < MAX_ENABLE_ENGINE && viewport->engine_data[i].handle; i++) { + ViewportEngineData *data = viewport->engine_data[i].data; DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL); gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); } @@ -593,13 +601,7 @@ static void gpu_viewport_storage_free(StorageList *stl, int stl_len) static void gpu_viewport_passes_free(PassList *psl, int psl_len) { - for (int i = 0; i < psl_len; i++) { - struct DRWPass *pass = psl->passes[i]; - if (pass) { - DRW_pass_free(pass); - psl->passes[i] = NULL; - } - } + memset(psl, 0, sizeof(struct DRWPass *) * psl_len); } /* Must be executed inside Drawmanager Opengl Context. */ @@ -618,28 +620,34 @@ void GPU_viewport_free(GPUViewport *viewport) MEM_freeN(viewport->txl); if (viewport->vmempool.calls != NULL) { - BLI_mempool_destroy(viewport->vmempool.calls); + BLI_memblock_destroy(viewport->vmempool.calls, NULL); } if (viewport->vmempool.states != NULL) { - BLI_mempool_destroy(viewport->vmempool.states); + BLI_memblock_destroy(viewport->vmempool.states, NULL); + } + if (viewport->vmempool.cullstates != NULL) { + BLI_memblock_destroy(viewport->vmempool.cullstates, NULL); } if (viewport->vmempool.shgroups != NULL) { - BLI_mempool_destroy(viewport->vmempool.shgroups); + BLI_memblock_destroy(viewport->vmempool.shgroups, NULL); } if (viewport->vmempool.uniforms != NULL) { - BLI_mempool_destroy(viewport->vmempool.uniforms); + BLI_memblock_destroy(viewport->vmempool.uniforms, NULL); + } + if (viewport->vmempool.views != NULL) { + BLI_memblock_destroy(viewport->vmempool.views, NULL); } if (viewport->vmempool.passes != NULL) { - BLI_mempool_destroy(viewport->vmempool.passes); + BLI_memblock_destroy(viewport->vmempool.passes, NULL); } if (viewport->vmempool.images != NULL) { - BLI_mempool_iter iter; + BLI_memblock_iter iter; GPUTexture **tex; - BLI_mempool_iternew(viewport->vmempool.images, &iter); - while ((tex = BLI_mempool_iterstep(&iter))) { + BLI_memblock_iternew(viewport->vmempool.images, &iter); + while ((tex = BLI_memblock_iterstep(&iter))) { GPU_texture_free(*tex); } - BLI_mempool_destroy(viewport->vmempool.images); + BLI_memblock_destroy(viewport->vmempool.images, NULL); } DRW_instance_data_list_free(viewport->idatalist); diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl deleted file mode 100644 index a71dfba575b..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl +++ /dev/null @@ -1,54 +0,0 @@ - -// Draw "fancy" wireframe, displaying front-facing, back-facing and -// silhouette lines differently. -// Mike Erwin, April 2015 - -uniform bool drawFront = true; -uniform bool drawBack = true; -uniform bool drawSilhouette = true; - -uniform vec4 frontColor; -uniform vec4 backColor; -uniform vec4 silhouetteColor; - -uniform vec3 eye; // direction we are looking - -uniform mat4 ModelViewProjectionMatrix; - -in vec3 pos; - -// normals of faces this edge joins (object coords) -in vec3 N1; -in vec3 N2; - -flat out vec4 finalColor; - -// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley - -// to discard an entire line, set both endpoints to nowhere -// and it won't produce any fragments -const vec4 nowhere = vec4(vec3(0.0), 1.0); - -void main() -{ - bool face_1_front = dot(N1, eye) > 0.0; - bool face_2_front = dot(N2, eye) > 0.0; - - vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0); - - if (face_1_front && face_2_front) { - // front-facing edge - gl_Position = drawFront ? position : nowhere; - finalColor = frontColor; - } - else if (face_1_front || face_2_front) { - // exactly one face is front-facing, silhouette edge - gl_Position = drawSilhouette ? position : nowhere; - finalColor = silhouetteColor; - } - else { - // back-facing edge - gl_Position = drawBack ? position : nowhere; - finalColor = backColor; - } -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl deleted file mode 100644 index 3de14704781..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl +++ /dev/null @@ -1,60 +0,0 @@ - -// Draw "fancy" wireframe, displaying front-facing, back-facing and -// silhouette lines differently. -// Mike Erwin, April 2015 - -// After working with this shader a while, convinced we should make -// separate shaders for perpective & ortho. (Oct 2016) - -// Due to perspective, the line segment's endpoints might disagree on -// whether the adjacent faces are front facing. This geometry shader -// decides which edge type to use if endpoints disagree. - -uniform mat4 ProjectionMatrix; - -uniform bool drawFront = true; -uniform bool drawBack = true; -uniform bool drawSilhouette = true; - -uniform vec4 frontColor; -uniform vec4 backColor; -uniform vec4 silhouetteColor; - -layout(lines) in; -layout(line_strip, max_vertices = 2) out; - -in vec4 MV_pos[]; -in float edgeClass[]; - -flat out vec4 finalColor; - -void emitLine(vec4 color) -{ - gl_Position = ProjectionMatrix * MV_pos[0]; - EmitVertex(); - gl_Position = ProjectionMatrix * MV_pos[1]; - finalColor = color; - EmitVertex(); - EndPrimitive(); -} - -void main() -{ - float finalEdgeClass = max(edgeClass[0], edgeClass[1]); - - if (finalEdgeClass > 0.0f) { - // front-facing edge - if (drawFront) - emitLine(frontColor); - } - else if (finalEdgeClass < 0.0f) { - // back-facing edge - if (drawBack) - emitLine(backColor); - } - else { - // exactly one face is front-facing, silhouette edge - if (drawSilhouette) - emitLine(silhouetteColor); - } -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl deleted file mode 100644 index ffd52a0a225..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl +++ /dev/null @@ -1,68 +0,0 @@ - -// Draw "fancy" wireframe, displaying front-facing, back-facing and -// silhouette lines differently. -// Mike Erwin, April 2015 - -// After working with this shader a while, convinced we should make -// separate shaders for perpective & ortho. (Oct 2016) - -// This shader is an imperfect stepping stone until all platforms are -// ready for geometry shaders. - -// Due to perspective, the line segment's endpoints might disagree on -// whether the adjacent faces are front facing. Need to use a geometry -// shader or pass in an extra position attribute (the other endpoint) -// to do this properly. - -uniform bool drawFront = true; -uniform bool drawBack = true; -uniform bool drawSilhouette = true; - -uniform vec4 frontColor; -uniform vec4 backColor; -uniform vec4 silhouetteColor; - -uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewProjectionMatrix; -uniform mat3 NormalMatrix; - -in vec3 pos; - -// normals of faces this edge joins (object coords) -in vec3 N1; -in vec3 N2; - -flat out vec4 finalColor; - -// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley - -// to discard an entire line, set its color to invisible -// (must have GL_BLEND enabled, or discard in fragment shader) -const vec4 invisible = vec4(0.0); - -bool front(vec3 N) -{ - vec4 xformed = ModelViewMatrix * vec4(pos, 1.0); - return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0; -} - -void main() -{ - bool face_1_front = front(N1); - bool face_2_front = front(N2); - - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - - if (face_1_front && face_2_front) { - // front-facing edge - finalColor = drawFront ? frontColor : invisible; - } - else if (face_1_front || face_2_front) { - // exactly one face is front-facing, silhouette edge - finalColor = drawSilhouette ? silhouetteColor : invisible; - } - else { - // back-facing edge - finalColor = drawBack ? backColor : invisible; - } -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl deleted file mode 100644 index c8b722e1d7e..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl +++ /dev/null @@ -1,44 +0,0 @@ - -// Draw "fancy" wireframe, displaying front-facing, back-facing and -// silhouette lines differently. -// Mike Erwin, April 2015 - -// After working with this shader a while, convinced we should make -// separate shaders for perpective & ortho. (Oct 2016) - -// Due to perspective, the line segment's endpoints might disagree on -// whether the adjacent faces are front facing. We use a geometry -// shader to resolve this properly. - -uniform mat4 ModelViewMatrix; -uniform mat3 NormalMatrix; - -in vec3 pos; -in vec3 N1, N2; // normals of faces this edge joins (object coords) - -out vec4 MV_pos; -out float edgeClass; - -// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley - -bool front(vec3 N, vec3 eye) -{ - return dot(NormalMatrix * N, eye) > 0.0; -} - -void main() -{ - MV_pos = ModelViewMatrix * vec4(pos, 1.0); - - vec3 eye = normalize(-MV_pos.xyz); - - bool face_1_front = front(N1, eye); - bool face_2_front = front(N2, eye); - - if (face_1_front && face_2_front) - edgeClass = 1.0; // front-facing edge - else if (face_1_front || face_2_front) - edgeClass = 0.0; // exactly one face is front-facing, silhouette edge - else - edgeClass = -1.0; // back-facing edge -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl deleted file mode 100644 index 7b35f67dd54..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl +++ /dev/null @@ -1,21 +0,0 @@ - -#define SMOOTH 1 - -const float transitionWidth = 1.0; - -uniform vec4 fillColor = vec4(0); -uniform vec4 outlineColor = vec4(0, 0, 0, 1); - -noperspective in vec3 distanceToOutline; - -out vec4 FragColor; - -void main() -{ - float edgeness = min(min(distanceToOutline.x, distanceToOutline.y), distanceToOutline.z); -#if SMOOTH - FragColor = mix(outlineColor, fillColor, smoothstep(0, transitionWidth, edgeness)); -#else - FragColor = (edgeness <= 0) ? outlineColor : fillColor; -#endif -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl deleted file mode 100644 index 48fff1629fd..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl +++ /dev/null @@ -1,72 +0,0 @@ -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -uniform float outlineWidth = 1.0; -uniform vec2 viewportSize; - -in vec4 pos_xformed[]; -in float widthModulator[]; - -noperspective out vec3 distanceToOutline; - -// project to screen space -vec2 proj(int axis) -{ - vec4 pos = pos_xformed[axis]; - return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; -} - -float dist(vec2 pos[3], int v) -{ - // current vertex position - vec2 vpos = pos[v]; - // endpoints of opposite edge - vec2 e1 = pos[(v + 1) % 3]; - vec2 e2 = pos[(v + 2) % 3]; - - float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify - return abs_det / distance(e2, e1); -} - -vec3 distance[3]; - -void clearEdge(int v) -{ - float distant = 10 * outlineWidth; - for (int i = 0; i < 3; ++i) - distance[i][v] += distant; -} - -void modulateEdge(int v) -{ - float offset = min(widthModulator[v], 1) * outlineWidth; - for (int i = 0; i < 3; ++i) - distance[i][v] -= offset; -} - -void main() -{ - vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); - - for (int v = 0; v < 3; ++v) - distance[v] = vec3(0); - - for (int v = 0; v < 3; ++v) { - if (widthModulator[v] > 0) { - distance[v][v] = dist(pos, v); - modulateEdge(v); - } - } - - for (int v = 0; v < 3; ++v) - if (widthModulator[v] <= 0) - clearEdge(v); - - for (int v = 0; v < 3; ++v) { - gl_Position = pos_xformed[v]; - distanceToOutline = distance[v]; - EmitVertex(); - } - - EndPrimitive(); -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl deleted file mode 100644 index 12f5a2c7811..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl +++ /dev/null @@ -1,56 +0,0 @@ -layout(triangles) in; -layout(triangle_strip, max_vertices = 3) out; - -uniform float outlineWidth = 1.0; -uniform vec2 viewportSize; - -noperspective out vec3 distanceToOutline; - -// project to screen space -vec2 proj(int axis) -{ - vec4 pos = gl_in[axis].gl_Position; - return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; -} - -float dist(vec2 pos[3], int v) -{ - // current vertex position - vec2 vpos = pos[v]; - // endpoints of opposite edge - vec2 e1 = pos[(v + 1) % 3]; - vec2 e2 = pos[(v + 2) % 3]; - - float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify - return abs_det / distance(e2, e1); -} - -vec3 distance[3]; - -void modulateEdge(int v) -{ - float offset = 0.5 * outlineWidth; - for (int i = 0; i < 3; ++i) - distance[i][v] -= offset; -} - -void main() -{ - vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); - - for (int v = 0; v < 3; ++v) - distance[v] = vec3(0); - - for (int v = 0; v < 3; ++v) { - distance[v][v] = dist(pos, v); - modulateEdge(v); - } - - for (int v = 0; v < 3; ++v) { - gl_Position = gl_in[v].gl_Position; - distanceToOutline = distance[v]; - EmitVertex(); - } - - EndPrimitive(); -} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl deleted file mode 100644 index 33615ac36e5..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -uniform mat4 ModelViewProjectionMatrix; - -in vec3 pos; -in float edgeWidthModulator; - -out vec4 pos_xformed; -out float widthModulator; - -void main() -{ - pos_xformed = ModelViewProjectionMatrix * vec4(pos, 1.0); - widthModulator = edgeWidthModulator; -} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl index d9e73f81c45..62a526cae49 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl @@ -26,21 +26,21 @@ out vec3 fCol; // TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley -bool front(mat3 NormalMatrix, vec3 N, vec3 eye) +bool front(mat3 normal_matrix, vec3 N, vec3 eye) { - return dot(NormalMatrix * N, eye) > 0.0; + return dot(normal_matrix * N, eye) > 0.0; } void main() { vec3 eye; - mat4 ModelViewMatrix = ViewMatrix * InstanceModelMatrix; + mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix; vec4 pos_4d = vec4(pos, 1.0); - MV_pos = ModelViewMatrix * pos_4d; + MV_pos = model_view_matrix * pos_4d; - mat3 NormalMatrix = transpose(inverse(mat3(ModelViewMatrix))); + mat3 normal_matrix = transpose(inverse(mat3(model_view_matrix))); /* if persp */ if (ProjectionMatrix[3][3] == 0.0) { @@ -50,8 +50,8 @@ void main() eye = vec3(0.0, 0.0, 1.0); } - bool face_1_front = front(NormalMatrix, N1, eye); - bool face_2_front = front(NormalMatrix, N2, eye); + bool face_1_front = front(normal_matrix, N1, eye); + bool face_2_front = front(normal_matrix, N2, eye); if (face_1_front && face_2_front) edgeClass = 1.0; // front-facing edge diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl index 9b1a08d8d86..5b3922d7a72 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl @@ -1,5 +1,5 @@ -uniform mat4 ViewMatrix; +uniform mat4 ViewMatrixInverse; uniform mat4 ViewProjectionMatrix; /* ---- Instantiated Attrs ---- */ @@ -15,13 +15,12 @@ flat out vec4 finalColor; void main() { - mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * InstanceModelMatrix; - /* This is slow and run per vertex, but it's still faster than - * doing it per instance on CPU and sending it on via instance attr. */ - mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0)); - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - normal = NormalMatrix * nor; + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attribute. */ + mat3 normal_mat = transpose(inverse(mat3(InstanceModelMatrix))); + normal = normalize((transpose(mat3(ViewMatrixInverse)) * (normal_mat * nor))); finalColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index cf7a83e8a87..b94a7d6cc0a 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,14 +1,4 @@ -uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewMatrixInverse; -uniform mat3 NormalMatrix; -uniform mat3 NormalMatrixInverse; - -#ifndef USE_ATTR -uniform mat4 ModelMatrix; -uniform mat4 ModelMatrixInverse; -#endif - /* Converters */ float convert_rgba_to_float(vec4 color) @@ -119,38 +109,6 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol) outcol = vec4(rgb, hsv.w); } -float srgb_to_linearrgb(float c) -{ - if (c < 0.04045) - return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); - else - return pow((c + 0.055) * (1.0 / 1.055), 2.4); -} - -float linearrgb_to_srgb(float c) -{ - if (c < 0.0031308) - return (c < 0.0) ? 0.0 : c * 12.92; - else - return 1.055 * pow(c, 1.0 / 2.4) - 0.055; -} - -void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) -{ - col_to.r = srgb_to_linearrgb(col_from.r); - col_to.g = srgb_to_linearrgb(col_from.g); - col_to.b = srgb_to_linearrgb(col_from.b); - col_to.a = col_from.a; -} - -void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) -{ - col_to.r = linearrgb_to_srgb(col_from.r); - col_to.g = linearrgb_to_srgb(col_from.g); - col_to.b = linearrgb_to_srgb(col_from.b); - col_to.a = col_from.a; -} - void color_to_normal_new_shading(vec3 color, out vec3 normal) { normal = vec3(2.0) * color - vec3(1.0); @@ -204,9 +162,9 @@ void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) vout = (mat * vec4(vin, 0.0)).xyz; } -void mat3_mul(vec3 vin, mat3 mat, out vec3 vout) +void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout) { - vout = mat * vin; + vout = transpose(mat3(mat)) * vin; } void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout) @@ -1162,8 +1120,9 @@ vec3 cellnoise_color(vec3 p) float floorfrac(float x, out int i) { - i = floor_to_int(x); - return x - i; + float x_floor = floor(x); + i = int(x_floor); + return x - x_floor; } /* bsdfs */ @@ -1275,6 +1234,8 @@ void node_bsdf_principled(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1354,6 +1315,8 @@ void node_bsdf_principled(vec4 base_color, # endif result.sss_data.rgb *= (1.0 - transmission); # endif + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_principled_dielectric(vec4 base_color, @@ -1373,6 +1336,8 @@ void node_bsdf_principled_dielectric(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1402,6 +1367,8 @@ void node_bsdf_principled_dielectric(vec4 base_color, result.ssr_data = vec4(ssr_spec, roughness); result.ssr_normal = normal_encode(vN, viewCameraVec); result.ssr_id = int(ssr_id); + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_principled_metallic(vec4 base_color, @@ -1421,6 +1388,8 @@ void node_bsdf_principled_metallic(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1441,6 +1410,8 @@ void node_bsdf_principled_metallic(vec4 base_color, result.ssr_data = vec4(ssr_spec, roughness); result.ssr_normal = normal_encode(vN, viewCameraVec); result.ssr_id = int(ssr_id); + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_principled_clearcoat(vec4 base_color, @@ -1460,6 +1431,8 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1489,6 +1462,8 @@ void node_bsdf_principled_clearcoat(vec4 base_color, result.ssr_data = vec4(ssr_spec, roughness); result.ssr_normal = normal_encode(vN, viewCameraVec); result.ssr_id = int(ssr_id); + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_principled_subsurface(vec4 base_color, @@ -1508,6 +1483,8 @@ void node_bsdf_principled_subsurface(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1562,6 +1539,8 @@ void node_bsdf_principled_subsurface(vec4 base_color, result.radiance += (out_diff + out_trans) * mixed_ss_base_color; # endif result.radiance += out_diff * out_sheen; + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_principled_glass(vec4 base_color, @@ -1581,6 +1560,8 @@ void node_bsdf_principled_glass(vec4 base_color, float ior, float transmission, float transmission_roughness, + vec4 emission, + float alpha, vec3 N, vec3 CN, vec3 T, @@ -1615,6 +1596,8 @@ void node_bsdf_principled_glass(vec4 base_color, result.ssr_data = vec4(ssr_spec, roughness); result.ssr_normal = normal_encode(vN, viewCameraVec); result.ssr_id = int(ssr_id); + result.radiance += emission.rgb; + result.opacity = alpha; } void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) @@ -1743,11 +1726,11 @@ void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec) vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); vec4 co_homogenous = (ProjectionMatrixInverse * v); - vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + vec3 co = co_homogenous.xyz / co_homogenous.w; # if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) - worldvec = (ViewMatrixInverse * co).xyz; + worldvec = mat3(ViewMatrixInverse) * co; # else - worldvec = (ModelViewMatrixInverse * co).xyz; + worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co); # endif #endif } @@ -2014,18 +1997,13 @@ void tangent_orco_z(vec3 orco_in, out vec3 orco_out) orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0); } -void node_tangentmap(vec4 attr_tangent, mat4 toworld, out vec3 tangent) +void node_tangentmap(vec4 attr_tangent, out vec3 tangent) { - tangent = normalize((toworld * vec4(attr_tangent.xyz, 0.0)).xyz); + tangent = normalize(attr_tangent.xyz); } -void node_tangent(vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 T) +void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T) { -#ifndef VOLUMETRICS - N = normalize(gl_FrontFacing ? worldNormal : -worldNormal); -#else - N = (toworld * vec4(N, 0.0)).xyz; -#endif T = (objmat * vec4(orco, 0.0)).xyz; T = cross(N, normalize(cross(T, N))); } @@ -2060,7 +2038,7 @@ void node_geometry(vec3 I, position = worldPosition; # ifndef VOLUMETRICS - normal = normalize(gl_FrontFacing ? worldNormal : -worldNormal); + normal = normalize(N); vec3 B = dFdx(worldPosition); vec3 T = dFdy(worldPosition); true_normal = normalize(cross(B, T)); @@ -2069,7 +2047,7 @@ void node_geometry(vec3 I, true_normal = normal; # endif tangent_orco_z(orco, orco); - node_tangent(N, orco, objmat, toworld, tangent); + node_tangent(N, orco, objmat, tangent); parametric = vec3(barycentric, 0.0); backfacing = (gl_FrontFacing) ? 0.0 : 1.0; @@ -2091,9 +2069,8 @@ void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated) } void node_tex_coord(vec3 I, - vec3 N, - mat4 viewinvmat, - mat4 obinvmat, + vec3 wN, + mat4 obmatinv, vec4 camerafac, vec3 attr_orco, vec3 attr_uv, @@ -2106,22 +2083,18 @@ void node_tex_coord(vec3 I, out vec3 reflection) { generated = attr_orco; - normal = normalize(NormalMatrixInverse * N); + normal = normalize(normal_world_to_object(wN)); uv = attr_uv; - object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz; + object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz; camera = vec3(I.xy, -I.z); vec4 projvec = ProjectionMatrix * vec4(I, 1.0); window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); - - vec3 shade_I = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); - vec3 view_reflection = reflect(shade_I, normalize(N)); - reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz; + reflection = reflect(cameraVec, normalize(wN)); } void node_tex_coord_background(vec3 I, vec3 N, - mat4 viewinvmat, - mat4 obinvmat, + mat4 obmatinv, vec4 camerafac, vec3 attr_orco, vec3 attr_uv, @@ -2140,11 +2113,7 @@ void node_tex_coord_background(vec3 I, co = normalize(co); -#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) vec3 coords = (ViewMatrixInverse * co).xyz; -#else - vec3 coords = (ModelViewMatrixInverse * co).xyz; -#endif generated = coords; normal = -coords; @@ -2345,6 +2314,21 @@ void node_tex_environment_empty(vec3 co, out vec4 color) /* 16bits floats limits. Higher/Lower values produce +/-inf. */ #define safe_color(a) (clamp(a, -65520.0, 65520.0)) +void tex_color_alpha_clear(vec4 color, out vec4 result) +{ + result = vec4(color.rgb, 1.0); +} + +void tex_color_alpha_unpremultiply(vec4 color, out vec4 result) +{ + if (color.a == 0.0 || color.a == 1.0) { + result = vec4(color.rgb, 1.0); + } + else { + result = vec4(color.rgb / color.a, 1.0); + } +} + void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha) { color = safe_color(texture(ima, co.xy)); @@ -3245,6 +3229,7 @@ void node_light_falloff( void node_object_info(mat4 obmat, vec4 info, + float mat_index, out vec3 location, out float object_index, out float material_index, @@ -3252,7 +3237,7 @@ void node_object_info(mat4 obmat, { location = obmat[3].xyz; object_index = info.x; - material_index = info.y; + material_index = mat_index; random = info.z; } @@ -3346,6 +3331,7 @@ void node_vector_displacement_tangent(vec4 vector, mat4 viewmat, out vec3 result) { + /* TODO(fclem) this is broken. revisit latter. */ vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz); vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz); vec3 B_object = tangent.w * normalize(cross(N_object, T_object)); @@ -3390,11 +3376,11 @@ void node_output_world(Closure surface, Closure volume, out Closure result) #endif /* VOLUMETRICS */ } -#ifndef VOLUMETRICS /* TODO : clean this ifdef mess */ /* EEVEE output */ void world_normals_get(out vec3 N) { +#ifndef VOLUMETRICS # ifdef HAIR_SHADER vec3 B = normalize(cross(worldNormal, hairTangent)); float cos_theta; @@ -3412,8 +3398,12 @@ void world_normals_get(out vec3 N) # else N = gl_FrontFacing ? worldNormal : -worldNormal; # endif +#else + generated_from_orco(vec3(0.0), N); +#endif } +#ifndef VOLUMETRICS void node_eevee_specular(vec4 diffuse, vec4 specular, float roughness, diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 620f8984d9f..a27945cc369 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -58,6 +58,11 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char * const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf); const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf); +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); + BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]); BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]); BLI_INLINE void IMB_colormangement_xyz_to_rgb(float rgb[3], const float xyz[3]); @@ -124,6 +129,14 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, struct ColorSpace *colorspace, bool predivide); +void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *rect, + const int x, + const int y, + const int width, + const int height, + const struct ImBuf *ibuf, + const bool compress_as_srgb); + void IMB_colormanagement_scene_linear_to_color_picking_v3(float pixel[3]); void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3]); @@ -340,6 +353,7 @@ enum { COLOR_ROLE_DEFAULT_SEQUENCER, COLOR_ROLE_DEFAULT_BYTE, COLOR_ROLE_DEFAULT_FLOAT, + COLOR_ROLE_DATA, }; #include "intern/colormanagement_inline.c" diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index f8df14cf317..8574f33bce6 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -476,13 +476,11 @@ int imb_get_anim_type(const char *name); */ bool IMB_isfloat(struct ImBuf *ibuf); +/* Do byte/float and colorspace conversions need to take alpha into account? */ +bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf); + /* create char buffer, color corrected if necessary, for ImBufs that lack one */ void IMB_rect_from_float(struct ImBuf *ibuf); -/* Create char buffer for part of the image, color corrected if necessary, - * Changed part will be stored in buffer. - * This is expected to be used for texture painting updates */ -void IMB_partial_rect_from_float( - struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data); void IMB_float_from_rect(struct ImBuf *ibuf); void IMB_color_to_bw(struct ImBuf *ibuf); void IMB_saturation(struct ImBuf *ibuf, float sat); @@ -555,7 +553,6 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to, int height, int stride_to, int stride_from); -void IMB_buffer_float_clamp(float *buf, int width, int height); void IMB_buffer_float_unpremultiply(float *buf, int width, int height); void IMB_buffer_float_premultiply(float *buf, int width, int height); diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 0f2529e261a..61aa1f401a0 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -285,10 +285,12 @@ enum { IB_alphamode_premul = 1 << 12, /** if this flag is set, alpha mode would be guessed from file */ IB_alphamode_detect = 1 << 13, + /* alpha channel is unrelated to RGB and should not affect it */ + IB_alphamode_channel_packed = 1 << 14, /** ignore alpha on load and substitute it with 1.0f */ - IB_ignore_alpha = 1 << 14, - IB_thumbnail = 1 << 15, - IB_multiview = 1 << 16, + IB_alphamode_ignore = 1 << 15, + IB_thumbnail = 1 << 16, + IB_multiview = 1 << 17, }; /** \} */ diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index 2566016ffdd..a83f2d60b8c 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -48,6 +48,13 @@ typedef struct ColorSpace { bool is_invertible; bool is_data; + + /* Additional info computed only when needed since it's not cheap. */ + struct { + bool cached; + bool is_srgb; + bool is_scene_linear; + } info; } ColorSpace; typedef struct ColorManagedDisplay { diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c index 01c588daedd..7ddf4423bbf 100644 --- a/source/blender/imbuf/intern/cache.c +++ b/source/blender/imbuf/intern/cache.c @@ -156,7 +156,7 @@ void imb_tile_cache_tile_free(ImBuf *ibuf, int tx, int ty) if (gtile) { /* in case another thread is loading this */ while (gtile->loading) { - ; + /* pass */ } BLI_ghash_remove(GLOBAL_CACHE.tilehash, gtile, NULL, NULL); @@ -295,7 +295,7 @@ static ImGlobalTile *imb_global_cache_get_tile(ImBuf *ibuf, BLI_mutex_unlock(&GLOBAL_CACHE.mutex); while (gtile->loading) { - ; + /* pass */ } } else { diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index f31d4ede693..583a3be8168 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -65,6 +65,7 @@ #define DISPLAY_BUFFER_CHANNELS 4 /* ** list of all supported color spaces, displays and views */ +static char global_role_data[MAX_COLORSPACE_NAME]; static char global_role_scene_linear[MAX_COLORSPACE_NAME]; static char global_role_color_picking[MAX_COLORSPACE_NAME]; static char global_role_texture_painting[MAX_COLORSPACE_NAME]; @@ -488,6 +489,7 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) const char *name; /* get roles */ + colormanage_role_color_space_name_get(config, global_role_data, OCIO_ROLE_DATA, NULL); colormanage_role_color_space_name_get( config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL); colormanage_role_color_space_name_get( @@ -745,6 +747,16 @@ void colormanagement_exit(void) /*********************** Internal functions *************************/ +static bool colormanage_compatible_look(ColorManagedLook *look, const char *view_name) +{ + if (look->is_noop) { + return true; + } + + /* Skip looks only relevant to specific view transforms. */ + return (look->view[0] == 0 || (view_name && STREQ(look->view, view_name))); +} + void colormanage_cache_free(ImBuf *ibuf) { if (ibuf->display_buffer_flags) { @@ -838,7 +850,7 @@ static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *loo OCIO_displayTransformSetView(dt, view_transform); OCIO_displayTransformSetDisplay(dt, display); - if (look_descr->is_noop == false) { + if (look_descr->is_noop == false && colormanage_compatible_look(look_descr, view_transform)) { OCIO_displayTransformSetLooksOverrideEnabled(dt, true); OCIO_displayTransformSetLooksOverride(dt, look); } @@ -987,9 +999,9 @@ static OCIO_ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedD void IMB_colormanagement_init_default_view_settings( ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { - /* First, try use "Default" view transform of the requested device. */ + /* First, try use "Standard" view transform of the requested device. */ ColorManagedView *default_view = colormanage_view_get_named_for_display( - display_settings->display_device, "Default"); + display_settings->display_device, "Standard"); /* If that fails, we fall back to the default view transform of the display * as per OCIO configuration. */ if (default_view == NULL) { @@ -1055,13 +1067,19 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) if (ibuf->rect_float) { const char *to_colorspace = global_role_scene_linear; + const bool predivide = IMB_alpha_affects_rgb(ibuf); if (ibuf->rect) { imb_freerectImBuf(ibuf); } - IMB_colormanagement_transform( - ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true); + IMB_colormanagement_transform(ibuf->rect_float, + ibuf->x, + ibuf->y, + ibuf->channels, + from_colorspace, + to_colorspace, + predivide); } } @@ -1260,6 +1278,8 @@ void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *di const char *IMB_colormanagement_role_colorspace_name_get(int role) { switch (role) { + case COLOR_ROLE_DATA: + return global_role_data; case COLOR_ROLE_SCENE_LINEAR: return global_role_scene_linear; case COLOR_ROLE_COLOR_PICKING: @@ -1341,6 +1361,48 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf) } } +bool IMB_colormanagement_space_is_data(ColorSpace *colorspace) +{ + return (colorspace && colorspace->is_data); +} + +static void colormanage_ensure_srgb_scene_linear_info(ColorSpace *colorspace) +{ + if (!colorspace->info.cached) { + OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); + OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config, + colorspace->name); + + bool is_scene_linear, is_srgb; + OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb); + + OCIO_colorSpaceRelease(ocio_colorspace); + OCIO_configRelease(config); + + colorspace->info.is_scene_linear = is_scene_linear; + colorspace->info.is_srgb = is_srgb; + colorspace->info.cached = true; + } +} + +bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace) +{ + colormanage_ensure_srgb_scene_linear_info(colorspace); + return (colorspace && colorspace->info.is_scene_linear); +} + +bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace) +{ + colormanage_ensure_srgb_scene_linear_info(colorspace); + return (colorspace && colorspace->info.is_srgb); +} + +bool IMB_colormanagement_space_name_is_data(const char *name) +{ + ColorSpace *colorspace = colormanage_colorspace_get_named(name); + return (colorspace && colorspace->is_data); +} + /*********************** Threaded display buffer transform routines *************************/ typedef struct DisplayBufferThread { @@ -1359,6 +1421,7 @@ typedef struct DisplayBufferThread { int channels; float dither; bool is_data; + bool predivide; const char *byte_colorspace; const char *float_colorspace; @@ -1423,6 +1486,7 @@ static void display_buffer_init_handle(void *handle_v, handle->channels = channels; handle->dither = dither; handle->is_data = is_data; + handle->predivide = IMB_alpha_affects_rgb(ibuf); handle->byte_colorspace = init_data->byte_colorspace; handle->float_colorspace = init_data->float_colorspace; @@ -1440,6 +1504,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, bool is_data = handle->is_data; bool is_data_display = handle->cm_processor->is_data_result; + bool predivide = handle->predivide; if (!handle->buffer) { unsigned char *byte_buffer = handle->byte_buffer; @@ -1488,7 +1553,7 @@ static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, if (!is_data && !is_data_display) { IMB_colormanagement_transform( - linear_buffer, width, height, channels, from_colorspace, to_colorspace, true); + linear_buffer, width, height, channels, from_colorspace, to_colorspace, predivide); } *is_straight_alpha = false; @@ -1544,13 +1609,13 @@ static void *do_display_buffer_apply_thread(void *handle_v) } } else { - bool is_straight_alpha, predivide; + bool is_straight_alpha; float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float), "color conversion linear buffer"); display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha); - predivide = is_straight_alpha == false; + bool predivide = handle->predivide && (is_straight_alpha == false); if (is_data) { /* special case for data buffers - no color space conversions, @@ -2111,6 +2176,69 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, } } +void IMB_colormanagement_imbuf_to_srgb_texture(unsigned char *out_buffer, + const int offset_x, + const int offset_y, + const int width, + const int height, + const struct ImBuf *ibuf, + const bool compress_as_srgb) +{ + /* Convert byte buffer for texture storage on the GPU. These have builtin + * support for converting sRGB to linear, which allows us to store textures + * without precision or performance loss at minimal memory usage. */ + BLI_assert(ibuf->rect && ibuf->rect_float == NULL); + + OCIO_ConstProcessorRcPtr *processor = NULL; + if (compress_as_srgb && ibuf->rect_colorspace && + !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) { + processor = colorspace_to_scene_linear_processor(ibuf->rect_colorspace); + } + + /* TODO(brecht): make this multithreaded, or at least process in batches. */ + const unsigned char *in_buffer = (unsigned char *)ibuf->rect; + const bool use_premultiply = IMB_alpha_affects_rgb(ibuf); + + for (int y = 0; y < height; y++) { + const size_t in_offset = (offset_y + y) * ibuf->x + offset_x; + const size_t out_offset = y * width; + const unsigned char *in = in_buffer + in_offset * 4; + unsigned char *out = out_buffer + out_offset * 4; + + if (processor) { + /* Convert to scene linear, to sRGB and premultiply. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + float pixel[4]; + rgba_uchar_to_float(pixel, in); + OCIO_processorApplyRGB(processor, pixel); + linearrgb_to_srgb_v3_v3(pixel, pixel); + if (use_premultiply) { + mul_v3_fl(pixel, pixel[3]); + } + rgba_float_to_uchar(out, pixel); + } + } + else if (use_premultiply) { + /* Premultiply only. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + out[0] = (in[0] * in[3]) >> 8; + out[1] = (in[1] * in[3]) >> 8; + out[2] = (in[2] * in[3]) >> 8; + out[3] = in[3]; + } + } + else { + /* Copy only. */ + for (int x = 0; x < width; x++, in += 4, out += 4) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + } + } + } +} + /* Conversion between color picking role. Typically we would expect such a * requirements: * - It is approximately perceptually linear, so that the HSV numbers and @@ -3097,17 +3225,9 @@ void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, const char *view_name) { ColorManagedLook *look; - const char *view_filter = NULL; - - /* Test if this view transform is limited to specific looks. */ - for (look = global_looks.first; look; look = look->next) { - if (STREQ(look->view, view_name)) { - view_filter = view_name; - } - } for (look = global_looks.first; look; look = look->next) { - if (!look->is_noop && view_filter && !STREQ(look->view, view_filter)) { + if (!colormanage_compatible_look(look, view_name)) { continue; } diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index e4845e56c46..aa49453d68c 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -96,6 +96,12 @@ MINLINE void float_to_byte_dither_v4( b[3] = unit_float_to_uchar_clamp(f[3]); } +/* Test if colorspace conversions of pixels in buffer need to take into account alpha. */ +bool IMB_alpha_affects_rgb(const ImBuf *ibuf) +{ + return (ibuf->flags & IB_alphamode_channel_packed) == 0; +} + /* float to byte pixels, output 4-channel RGBA */ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, @@ -728,16 +734,19 @@ void IMB_rect_from_float(ImBuf *ibuf) buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ + const bool predivide = IMB_alpha_affects_rgb(ibuf); IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, - true); + predivide); /* convert from float's premul alpha to byte's straight alpha */ - IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y); + if (IMB_alpha_affects_rgb(ibuf)) { + IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y); + } /* convert float to byte */ IMB_buffer_byte_from_float((unsigned char *)ibuf->rect, @@ -758,118 +767,6 @@ void IMB_rect_from_float(ImBuf *ibuf) ibuf->userflags &= ~IB_RECT_INVALID; } -typedef struct PartialThreadData { - ImBuf *ibuf; - float *buffer; - uchar *rect_byte; - const float *rect_float; - int width; - bool is_data; -} PartialThreadData; - -static void partial_rect_from_float_slice(float *buffer, - uchar *rect_byte, - ImBuf *ibuf, - const float *rect_float, - const int w, - const int h, - const bool is_data) -{ - const int profile_from = IB_PROFILE_LINEAR_RGB; - if (is_data) { - /* exception for non-color data, just copy float */ - IMB_buffer_float_from_float(buffer, - rect_float, - ibuf->channels, - IB_PROFILE_LINEAR_RGB, - IB_PROFILE_LINEAR_RGB, - 0, - w, - h, - w, - ibuf->x); - - /* and do color space conversion to byte */ - IMB_buffer_byte_from_float(rect_byte, - rect_float, - 4, - ibuf->dither, - IB_PROFILE_SRGB, - profile_from, - true, - w, - h, - ibuf->x, - w); - } - else { - IMB_buffer_float_from_float( - buffer, rect_float, ibuf->channels, IB_PROFILE_SRGB, profile_from, true, w, h, w, ibuf->x); - - IMB_buffer_float_unpremultiply(buffer, w, h); - /* XXX: need to convert to image buffer's rect space */ - IMB_buffer_byte_from_float( - rect_byte, buffer, 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, w, h, ibuf->x, w); - } -} - -static void partial_rect_from_float_thread_do(void *data_v, int start_scanline, int num_scanlines) -{ - PartialThreadData *data = (PartialThreadData *)data_v; - ImBuf *ibuf = data->ibuf; - size_t global_offset = ((size_t)ibuf->x) * start_scanline; - size_t local_offset = ((size_t)data->width) * start_scanline; - partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels, - data->rect_byte + global_offset * 4, - ibuf, - data->rect_float + global_offset * ibuf->channels, - data->width, - num_scanlines, - data->is_data); -} - -/** - * Converts from linear float to sRGB byte for part of the texture, - * buffer will hold the changed part. - */ -void IMB_partial_rect_from_float( - ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data) -{ - const float *rect_float; - uchar *rect_byte; - - /* verify we have a float buffer */ - if (ibuf->rect_float == NULL || buffer == NULL) { - return; - } - - /* create byte rect if it didn't exist yet */ - if (ibuf->rect == NULL) { - imb_addrectImBuf(ibuf); - } - - /* do conversion */ - rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels; - rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4; - - if (((size_t)w) * h < 64 * 64) { - partial_rect_from_float_slice(buffer, rect_byte, ibuf, rect_float, w, h, is_data); - } - else { - PartialThreadData data; - data.ibuf = ibuf; - data.buffer = buffer; - data.rect_byte = rect_byte; - data.rect_float = rect_float; - data.width = w; - data.is_data = is_data; - IMB_processor_apply_threaded_scanlines(h, partial_rect_from_float_thread_do, &data); - } - - /* ensure user flag is reset */ - ibuf->userflags &= ~IB_RECT_INVALID; -} - void IMB_float_from_rect(ImBuf *ibuf) { float *rect_float; @@ -914,7 +811,9 @@ void IMB_float_from_rect(ImBuf *ibuf) rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false); /* byte buffer is straight alpha, float should always be premul */ - IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y); + if (IMB_alpha_affects_rgb(ibuf)) { + IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y); + } if (ibuf->rect_float == NULL) { ibuf->rect_float = rect_float; @@ -945,14 +844,6 @@ void IMB_color_to_bw(ImBuf *ibuf) } } -void IMB_buffer_float_clamp(float *buf, int width, int height) -{ - size_t i, total = ((size_t)width) * height * 4; - for (i = 0; i < total; i++) { - buf[i] = min_ff(1.0, buf[i]); - } -} - void IMB_buffer_float_unpremultiply(float *buf, int width, int height) { size_t total = ((size_t)width) * height; diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index ed3b214047a..ac31f7db791 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -55,7 +55,6 @@ void IMB_metadata_free(struct IDProperty *metadata) } IDP_FreeProperty(metadata); - MEM_freeN(metadata); } bool IMB_metadata_get_field(struct IDProperty *metadata, diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 58ac966ac30..5e81b716619 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -354,7 +354,7 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); cnt++) { - ; + /* pass */ } if (cnt >= MINRUN) { break; /* long enough */ diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index e1df5c63093..d9f3c7ec6bb 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -49,8 +49,6 @@ static void imb_handle_alpha(ImBuf *ibuf, char colorspace[IM_MAX_SPACE], char effective_colorspace[IM_MAX_SPACE]) { - int alpha_flags; - if (colorspace) { if (ibuf->rect != NULL && ibuf->rect_float == NULL) { /* byte buffer is never internally converted to some standard space, @@ -62,15 +60,17 @@ static void imb_handle_alpha(ImBuf *ibuf, BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE); } - if (flags & IB_alphamode_detect) { - alpha_flags = ibuf->flags & IB_alphamode_premul; - } - else { - alpha_flags = flags & IB_alphamode_premul; - } + bool is_data = (colorspace && IMB_colormanagement_space_name_is_data(colorspace)); + int alpha_flags = (flags & IB_alphamode_detect) ? ibuf->flags : flags; - if (flags & IB_ignore_alpha) { + if (is_data || (flags & IB_alphamode_channel_packed)) { + /* Don't touch alpha. */ + ibuf->flags |= IB_alphamode_channel_packed; + } + else if (flags & IB_alphamode_ignore) { + /* Make opaque. */ IMB_rectfill_alpha(ibuf, 1.0f); + ibuf->flags |= IB_alphamode_ignore; } else { if (alpha_flags & IB_alphamode_premul) { diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 2cdbfa06e30..5a666653043 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -448,7 +448,9 @@ typedef enum ID_Type { /* No copy-on-write for these types. * Keep in sync with check_datablocks_copy_on_writable and deg_copy_on_write_is_needed */ -#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM)) +/* TODO(sergey): Make Sound copyable. It is here only because the code for dependency graph is + * being work in progress. */ +#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM, ID_SO)) #ifdef GS # undef GS diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index c524f50ff52..c8a76791cef 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -512,6 +512,12 @@ typedef enum ePose_Flags { POSE_FLAG_DEPRECATED = (1 << 6), /* deprecated. */ /* pose constraint flags needs to be updated */ POSE_CONSTRAINTS_NEED_UPDATE_FLAGS = (1 << 7), + /* Use auto IK in pose mode */ + POSE_AUTO_IK = (1 << 8), + /* Use x-axis mirror in pose mode */ + POSE_MIRROR_EDIT = (1 << 9), + /* Use relative mirroring in mirror mode */ + POSE_MIRROR_RELATIVE = (1 << 10), } ePose_Flags; /* IK Solvers ------------------------------------ */ diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index c76d4895b25..ecf587301c7 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -357,6 +357,7 @@ typedef enum eDriverTarget_TransformChannels { DTAR_TRANSCHAN_SCALEX, DTAR_TRANSCHAN_SCALEY, DTAR_TRANSCHAN_SCALEZ, + DTAR_TRANSCHAN_SCALE_AVG, MAX_DTAR_TRANSCHAN_TYPES, } eDriverTarget_TransformChannels; @@ -969,6 +970,8 @@ typedef enum eInsertKeyFlags { INSERTKEY_DRIVER = (1 << 8), /** for cyclic FCurves, adjust key timing to preserve the cycle period and flow */ INSERTKEY_CYCLE_AWARE = (1 << 9), + /** don't create new F-Curves (implied by INSERTKEY_REPLACE) */ + INSERTKEY_AVAILABLE = (1 << 10), } eInsertKeyFlags; /* ************************************************ */ diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 483ff3483d3..b18ab503e94 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -104,7 +104,11 @@ typedef struct bArmature { struct AnimData *adt; ListBase bonebase; - ListBase chainbase; + + /** Ghash for quicker lookups of bones by name. */ + struct GHash *bonehash; + void *_pad1; + /** Editbone listbase, we use pointer so we can check state. */ ListBase *edbo; @@ -144,9 +148,9 @@ typedef enum eArmature_Flag { ARM_POSEMODE = (1 << 4), ARM_FLAG_UNUSED_5 = (1 << 5), /* cleared */ ARM_DELAYDEFORM = (1 << 6), - ARM_FLAG_UNUSED_7 = (1 << 7), /* cleared */ + ARM_FLAG_UNUSED_7 = (1 << 7), ARM_MIRROR_EDIT = (1 << 8), - ARM_AUTO_IK = (1 << 9), + ARM_FLAG_UNUSED_9 = (1 << 9), /** made option negative, for backwards compat */ ARM_NO_CUSTOM = (1 << 10), /** draw custom colors */ diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 8c5d911b7fa..b78b2f64648 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -67,6 +67,19 @@ typedef struct CameraBGImage { short source; } CameraBGImage; +/** Properties for dof effect. */ +typedef struct CameraDOFSettings { + /** Focal distance for depth of field. */ + struct Object *focus_object; + float focus_distance; + float aperture_fstop; + float aperture_rotation; + float aperture_ratio; + int aperture_blades; + short flag; + char _pad[2]; +} CameraDOFSettings; + typedef struct Camera_Runtime { /* For draw manager. */ float drw_corners[2][4][2]; @@ -91,13 +104,14 @@ typedef struct Camera { float lens, ortho_scale, drawsize; float sensor_x, sensor_y; float shiftx, shifty; - float dof_distance; + float dof_distance DNA_DEPRECATED; /** Old animation system, deprecated for 2.5. */ struct Ipo *ipo DNA_DEPRECATED; - struct Object *dof_ob; - struct GPUDOFSettings gpu_dof; + struct Object *dof_ob DNA_DEPRECATED; + struct GPUDOFSettings gpu_dof DNA_DEPRECATED; + struct CameraDOFSettings dof; /* CameraBGImage reference images */ struct ListBase bg_images; @@ -204,6 +218,11 @@ enum { CAM_BGIMG_SOURCE_MOVIE = 1, }; +/* CameraDOFSettings->flag */ +enum { + CAM_DOF_ENABLED = (1 << 0), +}; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h index b935acd5a24..c7f3ef4156d 100644 --- a/source/blender/makesdna/DNA_collection_types.h +++ b/source/blender/makesdna/DNA_collection_types.h @@ -76,10 +76,10 @@ typedef struct Collection { /* Collection->flag */ enum { - COLLECTION_RESTRICT_VIEW = (1 << 0), /* Hidden in viewport. */ + COLLECTION_RESTRICT_VIEWPORT = (1 << 0), /* Disable in viewports. */ COLLECTION_RESTRICT_SELECT = (1 << 1), /* Not selectable in viewport. */ COLLECTION_DISABLED_DEPRECATED = (1 << 2), /* Not used anymore */ - COLLECTION_RESTRICT_RENDER = (1 << 3), /* Hidden in renders. */ + COLLECTION_RESTRICT_RENDER = (1 << 3), /* Disable in renders. */ COLLECTION_HAS_OBJECT_CACHE = (1 << 4), /* Runtime: object_cache is populated. */ COLLECTION_IS_MASTER = (1 << 5), /* Is master collection embedded in the scene. */ }; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index f839f22ec9f..c09ea400f4c 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -289,14 +289,16 @@ typedef struct bLocateLikeConstraint { typedef struct bSizeLikeConstraint { struct Object *tar; int flag; - int reserved1; + float power; /** MAX_ID_NAME-2. */ char subtarget[64]; } bSizeLikeConstraint; /* Maintain Volume Constraint */ typedef struct bSameVolumeConstraint { - int flag; + char free_axis; + char mode; + char _pad[2]; float volume; } bSameVolumeConstraint; @@ -758,12 +760,22 @@ typedef enum eTransform_ToFrom { TRANS_SCALE = 2, } eTransform_ToFrom; -/* bSameVolumeConstraint.flag */ -typedef enum eSameVolume_Modes { +/* bSameVolumeConstraint.free_axis */ +typedef enum eSameVolume_Axis { SAMEVOL_X = 0, SAMEVOL_Y = 1, SAMEVOL_Z = 2, -} eSameVolume_Modes; +} eSameVolume_Axis; + +/* bSameVolumeConstraint.mode */ +typedef enum eSameVolume_Mode { + /* Strictly maintain the volume, overriding non-free axis scale. */ + SAMEVOL_STRICT = 0, + /* Maintain the volume when scale is uniform, pass non-uniform other axis scale through. */ + SAMEVOL_UNIFORM = 1, + /* Maintain the volume when scaled only on the free axis, pass other axis scale through. */ + SAMEVOL_SINGLE_AXIS = 2, +} eSameVolume_Mode; /* bActionConstraint.flag */ typedef enum eActionConstraint_Flags { @@ -894,6 +906,9 @@ typedef enum eSplineIK_Flags { /* for "volumetric" xz scale mode, limit the minimum or maximum scale values */ CONSTRAINT_SPLINEIK_USE_BULGE_MIN = (1 << 5), CONSTRAINT_SPLINEIK_USE_BULGE_MAX = (1 << 6), + + /* apply volume preservation over original scaling of the bone */ + CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE = (1 << 7), } eSplineIK_Flags; /* bSplineIKConstraint->xzScaleMode */ diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h index 6a9d50ecc2d..dc4f5512b1a 100644 --- a/source/blender/makesdna/DNA_genfile.h +++ b/source/blender/makesdna/DNA_genfile.h @@ -121,4 +121,15 @@ bool DNA_sdna_patch_struct_member(struct SDNA *sdna, void DNA_sdna_alias_data_ensure(struct SDNA *sdna); +/* Alias lookups (using runtime struct member names). */ +int DNA_struct_alias_find_nr_ex(const struct SDNA *sdna, + const char *str, + unsigned int *index_last); +int DNA_struct_alias_find_nr(const struct SDNA *sdna, const char *str); +bool DNA_struct_alias_elem_find(const struct SDNA *sdna, + const char *stype, + const char *vartype, + const char *name); +void DNA_sdna_alias_data_ensure_structs_map(struct SDNA *sdna); + #endif /* __DNA_GENFILE_H__ */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index bb38311cbac..007be021def 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -518,7 +518,8 @@ typedef struct bGPdata { /** Draw mode for strokes (eGP_DrawMode). */ short draw_mode; - char _pad3[2]; + /** Keyframe type for onion filter (eBezTriple_KeyframeType plus All option) */ + short onion_keytype; bGPgrid grid; diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index fec5f96b4f3..6141472125f 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -178,7 +178,7 @@ enum { /** For image user, but these flags are mixed. */ IMA_USER_FRAME_IN_RANGE = (1 << 10), IMA_VIEW_AS_RENDER = (1 << 11), - IMA_IGNORE_ALPHA = (1 << 12), + IMA_FLAG_UNUSED_12 = (1 << 12), /* cleared */ IMA_DEINTERLACE = (1 << 13), IMA_USE_VIEWS = (1 << 14), IMA_FLAG_UNUSED_15 = (1 << 15), /* cleared */ @@ -191,22 +191,50 @@ enum { IMA_GPU_REFRESH = (1 << 0), /** All mipmap levels in OpenGL texture set? */ IMA_GPU_MIPMAP_COMPLETE = (1 << 1), - /** OpenGL image texture bound as non-color data. */ - IMA_GPU_IS_DATA = (1 << 2), }; -/* ima->type and ima->source moved to BKE_image.h, for API */ +/* Image.source, where the image comes from */ +enum { + IMA_SRC_CHECK = 0, + IMA_SRC_FILE = 1, + IMA_SRC_SEQUENCE = 2, + IMA_SRC_MOVIE = 3, + IMA_SRC_GENERATED = 4, + IMA_SRC_VIEWER = 5, +}; + +/* Image.type, how to handle or generate the image */ +enum { + IMA_TYPE_IMAGE = 0, + IMA_TYPE_MULTILAYER = 1, + /* generated */ + IMA_TYPE_UV_TEST = 2, + /* viewers */ + IMA_TYPE_R_RESULT = 4, + IMA_TYPE_COMPOSITE = 5, +}; + +/* Image.gen_type */ +enum { + IMA_GENTYPE_BLANK = 0, + IMA_GENTYPE_GRID = 1, + IMA_GENTYPE_GRID_COLOR = 2, +}; /* render */ #define IMA_MAX_RENDER_TEXT (1 << 9) -/* gen_flag */ -#define IMA_GEN_FLOAT 1 +/* Image.gen_flag */ +enum { + IMA_GEN_FLOAT = 1, +}; -/* alpha_mode */ +/* Image.alpha_mode */ enum { IMA_ALPHA_STRAIGHT = 0, IMA_ALPHA_PREMUL = 1, + IMA_ALPHA_CHANNEL_PACKED = 2, + IMA_ALPHA_IGNORE = 3, }; #endif diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index dd8adeaf153..5f64e3220b7 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -133,7 +133,7 @@ enum { LAYER_COLLECTION_EXCLUDE = (1 << 4), LAYER_COLLECTION_HOLDOUT = (1 << 5), LAYER_COLLECTION_INDIRECT_ONLY = (1 << 6), - LAYER_COLLECTION_RESTRICT_VIEW = (1 << 7), + LAYER_COLLECTION_HIDE = (1 << 7), }; /* Layer Collection->runtime_flag */ diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h index 6bd118b7be9..5e881053910 100644 --- a/source/blender/makesdna/DNA_light_types.h +++ b/source/blender/makesdna/DNA_light_types.h @@ -66,6 +66,9 @@ typedef struct Light { short area_shape; float area_size, area_sizey, area_sizez; + float sun_angle; + char _pad3[4]; + /* texact is for buttons */ short texact, shadhalostep; diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 02f8245413d..d65a4896758 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -99,6 +99,9 @@ typedef struct MaterialGPencilStyle { /** Factor used to mix texture and stroke color. */ float mix_stroke_factor; + /** Mode used to align Dots and Boxes with stroke drawing path and object rotation */ + int alignment_mode; + char _pad[4]; } MaterialGPencilStyle; /* MaterialGPencilStyle->flag */ @@ -123,8 +126,6 @@ typedef enum eMaterialGPencilStyle_Flag { GP_STYLE_STROKE_SHOW = (1 << 8), /* Fill show main switch */ GP_STYLE_FILL_SHOW = (1 << 9), - /* Don't rotate dots/boxes */ - GP_STYLE_COLOR_LOCK_DOTS = (1 << 10), /* mix stroke texture */ GP_STYLE_STROKE_TEX_MIX = (1 << 11), } eMaterialGPencilStyle_Flag; @@ -315,7 +316,7 @@ enum { enum { MA_BL_HIDE_BACKFACE = (1 << 0), MA_BL_SS_REFRACTION = (1 << 1), - MA_BL_FLAG_UNUSED_2 = (1 << 2), /* cleared */ + MA_BL_CULL_BACKFACE = (1 << 2), MA_BL_TRANSLUCENCY = (1 << 3), }; @@ -347,4 +348,10 @@ enum { GP_STYLE_GRADIENT_RADIAL, }; +/* Grease Pencil Follow Drawing Modes */ +enum { + GP_STYLE_FOLLOW_PATH = 0, + GP_STYLE_FOLLOW_OBJ, + GP_STYLE_FOLLOW_FIXED, +}; #endif diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 8f08b212d6d..f54c178f1d0 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -233,11 +233,11 @@ enum { /* me->flag */ enum { - ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */ - ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */ - ME_TWOSIDED = 1 << 2, - ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */ - ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */ + ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */ + ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */ + ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */ + ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */ + ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */ ME_AUTOSMOOTH = 1 << 5, ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */ ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 226e1d2f841..3890fc63f3f 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -832,7 +832,7 @@ typedef struct NodeTexSky { typedef struct NodeTexImage { NodeTexBase base; ImageUser iuser; - int color_space; + int color_space DNA_DEPRECATED; int projection; float projection_blend; int interpolation; @@ -853,7 +853,7 @@ typedef struct NodeTexBrick { typedef struct NodeTexEnvironment { NodeTexBase base; ImageUser iuser; - int color_space; + int color_space DNA_DEPRECATED; int projection; int interpolation; char _pad[4]; @@ -1121,10 +1121,6 @@ typedef struct NodeCryptomatte { #define SHD_SKY_OLD 0 #define SHD_SKY_NEW 1 -/* image/environment texture */ -#define SHD_COLORSPACE_NONE 0 -#define SHD_COLORSPACE_COLOR 1 - /* environment texture */ #define SHD_PROJ_EQUIRECTANGULAR 0 #define SHD_PROJ_MIRROR_BALL 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 1aeb4a2f4d2..9bbb6f1656c 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -44,6 +44,7 @@ struct FluidsimSettings; struct GpencilBatchCache; struct Ipo; struct Material; +struct Mesh; struct Object; struct PartDeflect; struct ParticleSystem; @@ -136,6 +137,10 @@ typedef struct Object_Runtime { /** Only used for drawing the parent/child help-line. */ float parent_display_origin[3]; + /** Selection id of this object; only available in the original object */ + int select_id; + char _pad1[4]; + /** Axis aligned boundbox (in localspace). */ struct BoundBox *bb; @@ -156,11 +161,17 @@ typedef struct Object_Runtime { */ struct Mesh *mesh_deform_eval; + /* This is a mesh representation of corresponding object. + * It created when Python calls `object.to_mesh()`. */ + struct Mesh *object_as_temp_mesh; + /** Runtime evaluated curve-specific data, not stored in the file. */ struct CurveCache *curve_cache; /** Runtime grease pencil drawing data */ struct GpencilBatchCache *gpencil_cache; + + void *_pad2; /* Padding is here for win32s unconventional stuct alignment rules. */ } Object_Runtime; typedef struct Object { @@ -365,9 +376,7 @@ typedef struct Object { char empty_image_visibility_flag; char empty_image_depth; char empty_image_flag; - char _pad8[1]; - - int select_id; + char _pad8[5]; /** Contains data for levels of detail. */ ListBase lodlevels; @@ -600,7 +609,7 @@ enum { /* ob->restrictflag */ enum { - OB_RESTRICT_VIEW = 1 << 0, + OB_RESTRICT_VIEWPORT = 1 << 0, OB_RESTRICT_SELECT = 1 << 1, OB_RESTRICT_RENDER = 1 << 2, }; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index baa9b3ed5c3..0973405ce7b 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -661,19 +661,15 @@ typedef struct RenderData { */ int mode; + short frs_sec; + /** * What to do with the sky/background. * Picks sky/premul blending for the background. */ - short alphamode; - - /** - * The number of samples to use per pixel. - */ - short osa; + char alphamode; - short frs_sec; - char _pad[6]; + char _pad0[1]; /* safety, border and display rect */ rctf safety, border; @@ -1447,8 +1443,9 @@ typedef struct ToolSettings { /* Multires */ char multires_subdiv_type; - /* Alt+RMB option */ + /* Edge tagging, store operator settings (no UI access). */ char edge_mode; + char edge_mode_live_unwrap; char _pad1[1]; @@ -1503,7 +1500,7 @@ typedef struct ToolSettings { /* Normal Editing */ float normal_vector[3]; - int face_strength; + char _pad6[4]; } ToolSettings; /* *************************************************************** */ @@ -1566,6 +1563,11 @@ typedef struct SceneDisplay { float matcap_ssao_attenuation; int matcap_ssao_samples; + /** Method of AA for viewport rendering and image rendering */ + char viewport_aa; + char render_aa; + char _pad[6]; + /** OpenGL render engine settings. */ View3DShading shading; } SceneDisplay; @@ -1640,7 +1642,7 @@ typedef struct TransformOrientationSlot { char _pad0[7]; } TransformOrientationSlot; -/* Indices when used in Scene.orientation. */ +/** Indices when used in #Scene.orientation_slots */ enum { SCE_ORIENT_DEFAULT = 0, SCE_ORIENT_TRANSLATE = 1, @@ -1723,7 +1725,7 @@ typedef struct Scene { /* Units */ struct UnitSettings unit; - /* Grease Pencil - Annotations */ + /** Grease Pencil - Annotations */ struct bGPdata *gpd; /* Movie Tracking */ @@ -1764,15 +1766,15 @@ typedef struct Scene { /* **************** RENDERDATA ********************* */ -/* RenderData.flag */ +/** #RenderData.flag */ /* use preview range */ #define SCER_PRV_RANGE (1 << 0) #define SCER_LOCK_FRAME_SELECTION (1 << 1) /* show/use subframes (for checking motion blur) */ #define SCER_SHOW_SUBFRAME (1 << 3) -/* RenderData.mode */ -#define R_OSA (1 << 0) +/** #RenderData.mode */ +#define R_MODE_UNUSED_0 (1 << 0) /* dirty */ #define R_MODE_UNUSED_1 (1 << 1) /* cleared */ #define R_MODE_UNUSED_2 (1 << 2) /* cleared */ #define R_MODE_UNUSED_3 (1 << 3) /* cleared */ @@ -1804,7 +1806,7 @@ typedef struct Scene { #define R_PERSISTENT_DATA (1 << 26) /* keep data around for re-render */ #define R_MODE_UNUSED_27 (1 << 27) /* cleared */ -/* RenderData.seq_flag */ +/** #RenderData.seq_flag */ enum { R_SEQ_UNUSED_0 = (1 << 0), /* cleared */ R_SEQ_UNUSED_1 = (1 << 1), /* cleared */ @@ -1814,14 +1816,14 @@ enum { R_SEQ_OVERRIDE_SCENE_SETTINGS = (1 << 5), }; -/* RenderData.displaymode */ +/** #RenderData.displaymode */ #define R_OUTPUT_SCREEN 0 #define R_OUTPUT_AREA 1 #define R_OUTPUT_WINDOW 2 #define R_OUTPUT_NONE 3 /*#define R_OUTPUT_FORKED 4*/ -/* RenderData.filtertype (used for nodes) */ +/** #RenderData.filtertype (used for nodes) */ #define R_FILTER_BOX 0 #define R_FILTER_TENT 1 #define R_FILTER_QUAD 2 @@ -1831,7 +1833,7 @@ enum { #define R_FILTER_MITCH 6 #define R_FILTER_FAST_GAUSS 7 -/* RenderData.scemode */ +/** #RenderData.scemode */ #define R_DOSEQ (1 << 0) #define R_BG_RENDER (1 << 1) /* passepartout is camera option now, keep this for backward compatibility */ @@ -1856,7 +1858,7 @@ enum { #define R_EXR_CACHE_FILE (1 << 20) #define R_MULTIVIEW (1 << 21) -/* RenderData.stamp */ +/** #RenderData.stamp */ #define R_STAMP_TIME (1 << 0) #define R_STAMP_FRAME (1 << 1) #define R_STAMP_DATE (1 << 2) @@ -1881,10 +1883,12 @@ enum { R_STAMP_HOSTNAME) /** #RenderData.alphamode */ -#define R_ADDSKY 0 -#define R_ALPHAPREMUL 1 +enum { + R_ADDSKY = 0, + R_ALPHAPREMUL = 1, +}; -/* RenderData.color_mgt_flag */ +/** #RenderData.color_mgt_flag */ enum { /** deprecated, should only be used in versioning code only */ R_COLOR_MANAGEMENT = (1 << 0), @@ -2086,13 +2090,6 @@ enum { OB_DRAW_GROUPUSER_ALL = 2, }; -/* toolsettings->face_strength */ -enum { - FACE_STRENGTH_WEAK = -16384, - FACE_STRENGTH_MEDIUM = 0, - FACE_STRENGTH_STRONG = 16384, -}; - /* object_vgroup.c */ /* ToolSettings.vgroupsubset */ typedef enum eVGroupSelect { @@ -2244,14 +2241,6 @@ enum { #define UV_SELECT_FACE 4 #define UV_SELECT_ISLAND 8 -/* ToolSettings.edge_mode */ -#define EDGE_MODE_SELECT 0 -#define EDGE_MODE_TAG_SEAM 1 -#define EDGE_MODE_TAG_SHARP 2 -#define EDGE_MODE_TAG_CREASE 3 -#define EDGE_MODE_TAG_BEVEL 4 -#define EDGE_MODE_TAG_FREESTYLE 5 - /* ToolSettings.gpencil_flags */ typedef enum eGPencil_Flags { /* When creating new frames, the last frame gets used as the basis for the new one */ @@ -2366,19 +2355,19 @@ typedef enum eGPencil_Guide_Reference { /* SceneEEVEE->flag */ enum { - SCE_EEVEE_VOLUMETRIC_ENABLED = (1 << 0), + // SCE_EEVEE_VOLUMETRIC_ENABLED = (1 << 0), /* Unused */ SCE_EEVEE_VOLUMETRIC_LIGHTS = (1 << 1), SCE_EEVEE_VOLUMETRIC_SHADOWS = (1 << 2), // SCE_EEVEE_VOLUMETRIC_COLORED = (1 << 3), /* Unused */ SCE_EEVEE_GTAO_ENABLED = (1 << 4), SCE_EEVEE_GTAO_BENT_NORMALS = (1 << 5), SCE_EEVEE_GTAO_BOUNCE = (1 << 6), - SCE_EEVEE_DOF_ENABLED = (1 << 7), + // SCE_EEVEE_DOF_ENABLED = (1 << 7), /* Moved to camera->dof.flag */ SCE_EEVEE_BLOOM_ENABLED = (1 << 8), SCE_EEVEE_MOTION_BLUR_ENABLED = (1 << 9), SCE_EEVEE_SHADOW_HIGH_BITDEPTH = (1 << 10), SCE_EEVEE_TAA_REPROJECTION = (1 << 11), - SCE_EEVEE_SSS_ENABLED = (1 << 12), + // SCE_EEVEE_SSS_ENABLED = (1 << 12), /* Unused */ SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13), SCE_EEVEE_SSR_ENABLED = (1 << 14), SCE_EEVEE_SSR_REFRACTION = (1 << 15), @@ -2397,6 +2386,17 @@ enum { SHADOW_METHOD_MAX = 3, }; +/* SceneDisplay->render_aa, SceneDisplay->viewport_aa */ +enum { + SCE_DISPLAY_AA_OFF = 0, + SCE_DISPLAY_AA_FXAA = 1, + SCE_DISPLAY_AA_SAMPLES_5 = 5, + SCE_DISPLAY_AA_SAMPLES_8 = 8, + SCE_DISPLAY_AA_SAMPLES_11 = 11, + SCE_DISPLAY_AA_SAMPLES_16 = 16, + SCE_DISPLAY_AA_SAMPLES_32 = 32, +}; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 411777333a9..f5c2a518ef6 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -139,7 +139,7 @@ typedef struct Panel { struct uiLayout *layout; /** Defined as UI_MAX_NAME_STR. */ - char panelname[64], tabname[64]; + char panelname[64]; /** Panel name is identifier for restoring location. */ char drawname[64]; /** Offset within the region. */ @@ -155,8 +155,6 @@ typedef struct Panel { short snap; /** Panels are aligned according to increasing sort-order. */ int sortorder; - /** This panel is tabbed in *paneltab. */ - struct Panel *paneltab; /** Runtime for panel manipulation. */ void *activedata; /** Sub panels. */ @@ -599,31 +597,39 @@ enum { /* Region supports panel tabs (categories). */ #define RGN_TYPE_HAS_CATEGORY_MASK (1 << RGN_TYPE_UI) -/* region alignment */ -#define RGN_ALIGN_NONE 0 -#define RGN_ALIGN_TOP 1 -#define RGN_ALIGN_BOTTOM 2 -#define RGN_ALIGN_LEFT 3 -#define RGN_ALIGN_RIGHT 4 -#define RGN_ALIGN_HSPLIT 5 -#define RGN_ALIGN_VSPLIT 6 -#define RGN_ALIGN_FLOAT 7 -#define RGN_ALIGN_QSPLIT 8 -#define RGN_ALIGN_ENUM_MASK 0x0F +/** #ARegion.alignment */ +enum { + RGN_ALIGN_NONE = 0, + RGN_ALIGN_TOP = 1, + RGN_ALIGN_BOTTOM = 2, + RGN_ALIGN_LEFT = 3, + RGN_ALIGN_RIGHT = 4, + RGN_ALIGN_HSPLIT = 5, + RGN_ALIGN_VSPLIT = 6, + RGN_ALIGN_FLOAT = 7, + RGN_ALIGN_QSPLIT = 8, + /* Maximum 15. */ + + /* Flags start here. */ + RGN_SPLIT_PREV = 32, +}; -#define RGN_SPLIT_PREV 32 +/** Mask out flags so we can check the alignment. */ +#define RGN_ALIGN_ENUM_FROM_MASK(align) ((align) & ((1 << 4) - 1)) /** #ARegion.flag */ enum { RGN_FLAG_HIDDEN = (1 << 0), RGN_FLAG_TOO_SMALL = (1 << 1), - /* Force delayed reinit of region size data, so that region size is calculated + /** + * Force delayed reinit of region size data, so that region size is calculated * just big enough to show all its content (if enough space is available). - * Note that only ED_region_header supports this right now. */ + * Note that only ED_region_header supports this right now. + */ RGN_FLAG_DYNAMIC_SIZE = (1 << 2), - /* Region data is NULL'd on read, never written. */ + /** Region data is NULL'd on read, never written. */ RGN_FLAG_TEMP_REGIONDATA = (1 << 3), - /* The region must either use its prefsizex/y or be hidden. */ + /** The region must either use its prefsizex/y or be hidden. */ RGN_FLAG_PREFSIZE_OR_HIDDEN = (1 << 4), /** Size has been clamped (floating regions only). */ RGN_FLAG_SIZE_CLAMP_X = (1 << 5), diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h index 01e74da4e3b..efa7a308f88 100644 --- a/source/blender/makesdna/DNA_sdna_types.h +++ b/source/blender/makesdna/DNA_sdna_types.h @@ -35,7 +35,7 @@ typedef struct SDNA { bool data_alloc; /** Total number of struct members. */ - int nr_names, nr_names_alloc; + int names_len, names_len_alloc; /** Struct member names. */ const char **names; /** Result of #DNA_elem_array_size (aligned with #names). */ @@ -44,15 +44,14 @@ typedef struct SDNA { /** Size of a pointer in bytes. */ int pointer_size; - /** Number of basic types + struct types. */ - int nr_types; /** Type names. */ const char **types; + /** Number of basic types + struct types. */ + int types_len; + /** Type lengths. */ short *types_size; - /** Number of struct types. */ - int nr_structs; /** * sp = structs[a] is the address of a struct definition * sp[0] is struct type number, sp[1] amount of members @@ -61,6 +60,8 @@ typedef struct SDNA { * type and name numbers respectively. */ short **structs; + /** Number of struct types. */ + int structs_len; /** #GHash for faster lookups, requires WITH_DNA_GHASH to be used for now. */ struct GHash *structs_map; @@ -74,6 +75,8 @@ typedef struct SDNA { const char **names; /** Aligned with #SDNA.types, same pointers when unchanged. */ const char **types; + /** A version of #SDNA.structs_map that uses #SDNA.alias.types for it's keys. */ + struct GHash *structs_map; } alias; } SDNA; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 9e8ece0c6e8..20d4f7d96e4 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -247,7 +247,7 @@ typedef struct SpaceOutliner { short flag, outlinevis, storeflag, search_flags; int filter; char filter_state; - char _pad; + char show_restrict_flags; short filter_id_type; /** @@ -260,7 +260,7 @@ typedef struct SpaceOutliner { typedef enum eSpaceOutliner_Flag { SO_TESTBLOCKS = (1 << 0), SO_NEWSELECTED = (1 << 1), - SO_HIDE_RESTRICTCOLS = (1 << 2), + SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */ SO_HIDE_KEYINGSETINFO = (1 << 3), SO_SKIP_SORT_ALPHA = (1 << 4), } eSpaceOutliner_Flag; @@ -309,6 +309,17 @@ typedef enum eSpaceOutliner_StateFilter { SO_FILTER_OB_ACTIVE = 3, } eSpaceOutliner_StateFilter; +/* SpaceOutliner.show_restrict_flags */ +typedef enum eSpaceOutliner_ShowRestrictFlag { + SO_RESTRICT_ENABLE = (1 << 0), + SO_RESTRICT_SELECT = (1 << 1), + SO_RESTRICT_HIDE = (1 << 2), + SO_RESTRICT_VIEWPORT = (1 << 3), + SO_RESTRICT_RENDER = (1 << 4), + SO_RESTRICT_HOLDOUT = (1 << 5), + SO_RESTRICT_INDIRECT_ONLY = (1 << 6), +} eSpaceOutliner_Restrict; + /* SpaceOutliner.outlinevis */ typedef enum eSpaceOutliner_Mode { SO_SCENES = 0, diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 4a7b46fc154..9cab63dbfeb 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -38,11 +38,6 @@ struct ColorBand; #define MAX_STYLE_NAME 64 -#define GPU_VIEWPORT_QUALITY_FXAA 0.10f -#define GPU_VIEWPORT_QUALITY_TAA8 0.25f -#define GPU_VIEWPORT_QUALITY_TAA16 0.6f -#define GPU_VIEWPORT_QUALITY_TAA32 0.8f - /** default offered by Blender. * #uiFont.uifont_id */ typedef enum eUIFont_ID { @@ -189,6 +184,8 @@ typedef struct ThemeUI { char gizmo_b[4]; /* Icon Colors. */ + /** Scene items. */ + char icon_scene[4]; /** Collection items. */ char icon_collection[4]; /** Object items. */ @@ -199,6 +196,9 @@ typedef struct ThemeUI { char icon_modifier[4]; /** Shading related items. */ char icon_shading[4]; + /** Intensity of the border icons. >0 will render an border around themed + * icons. */ + float icon_border_intensity; } ThemeUI; /* try to put them all in one, if needed a special struct can be created as well @@ -283,6 +283,8 @@ typedef struct ThemeSpace { char cframe[4]; char time_keyframe[4], time_gp_keyframe[4]; char freestyle_edge_mark[4], freestyle_face_mark[4]; + char scrubbing_background[4]; + char _pad5[4]; char nurb_uline[4], nurb_vline[4]; char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4]; @@ -361,6 +363,14 @@ typedef struct ThemeSpace { char match[4]; /** Outliner - selected item. */ char selected_highlight[4]; + /** Outliner - selected object. */ + char selected_object[4]; + /** Outliner - active object. */ + char active_object[4]; + /** Outliner - edited object. */ + char edited_object[4]; + /** Outliner - row color difference. */ + char row_alternate[4]; /** Skin modifier root color. */ char skin_root[4]; @@ -372,7 +382,6 @@ typedef struct ThemeSpace { char anim_non_active[4]; /** Preview range overlay. */ char anim_preview_range[4]; - char _pad2[4]; /** NLA 'Tweaking' action/strip. */ char nla_tweaking[4]; @@ -398,6 +407,8 @@ typedef struct ThemeSpace { char metadatabg[4]; char metadatatext[4]; + + char _pad2[4]; } ThemeSpace; /* set of colors for use as a custom color set for Objects/Bones wire drawing */ @@ -535,6 +546,11 @@ typedef struct WalkNavigation { char _pad0[6]; } WalkNavigation; +typedef struct UserDef_Runtime { + char is_dirty; + char _pad0[7]; +} UserDef_Runtime; + typedef struct UserDef { /* UserDef has separate do-version handling, and can be read from other files */ int versionfile, subversionfile; @@ -542,8 +558,12 @@ typedef struct UserDef { /** #eUserPref_Flag. */ int flag; /** #eDupli_ID_Flags. */ - int dupflag; - int savetime; + short dupflag; + /** + * #eUserPref_PrefFlag preferences for the preferences. */ + char pref_flag; + char savetime; + char _pad4[4]; /** FILE_MAXDIR length. */ char tempdir[768]; char fontdir[768]; @@ -600,6 +620,7 @@ typedef struct UserDef { int dpi; /** Runtime, multiplier to scale UI elements based on DPI. */ float dpi_fac; + float inv_dpi_fac; /** Runtime, line width and point size based on DPI. */ float pixelsize; /** Deprecated, for forward compatibility. */ @@ -609,7 +630,7 @@ typedef struct UserDef { int scrollback; /** Node insert offset (aka auto-offset) margin, but might be useful for later stuff as well. */ char node_margin; - char _pad2[5]; + char _pad2[1]; /** #eUserpref_Translation_Flags. */ short transopts; short menuthreshold1, menuthreshold2; @@ -633,7 +654,7 @@ typedef struct UserDef { short undosteps; char _pad1[2]; int undomemory; - float gpu_viewport_quality; + float gpu_viewport_quality DNA_DEPRECATED; short gp_manhattendist, gp_euclideandist, gp_eraser; /** #eGP_UserdefSettings. */ short gp_settings; @@ -643,7 +664,7 @@ typedef struct UserDef { char _pad3[4]; short gizmo_flag, gizmo_size; short edit_studio_light; - char _pad6[2]; + short lookdev_sphere_size; short vbotimeout, vbocollectrate; short textimeout, texcollectrate; int memcachelimit; @@ -761,7 +782,12 @@ typedef struct UserDef { char factor_display_type; - char _pad5[3]; + char viewport_aa; + + char _pad5[2]; + + /** Runtime data (keep last). */ + UserDef_Runtime runtime; } UserDef; /* from blenkernel blender.c */ @@ -816,7 +842,7 @@ typedef enum eUserPref_Flag { USER_TOOLTIPS = (1 << 11), USER_TWOBUTTONMOUSE = (1 << 12), USER_NONUMPAD = (1 << 13), - USER_FLAG_UNUSED_14 = (1 << 14), /* cleared */ + USER_ADD_CURSORALIGNED = (1 << 14), USER_FILECOMPRESS = (1 << 15), USER_SAVE_PREVIEWS = (1 << 16), USER_CUSTOM_RANGE = (1 << 17), @@ -831,6 +857,10 @@ typedef enum eUserPref_Flag { USER_TOOLTIPS_PYTHON = (1 << 26), } eUserPref_Flag; +typedef enum eUserPref_PrefFlag { + USER_PREF_FLAG_SAVE = (1 << 0), +} eUserPref_PrefFlag; + /** #bPathCompare.flag */ typedef enum ePathCompare_Flag { USER_PATHCMP_GLOB = (1 << 0), diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index 0f25b47cb0b..8734a73c07a 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -151,10 +151,10 @@ enum { V2D_SCROLL_BOTTOM = (1 << 3), /* UNUSED = (1 << 4), */ V2D_SCROLL_HORIZONTAL = (V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM), - /* scale markings - vertical */ - V2D_SCROLL_SCALE_VERTICAL = (1 << 5), - /* scale markings - horizontal */ - V2D_SCROLL_SCALE_HORIZONTAL = (1 << 6), + /* display vertical scale handles */ + V2D_SCROLL_VERTICAL_HANDLES = (1 << 5), + /* display horizontal scale handles */ + V2D_SCROLL_HORIZONTAL_HANDLES = (1 << 6), /* induce hiding of scrollbars - set by region drawing in response to size of region */ V2D_SCROLL_VERTICAL_HIDE = (1 << 7), V2D_SCROLL_HORIZONTAL_HIDE = (1 << 8), diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index d5ac8cc197b..0170b27e15f 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -584,9 +584,8 @@ enum { /** Settings for offscreen rendering */ enum { V3D_OFSDRAW_NONE = (0), - V3D_OFSDRAW_USE_FULL_SAMPLE = (1 << 0), - V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 1), - V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 2), + V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0), + V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1), }; #define RV3D_CAMZOOM_MIN -30 diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index ad0765a58de..82c356ab662 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -39,9 +39,7 @@ #include "BLI_memarena.h" #include "BLI_string.h" -#ifdef WITH_DNA_GHASH -# include "BLI_ghash.h" -#endif +#include "BLI_ghash.h" #include "DNA_genfile.h" #include "DNA_sdna_types.h" // for SDNA ;-) @@ -161,6 +159,11 @@ void DNA_sdna_free(SDNA *sdna) MEM_SAFE_FREE(sdna->alias.names); MEM_SAFE_FREE(sdna->alias.types); +#ifdef WITH_DNA_GHASH + if (sdna->alias.structs_map) { + BLI_ghash_free(sdna->alias.structs_map, NULL, NULL); + } +#endif MEM_freeN(sdna); } @@ -222,49 +225,86 @@ static void printstruct(SDNA *sdna, short strnr) /** * Returns the index of the struct info for the struct with the specified name. */ -int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last) +static int dna_struct_find_nr_ex_impl( + /* From SDNA struct. */ + const char **types, + const int UNUSED(types_len), + short **const structs, + const int structs_len, +#ifdef WITH_DNA_GHASH + GHash *structs_map, +#endif + /* Regular args. */ + const char *str, + unsigned int *index_last) { - const short *sp = NULL; - - if (*index_last < sdna->nr_structs) { - sp = sdna->structs[*index_last]; - if (strcmp(sdna->types[sp[0]], str) == 0) { + if (*index_last < structs_len) { + const short *sp = structs[*index_last]; + if (STREQ(types[sp[0]], str)) { return *index_last; } } #ifdef WITH_DNA_GHASH { - void **index_p; - int a; - - index_p = BLI_ghash_lookup_p(sdna->structs_map, str); - + void **index_p = BLI_ghash_lookup_p(structs_map, str); if (index_p) { - a = POINTER_AS_INT(*index_p); - *index_last = a; - } - else { - a = -1; + const int index = POINTER_AS_INT(*index_p); + *index_last = index; + return index; } - return a; } #else { - int a; - - for (a = 0; a < sdna->nr_structs; a++) { - - sp = sdna->structs[a]; - - if (strcmp(sdna->types[sp[0]], str) == 0) { - *index_last = a; - return a; + for (int index = 0; index < structs_len; index++) { + const short *sp = structs[index]; + if (STREQ(types[sp[0]], str)) { + *index_last = index; + return index; } } } +#endif return -1; +} + +/** + * Returns the index of the struct info for the struct with the specified name. + */ +int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last) +{ + return dna_struct_find_nr_ex_impl( + /* Expand SDNA. */ + sdna->types, + sdna->types_len, + sdna->structs, + sdna->structs_len, +#ifdef WITH_DNA_GHASH + sdna->structs_map, #endif + /* Regular args. */ + str, + index_last); +} + +/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */ +int DNA_struct_alias_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last) +{ +#ifdef WITH_DNA_GHASH + BLI_assert(sdna->alias.structs_map != NULL); +#endif + return dna_struct_find_nr_ex_impl( + /* Expand SDNA. */ + sdna->alias.types, + sdna->types_len, + sdna->structs, + sdna->structs_len, +#ifdef WITH_DNA_GHASH + sdna->alias.structs_map, +#endif + /* Regular args. */ + str, + index_last); } int DNA_struct_find_nr(const SDNA *sdna, const char *str) @@ -273,6 +313,13 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str) return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy); } +/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */ +int DNA_struct_alias_find_nr(const SDNA *sdna, const char *str) +{ + unsigned int index_last_dummy = UINT_MAX; + return DNA_struct_alias_find_nr_ex(sdna, str, &index_last_dummy); +} + /* ************************* END DIV ********************** */ /* ************************* READ DNA ********************** */ @@ -317,14 +364,14 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error if (*data == MAKE_ID('N', 'A', 'M', 'E')) { data++; - sdna->nr_names = *data; + sdna->names_len = *data; if (do_endian_swap) { - BLI_endian_switch_int32(&sdna->nr_names); + BLI_endian_switch_int32(&sdna->names_len); } - sdna->nr_names_alloc = sdna->nr_names; + sdna->names_len_alloc = sdna->names_len; data++; - sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames"); + sdna->names = MEM_callocN(sizeof(void *) * sdna->names_len, "sdnanames"); } else { *r_error_message = "NAME error in SDNA file"; @@ -332,7 +379,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error } cp = (char *)data; - for (int nr = 0; nr < sdna->nr_names; nr++) { + for (int nr = 0; nr < sdna->names_len; nr++) { sdna->names[nr] = cp; /* "float gravity [3]" was parsed wrong giving both "gravity" and @@ -357,13 +404,13 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error if (*data == MAKE_ID('T', 'Y', 'P', 'E')) { data++; - sdna->nr_types = *data; + sdna->types_len = *data; if (do_endian_swap) { - BLI_endian_switch_int32(&sdna->nr_types); + BLI_endian_switch_int32(&sdna->types_len); } data++; - sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes"); + sdna->types = MEM_callocN(sizeof(void *) * sdna->types_len, "sdnatypes"); } else { *r_error_message = "TYPE error in SDNA file"; @@ -371,7 +418,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error } cp = (char *)data; - for (int nr = 0; nr < sdna->nr_types; nr++) { + for (int nr = 0; nr < sdna->types_len; nr++) { /* WARNING! See: DNA_struct_rename_legacy_hack_static_from_alias docs. */ sdna->types[nr] = DNA_struct_rename_legacy_hack_static_from_alias(cp); while (*cp) { @@ -390,17 +437,17 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error sdna->types_size = sp; if (do_endian_swap) { - BLI_endian_switch_int16_array(sp, sdna->nr_types); + BLI_endian_switch_int16_array(sp, sdna->types_len); } - sp += sdna->nr_types; + sp += sdna->types_len; } else { *r_error_message = "TLEN error in SDNA file"; return false; } /* prevent BUS error */ - if (sdna->nr_types & 1) { + if (sdna->types_len & 1) { sp++; } @@ -409,13 +456,13 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error if (*data == MAKE_ID('S', 'T', 'R', 'C')) { data++; - sdna->nr_structs = *data; + sdna->structs_len = *data; if (do_endian_swap) { - BLI_endian_switch_int32(&sdna->nr_structs); + BLI_endian_switch_int32(&sdna->structs_len); } data++; - sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs"); + sdna->structs = MEM_callocN(sizeof(void *) * sdna->structs_len, "sdnastrcs"); } else { *r_error_message = "STRC error in SDNA file"; @@ -423,7 +470,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error } sp = (short *)data; - for (int nr = 0; nr < sdna->nr_structs; nr++) { + for (int nr = 0; nr < sdna->structs_len; nr++) { sdna->structs[nr] = sp; if (do_endian_swap) { @@ -449,7 +496,7 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error { /* second part of gravity problem, setting "gravity" type to void */ if (gravity_fix > -1) { - for (int nr = 0; nr < sdna->nr_structs; nr++) { + for (int nr = 0; nr < sdna->structs_len; nr++) { sp = sdna->structs[nr]; if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0) { sp[10] = SDNA_TYPE_VOID; @@ -461,9 +508,9 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error #ifdef WITH_DNA_GHASH { /* create a ghash lookup to speed up */ - sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs); + sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->structs_len); - for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) { + for (intptr_t nr = 0; nr < sdna->structs_len; nr++) { sp = sdna->structs[nr]; BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], POINTER_FROM_INT(nr)); } @@ -495,8 +542,8 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error /* Cache name size. */ { - short *names_array_len = MEM_mallocN(sizeof(*names_array_len) * sdna->nr_names, __func__); - for (int i = 0; i < sdna->nr_names; i++) { + short *names_array_len = MEM_mallocN(sizeof(*names_array_len) * sdna->names_len, __func__); + for (int i = 0; i < sdna->names_len; i++) { names_array_len[i] = DNA_elem_array_size(sdna->names[i]); } sdna->names_array_len = names_array_len; @@ -586,7 +633,7 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn sp = sdna->structs[structnr]; typenr = sp[0]; - for (a = 0; a < sdna->nr_structs; a++) { + for (a = 0; a < sdna->structs_len; a++) { if ((a != structnr) && (compflags[a] == SDNA_CMP_EQUAL)) { sp = sdna->structs[a]; elems = sp[1]; @@ -615,19 +662,19 @@ const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna const char *str1, *str2; char *compflags; - if (oldsdna->nr_structs == 0) { + if (oldsdna->structs_len == 0) { printf("error: file without SDNA\n"); return NULL; } - compflags = MEM_callocN(oldsdna->nr_structs, "compflags"); + compflags = MEM_callocN(oldsdna->structs_len, "compflags"); /* we check all structs in 'oldsdna' and compare them with * the structs in 'newsdna' */ unsigned int newsdna_index_last = 0; - for (a = 0; a < oldsdna->nr_structs; a++) { + for (a = 0; a < oldsdna->structs_len; a++) { sp_old = oldsdna->structs[a]; /* search for type in cur */ @@ -691,14 +738,14 @@ const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna /* Because structs can be inside structs, we recursively * set flags when a struct is altered */ - for (a = 0; a < oldsdna->nr_structs; a++) { + for (a = 0; a < oldsdna->structs_len; a++) { if (compflags[a] == SDNA_CMP_NOT_EQUAL) { recurs_test_compflags(oldsdna, compflags, a); } } #if 0 - for (a = 0; a < oldsdna->nr_structs; a++) { + for (a = 0; a < oldsdna->structs_len; a++) { if (compflags[a] == SDNA_CMP_NOT_EQUAL) { spold = oldsdna->structs[a]; printf("changed: %s\n", oldsdna->types[spold[0]]); @@ -922,7 +969,14 @@ static int elem_strcmp(const char *name, const char *oname) * \param old: Pointer to struct information in sdna * \return true when existing, false otherwise. */ -static bool elem_exists(const SDNA *sdna, const char *type, const char *name, const short *old) +static bool elem_exists_impl( + /* Expand SDNA. */ + const char **types, + const char **names, + /* Regular args. */ + const char *type, + const char *name, + const short *old) { int a, elemcount; const char *otype, *oname; @@ -931,8 +985,8 @@ static bool elem_exists(const SDNA *sdna, const char *type, const char *name, co elemcount = old[1]; old += 2; for (a = 0; a < elemcount; a++, old += 2) { - otype = sdna->types[old[0]]; - oname = sdna->names[old[1]]; + otype = types[old[0]]; + oname = names[old[1]]; if (elem_strcmp(name, oname) == 0) { /* name equal */ return strcmp(type, otype) == 0; /* type equal */ @@ -941,6 +995,33 @@ static bool elem_exists(const SDNA *sdna, const char *type, const char *name, co return false; } +static bool elem_exists(const SDNA *sdna, const char *type, const char *name, const short *old) +{ + return elem_exists_impl( + /* Expand SDNA. */ + sdna->types, + sdna->names, + /* Regular args. */ + type, + name, + old); +} + +static bool elem_exists_alias(const SDNA *sdna, + const char *type, + const char *name, + const short *old) +{ + return elem_exists_impl( + /* Expand SDNA. */ + sdna->alias.types, + sdna->alias.names, + /* Regular args. */ + type, + name, + old); +} + /** * Returns the address of the data for the specified field within olddata * according to the struct format pointed to by old, or NULL if no such @@ -1397,6 +1478,25 @@ bool DNA_struct_elem_find(const SDNA *sdna, return false; } +/** \note requires #DNA_sdna_alias_data_ensure_structs_map to be called. */ +bool DNA_struct_alias_elem_find(const SDNA *sdna, + const char *stype, + const char *vartype, + const char *name) +{ + const int SDNAnr = DNA_struct_alias_find_nr(sdna, stype); + + if (SDNAnr != -1) { + const short *const spo = sdna->structs[SDNAnr]; + const bool found = elem_exists_alias(sdna, vartype, name, spo); + + if (found) { + return true; + } + } + return false; +} + /** * Returns the size in bytes of a primitive type. */ @@ -1483,14 +1583,14 @@ static bool DNA_sdna_patch_struct_member_nr(SDNA *sdna, strlen(elem_old_full), elem_old_full_offset_start); - if (sdna->nr_names == sdna->nr_names_alloc) { - sdna->nr_names_alloc += 64; - sdna->names = MEM_recallocN(sdna->names, sizeof(*sdna->names) * sdna->nr_names_alloc); + if (sdna->names_len == sdna->names_len_alloc) { + sdna->names_len_alloc += 64; + sdna->names = MEM_recallocN(sdna->names, sizeof(*sdna->names) * sdna->names_len_alloc); sdna->names_array_len = MEM_recallocN( - (void *)sdna->names_array_len, sizeof(*sdna->names_array_len) * sdna->nr_names_alloc); + (void *)sdna->names_array_len, sizeof(*sdna->names_array_len) * sdna->names_len_alloc); } const short name_nr_prev = sp[1]; - sp[1] = sdna->nr_names++; + sp[1] = sdna->names_len++; sdna->names[sp[1]] = elem_new_full; sdna->names_array_len[sp[1]] = sdna->names_array_len[name_nr_prev]; @@ -1533,14 +1633,14 @@ bool DNA_sdna_patch_struct_member(SDNA *sdna, static void sdna_expand_names(SDNA *sdna) { int names_expand_len = 0; - for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) { const short *sp = sdna->structs[struct_nr]; names_expand_len += sp[1]; } const char **names_expand = MEM_mallocN(sizeof(*names_expand) * names_expand_len, __func__); int names_expand_index = 0; - for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) { /* We can't edit this memory 'sdna->structs' points to (readonly datatoc file). */ const short *sp = sdna->structs[struct_nr]; short *sp_expand = BLI_memarena_alloc(sdna->mem_arena, sizeof(short[2]) * (1 + sp[1])); @@ -1558,7 +1658,7 @@ static void sdna_expand_names(SDNA *sdna) } MEM_freeN((void *)sdna->names); sdna->names = names_expand; - sdna->nr_names = names_expand_len; + sdna->names_len = names_expand_len; } static const char *dna_sdna_alias_alias_from_static_elem_full(SDNA *sdna, @@ -1600,8 +1700,8 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna) DNA_RENAME_ALIAS_FROM_STATIC, &struct_map_alias_from_static, &elem_map_alias_from_static); if (sdna->alias.types == NULL) { - sdna->alias.types = MEM_mallocN(sizeof(*sdna->alias.types) * sdna->nr_types, __func__); - for (int type_nr = 0; type_nr < sdna->nr_types; type_nr++) { + sdna->alias.types = MEM_mallocN(sizeof(*sdna->alias.types) * sdna->types_len, __func__); + for (int type_nr = 0; type_nr < sdna->types_len; type_nr++) { const char *struct_name_static = sdna->types[type_nr]; if (use_legacy_hack) { @@ -1615,8 +1715,8 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna) if (sdna->alias.names == NULL) { sdna_expand_names(sdna); - sdna->alias.names = MEM_mallocN(sizeof(*sdna->alias.names) * sdna->nr_names, __func__); - for (int struct_nr = 0; struct_nr < sdna->nr_structs; struct_nr++) { + sdna->alias.names = MEM_mallocN(sizeof(*sdna->alias.names) * sdna->names_len, __func__); + for (int struct_nr = 0; struct_nr < sdna->structs_len; struct_nr++) { const short *sp = sdna->structs[struct_nr]; const char *struct_name_static = sdna->types[sp[0]]; @@ -1642,4 +1742,24 @@ void DNA_sdna_alias_data_ensure(SDNA *sdna) BLI_ghash_free(elem_map_alias_from_static, MEM_freeN, NULL); } +/** + * Separated from #DNA_sdna_alias_data_ensure because it's not needed + * unless we want to lookup aliased struct names (#DNA_struct_alias_find_nr and friends). + */ +void DNA_sdna_alias_data_ensure_structs_map(SDNA *sdna) +{ + DNA_sdna_alias_data_ensure(sdna); +#ifdef WITH_DNA_GHASH + /* create a ghash lookup to speed up */ + struct GHash *structs_map = BLI_ghash_str_new_ex(__func__, sdna->structs_len); + for (intptr_t nr = 0; nr < sdna->structs_len; nr++) { + const short *sp = sdna->structs[nr]; + BLI_ghash_insert(structs_map, (void *)sdna->alias.types[sp[0]], POINTER_FROM_INT(nr)); + } + sdna->alias.structs_map = structs_map; +#else + UNUSED_VARS(sdna); +#endif +} + /** \} */ diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index b9e0853b1ab..3aa0ff4b28a 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -58,12 +58,12 @@ DNA_STRUCT_RENAME(SpaceIpo, SpaceGraph) DNA_STRUCT_RENAME(SpaceOops, SpaceOutliner) DNA_STRUCT_RENAME_ELEM(BPoint, alfa, tilt) DNA_STRUCT_RENAME_ELEM(BezTriple, alfa, tilt) -DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x) -DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x) DNA_STRUCT_RENAME_ELEM(Bone, curveInX, curve_in_x) DNA_STRUCT_RENAME_ELEM(Bone, curveInY, curve_in_y) DNA_STRUCT_RENAME_ELEM(Bone, curveOutX, curve_out_x) DNA_STRUCT_RENAME_ELEM(Bone, curveOutY, curve_out_y) +DNA_STRUCT_RENAME_ELEM(Bone, scaleIn, scale_in_x) +DNA_STRUCT_RENAME_ELEM(Bone, scaleOut, scale_out_x) DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance) DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end) DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start) @@ -77,12 +77,13 @@ DNA_STRUCT_RENAME_ELEM(ParticleSettings, dup_ob, instance_object) DNA_STRUCT_RENAME_ELEM(ParticleSettings, dupliweights, instance_weights) DNA_STRUCT_RENAME_ELEM(View3D, far, clip_end) DNA_STRUCT_RENAME_ELEM(View3D, near, clip_start) -DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x) -DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x) DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInX, curve_in_x) DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveInY, curve_in_y) DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutX, curve_out_x) DNA_STRUCT_RENAME_ELEM(bPoseChannel, curveOutY, curve_out_y) +DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleIn, scale_in_x) +DNA_STRUCT_RENAME_ELEM(bPoseChannel, scaleOut, scale_out_x) +DNA_STRUCT_RENAME_ELEM(bSameVolumeConstraint, flag, free_axis) DNA_STRUCT_RENAME_ELEM(bTheme, tact, space_action) DNA_STRUCT_RENAME_ELEM(bTheme, tbuts, space_properties) DNA_STRUCT_RENAME_ELEM(bTheme, tclip, space_clip) diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 0ea1ca9c018..7e53231a547 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -41,6 +41,8 @@ * numbers give more output. */ +#define DNA_DEPRECATED_ALLOW + #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -142,10 +144,10 @@ static const char *includefiles[] = { static MemArena *mem_arena = NULL; -static int maxdata = 500000, maxnr = 50000; -static int nr_names = 0; -static int nr_types = 0; -static int nr_structs = 0; +static int max_data_size = 500000, max_array_len = 50000; +static int names_len = 0; +static int types_len = 0; +static int structs_len = 0; /** At address `names[a]` is string `a`. */ static char **names; /** At address `types[a]` is string `a`. */ @@ -159,7 +161,7 @@ static short *types_size_64; /** At `sp = structs[a]` is the first address of a struct definition: * - `sp[0]` is type number. * - `sp[1]` is the length of the element array (next). - * - `sp[2]` sp[3] is [(type_nr, name_nr), ..] (number of pairs is defined by `sp[1]`), + * - `sp[2]` sp[3] is [(type_index, name_index), ..] (number of pairs is defined by `sp[1]`), */ static short **structs, *structdata; @@ -342,7 +344,6 @@ static bool is_name_legal(const char *name) static int add_type(const char *str, int size) { - int nr; char *cp; /* first do validity check */ @@ -358,14 +359,14 @@ static int add_type(const char *str, int size) str = version_struct_static_from_alias(str); /* search through type array */ - for (nr = 0; nr < nr_types; nr++) { - if (strcmp(str, types[nr]) == 0) { + for (int index = 0; index < types_len; index++) { + if (strcmp(str, types[index]) == 0) { if (size) { - types_size_native[nr] = size; - types_size_32[nr] = size; - types_size_64[nr] = size; + types_size_native[index] = size; + types_size_32[index] = size; + types_size_64[index] = size; } - return nr; + return index; } } @@ -373,18 +374,18 @@ static int add_type(const char *str, int size) const int str_size = strlen(str) + 1; cp = BLI_memarena_alloc(mem_arena, str_size); memcpy(cp, str, str_size); - types[nr_types] = cp; - types_size_native[nr_types] = size; - types_size_32[nr_types] = size; - types_size_64[nr_types] = size; + types[types_len] = cp; + types_size_native[types_len] = size; + types_size_32[types_len] = size; + types_size_64[types_len] = size; - if (nr_types >= maxnr) { + if (types_len >= max_array_len) { printf("too many types\n"); - return nr_types - 1; + return types_len - 1; } - nr_types++; + types_len++; - return nr_types - 1; + return types_len - 1; } /** @@ -511,7 +512,7 @@ static int add_name(const char *str) } /* search name array */ - for (nr = 0; nr < nr_names; nr++) { + for (nr = 0; nr < names_len; nr++) { if (strcmp(name, names[nr]) == 0) { return nr; } @@ -526,15 +527,15 @@ static int add_name(const char *str) const int name_size = strlen(name) + 1; cp = BLI_memarena_alloc(mem_arena, name_size); memcpy(cp, name, name_size); - names[nr_names] = cp; + names[names_len] = cp; - if (nr_names >= maxnr) { + if (names_len >= max_array_len) { printf("too many names\n"); - return nr_names - 1; + return names_len - 1; } - nr_names++; + names_len++; - return nr_names - 1; + return names_len - 1; } static short *add_struct(int namecode) @@ -542,23 +543,23 @@ static short *add_struct(int namecode) int len; short *sp; - if (nr_structs == 0) { + if (structs_len == 0) { structs[0] = structdata; } else { - sp = structs[nr_structs - 1]; + sp = structs[structs_len - 1]; len = sp[1]; - structs[nr_structs] = sp + 2 * len + 2; + structs[structs_len] = sp + 2 * len + 2; } - sp = structs[nr_structs]; + sp = structs[structs_len]; sp[0] = namecode; - if (nr_structs >= maxnr) { + if (structs_len >= max_array_len) { printf("too many structs\n"); return sp; } - nr_structs++; + structs_len++; return sp; } @@ -894,7 +895,7 @@ static bool check_field_alignment( static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char *base_directory) { - int unknown = nr_structs, lastunknown; + int unknown = structs_len, lastunknown; bool dna_error = false; /* Write test to verify sizes are accurate. */ @@ -912,7 +913,7 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char unknown = 0; /* check all structs... */ - for (int a = 0; a < nr_structs; a++) { + for (int a = 0; a < structs_len; a++) { const short *structpoin = structs[a]; const int structtype = structpoin[0]; const char *structname = version_struct_alias_from_static(types[structtype]); @@ -1097,7 +1098,7 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char if (debugSDNA) { fprintf(stderr, "*** Known structs :\n"); - for (int a = 0; a < nr_structs; a++) { + for (int a = 0; a < structs_len; a++) { const short *structpoin = structs[a]; const int structtype = structpoin[0]; @@ -1110,7 +1111,7 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char fprintf(stderr, "*** Unknown structs :\n"); - for (int a = 0; a < nr_structs; a++) { + for (int a = 0; a < structs_len; a++) { const short *structpoin = structs[a]; const int structtype = structpoin[0]; @@ -1148,7 +1149,7 @@ static void dna_write(FILE *file, const void *pntr, const int size) void print_struct_sizes(void) { - int a, unknown = nr_structs, structtype; + int a, unknown = structs_len, structtype; /*int lastunknown;*/ /*UNUSED*/ const short *structpoin; printf("\n\n*** All detected structs:\n"); @@ -1158,7 +1159,7 @@ void print_struct_sizes(void) unknown = 0; /* check all structs... */ - for (a = 0; a < nr_structs; a++) { + for (a = 0; a < structs_len; a++) { structpoin = structs[a]; structtype = structpoin[0]; printf("\t%s\t:%d\n", types[structtype], types_size_native[structtype]); @@ -1188,15 +1189,15 @@ static int make_structDNA(const char *base_directory, mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); /* the longest known struct is 50k, so we assume 100k is sufficient! */ - structdata = MEM_callocN(maxdata, "structdata"); + structdata = MEM_callocN(max_data_size, "structdata"); /* a maximum of 5000 variables, must be sufficient? */ - names = MEM_callocN(sizeof(char *) * maxnr, "names"); - types = MEM_callocN(sizeof(char *) * maxnr, "types"); - types_size_native = MEM_callocN(sizeof(short) * maxnr, "types_size_native"); - types_size_32 = MEM_callocN(sizeof(short) * maxnr, "types_size_32"); - types_size_64 = MEM_callocN(sizeof(short) * maxnr, "types_size_64"); - structs = MEM_callocN(sizeof(short *) * maxnr, "structs"); + names = MEM_callocN(sizeof(char *) * max_array_len, "names"); + types = MEM_callocN(sizeof(char *) * max_array_len, "types"); + types_size_native = MEM_callocN(sizeof(short) * max_array_len, "types_size_native"); + types_size_32 = MEM_callocN(sizeof(short) * max_array_len, "types_size_32"); + types_size_64 = MEM_callocN(sizeof(short) * max_array_len, "types_size_64"); + structs = MEM_callocN(sizeof(short *) * max_array_len, "structs"); /* Build versioning data */ DNA_alias_maps(DNA_RENAME_ALIAS_FROM_STATIC, @@ -1231,7 +1232,7 @@ static int make_structDNA(const char *base_directory, add_type("void", 0); /* SDNA_TYPE_VOID */ /* the defines above shouldn't be output in the padding file... */ - firststruct = nr_types; + firststruct = types_len; /* add all include files defined in the global array */ /* Since the internal file+path name buffer has limited length, I do a */ @@ -1258,19 +1259,19 @@ static int make_structDNA(const char *base_directory, /* short *elem; */ short num_types; - printf("nr_names %d nr_types %d nr_structs %d\n", nr_names, nr_types, nr_structs); - for (a = 0; a < nr_names; a++) { + printf("names_len %d types_len %d structs_len %d\n", names_len, types_len, structs_len); + for (a = 0; a < names_len; a++) { printf(" %s\n", names[a]); } printf("\n"); sp = types_size_native; - for (a = 0; a < nr_types; a++, sp++) { + for (a = 0; a < types_len; a++, sp++) { printf(" %s %d\n", types[a], *sp); } printf("\n"); - for (a = 0; a < nr_structs; a++) { + for (a = 0; a < structs_len; a++) { sp = structs[a]; printf(" struct %s elems: %d size: %d\n", types[sp[0]], sp[1], types_size_native[sp[0]]); num_types = sp[1]; @@ -1286,7 +1287,7 @@ static int make_structDNA(const char *base_directory, DEBUG_PRINTF(0, "Writing file ... "); - if (nr_names == 0 || nr_structs == 0) { + if (names_len == 0 || structs_len == 0) { /* pass */ } else { @@ -1297,11 +1298,11 @@ static int make_structDNA(const char *base_directory, /* write names */ dna_write(file, "NAME", 4); - len = nr_names; + len = names_len; dna_write(file, &len, 4); /* write array */ len = 0; - for (int nr = 0; nr < nr_names; nr++) { + for (int nr = 0; nr < names_len; nr++) { int name_size = strlen(names[nr]) + 1; dna_write(file, names[nr], name_size); len += name_size; @@ -1313,11 +1314,11 @@ static int make_structDNA(const char *base_directory, /* write TYPES */ dna_write(file, "TYPE", 4); - len = nr_types; + len = types_len; dna_write(file, &len, 4); /* write array */ len = 0; - for (int nr = 0; nr < nr_types; nr++) { + for (int nr = 0; nr < types_len; nr++) { int type_size = strlen(types[nr]) + 1; dna_write(file, types[nr], type_size); len += type_size; @@ -1330,19 +1331,19 @@ static int make_structDNA(const char *base_directory, /* WRITE TYPELENGTHS */ dna_write(file, "TLEN", 4); - len = 2 * nr_types; - if (nr_types & 1) { + len = 2 * types_len; + if (types_len & 1) { len += 2; } dna_write(file, types_size_native, len); /* WRITE STRUCTS */ dna_write(file, "STRC", 4); - len = nr_structs; + len = structs_len; dna_write(file, &len, 4); /* calc datablock size */ - sp = structs[nr_structs - 1]; + sp = structs[structs_len - 1]; sp += 2 + 2 * (sp[1]); len = (intptr_t)((char *)sp - (char *)structs[0]); len = (len + 3) & ~3; @@ -1355,7 +1356,7 @@ static int make_structDNA(const char *base_directory, { fprintf(file_offsets, "#define SDNA_TYPE_FROM_STRUCT(id) _SDNA_TYPE_##id\n"); fprintf(file_offsets, "enum {\n"); - for (i = 0; i < nr_structs; i++) { + for (i = 0; i < structs_len; i++) { const short *structpoin = structs[i]; const int structtype = structpoin[0]; fprintf(file_offsets, @@ -1363,7 +1364,7 @@ static int make_structDNA(const char *base_directory, version_struct_alias_from_static(types[structtype]), i); } - fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs); + fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", structs_len); fprintf(file_offsets, "};\n\n"); } @@ -1371,7 +1372,7 @@ static int make_structDNA(const char *base_directory, * do last because names are stripped. */ { GSet *names_unique = BLI_gset_str_new_ex(__func__, 512); - for (int struct_nr = 0; struct_nr < nr_structs; struct_nr++) { + for (int struct_nr = 0; struct_nr < structs_len; struct_nr++) { sp = structs[struct_nr]; const char *struct_name = types[sp[0]]; const int len = sp[1]; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a7b111d49da..30abf0f54bf 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -97,6 +97,7 @@ extern StructRNA RNA_BuildGpencilModifier; extern StructRNA RNA_BuildModifier; extern StructRNA RNA_CacheFile; extern StructRNA RNA_Camera; +extern StructRNA RNA_CameraDOFSettings; extern StructRNA RNA_CastModifier; extern StructRNA RNA_ChildOfConstraint; extern StructRNA RNA_ChildParticle; @@ -725,6 +726,7 @@ extern StructRNA RNA_View3DOverlay; extern StructRNA RNA_View3DShading; extern StructRNA RNA_ViewLayer; extern StructRNA RNA_VoronoiTexture; +extern StructRNA RNA_WalkNavigation; extern StructRNA RNA_WarpModifier; extern StructRNA RNA_WaveModifier; extern StructRNA RNA_WeightedNormalModifier; @@ -1030,9 +1032,12 @@ void *RNA_property_enum_py_data_get(PropertyRNA *prop); int RNA_property_enum_step( const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step); -PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop); -void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value); -PointerRNA RNA_property_pointer_get_default(PointerRNA *ptr, PropertyRNA *prop); +PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) ATTR_NONNULL(1, 2); +void RNA_property_pointer_set(PointerRNA *ptr, + PropertyRNA *prop, + PointerRNA ptr_value, + struct ReportList *reports) ATTR_NONNULL(1, 2); +PointerRNA RNA_property_pointer_get_default(PointerRNA *ptr, PropertyRNA *prop) ATTR_NONNULL(1, 2); void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 59c03cf34b3..0beb14614ec 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -48,6 +48,7 @@ void RNA_define_free(BlenderRNA *brna); void RNA_free(BlenderRNA *brna); void RNA_define_verify_sdna(bool verify); void RNA_define_animate_sdna(bool animate); +void RNA_define_fallback_property_update(int noteflag, const char *updatefunc); void RNA_init(void); void RNA_exit(void); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 119186ff748..02aaef44a1f 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -96,6 +96,7 @@ extern const EnumPropertyItem rna_enum_keyblock_type_items[]; extern const EnumPropertyItem rna_enum_keyingset_path_grouping_items[]; extern const EnumPropertyItem rna_enum_keying_flag_items[]; +extern const EnumPropertyItem rna_enum_keying_flag_items_api[]; extern const EnumPropertyItem rna_enum_keyframe_paste_offset_items[]; extern const EnumPropertyItem rna_enum_keyframe_paste_merge_items[]; diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 3e948e2d712..35045a3a408 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1033,10 +1033,10 @@ static char *rna_def_property_set_func( break; } case PROP_POINTER: { - fprintf(f, "void %s(PointerRNA *ptr, PointerRNA value)\n", func); + fprintf(f, "void %s(PointerRNA *ptr, PointerRNA value, struct ReportList *reports)\n", func); fprintf(f, "{\n"); if (manualfunc) { - fprintf(f, " %s(ptr, value);\n", manualfunc); + fprintf(f, " %s(ptr, value, reports);\n", manualfunc); } else { rna_print_data_get(f, dp); @@ -2024,7 +2024,7 @@ static void rna_def_function_funcs_header(FILE *f, StructRNA *srna, FunctionDefR char funcname[2048]; rna_construct_wrapper_function_name( - funcname, sizeof(funcname), srna->identifier, func->identifier, NULL); + funcname, sizeof(funcname), srna->identifier, func->identifier, "func"); rna_generate_static_parameter_prototypes(f, srna, dfunc, funcname, 1); } @@ -2452,7 +2452,7 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func int first = 1; rna_construct_wrapper_function_name( - funcname, sizeof(funcname), srna->identifier, func->identifier, NULL); + funcname, sizeof(funcname), srna->identifier, func->identifier, "func"); fprintf(f, "%s(", funcname); @@ -2615,7 +2615,7 @@ static void rna_def_function_wrapper_funcs(FILE *f, StructDefRNA *dsrna, Functio } rna_construct_wrapper_function_name( - funcname, sizeof(funcname), srna->identifier, func->identifier, NULL); + funcname, sizeof(funcname), srna->identifier, func->identifier, "func"); rna_generate_static_parameter_prototypes(f, srna, dfunc, funcname, 0); diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 149cd7caf84..7e6a3e70b9d 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -435,6 +435,11 @@ StructRNA *rna_PropertyGroup_refine(PointerRNA *ptr) return ptr->type; } +static ID *rna_ID_evaluated_get(ID *id, struct Depsgraph *depsgraph) +{ + return DEG_get_evaluated_id(depsgraph, id); +} + static ID *rna_ID_copy(ID *id, Main *bmain) { ID *newid; @@ -458,7 +463,7 @@ static ID *rna_ID_override_create(ID *id, Main *bmain) return BKE_override_static_create_from_id(bmain, id); } -static void rna_ID_update_tag(ID *id, ReportList *reports, int flag) +static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag) { /* XXX, new function for this! */ # if 0 @@ -473,6 +478,8 @@ static void rna_ID_update_tag(ID *id, ReportList *reports, int flag) /* pass */ } else { + int allow_flag = 0; + /* ensure flag us correct for the type */ switch (GS(id->name)) { case ID_OB: @@ -480,28 +487,35 @@ static void rna_ID_update_tag(ID *id, ReportList *reports, int flag) * object types supports different flags. Maybe does not worth checking * for this at all. Or maybe let dependency graph to return whether * the tag was valid or not. */ - if (flag & ~(ID_RECALC_ALL)) { - BKE_report(reports, RPT_ERROR, "'Refresh' incompatible with Object ID type"); - return; - } + allow_flag = ID_RECALC_ALL; break; /* Could add particle updates later */ # if 0 case ID_PA: - if (flag & ~(OB_RECALC_ALL | PSYS_RECALC)) { - BKE_report(reports, RPT_ERROR, "'Refresh' incompatible with ParticleSettings ID type"); - return; - } + allow_flag = OB_RECALC_ALL | PSYS_RECALC; break; # endif + case ID_AC: + allow_flag = ID_RECALC_ANIMATION; + break; default: - BKE_report( - reports, RPT_ERROR, "This ID type is not compatible with any 'refresh' options"); - return; + if (id_can_have_animdata(id)) { + allow_flag = ID_RECALC_ANIMATION; + } + } + + if (flag & ~allow_flag) { + StructRNA *srna = ID_code_to_RNA_type(GS(id->name)); + BKE_reportf(reports, + RPT_ERROR, + "%s is not compatible with %s 'refresh' options", + RNA_struct_identifier(srna), + allow_flag ? "the specified" : "any"); + return; } } - DEG_id_tag_update(id, flag); + DEG_id_tag_update_ex(bmain, id, flag); } static void rna_ID_user_clear(ID *id) @@ -1446,6 +1460,15 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL); /* functions */ + func = RNA_def_function(srna, "evaluated_get", "rna_ID_evaluated_get"); + RNA_def_function_ui_description( + func, "Get corresponding evaluated ID from the given dependency graph"); + parm = RNA_def_pointer( + func, "depsgraph", "Depsgraph", "", "Dependency graph to perform lookup in"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "copy", "rna_ID_copy"); RNA_def_function_ui_description( func, "Create a copy of this data-block (not supported for all data-blocks)"); @@ -1517,7 +1540,7 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Clear animation on this this ID"); func = RNA_def_function(srna, "update_tag", "rna_ID_update_tag"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Tag the ID to update its display data, " "e.g. when calling :class:`bpy.types.Scene.update`"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index d5dfd0b5503..20358ca80fd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -302,7 +302,7 @@ static IDProperty *rna_idproperty_ui_ensure(PointerRNA *ptr, PropertyRNA *prop, idprop = IDP_New(IDP_GROUP, &dummy, RNA_IDP_UI); if (!IDP_AddToGroup(props, idprop)) { - IDP_FreeProperty(idprop); + IDP_FreePropertyContent(idprop); return NULL; } } @@ -316,7 +316,7 @@ static IDProperty *rna_idproperty_ui_ensure(PointerRNA *ptr, PropertyRNA *prop, rv = IDP_New(IDP_GROUP, &dummy, name); if (!IDP_AddToGroup(idprop, rv)) { - IDP_FreeProperty(rv); + IDP_FreePropertyContent(rv); return NULL; } } @@ -370,7 +370,7 @@ static bool rna_idproperty_ui_set_default(PointerRNA *ptr, item = IDP_New(type, value, "default"); if (!IDP_AddToGroup(idp_ui, item)) { - IDP_FreeProperty(item); + IDP_FreePropertyContent(item); return false; } } @@ -3733,24 +3733,29 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) } } -void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value) +void RNA_property_pointer_set(PointerRNA *ptr, + PropertyRNA *prop, + PointerRNA ptr_value, + ReportList *reports) { PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; BLI_assert(RNA_property_type(prop) == PROP_POINTER); /* Check types */ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) { - printf("%s: expected %s type, not %s.\n", - __func__, - pprop->type->identifier, - ptr_value.type->identifier); + BKE_reportf(reports, + RPT_ERROR, + "%s: expected %s type, not %s.\n", + __func__, + pprop->type->identifier, + ptr_value.type->identifier); return; } /* RNA */ if (pprop->set && !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) && !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data)) { - pprop->set(ptr, ptr_value); + pprop->set(ptr, ptr_value, reports); } /* IDProperty */ else if (prop->flag & PROP_EDITABLE) { @@ -3961,7 +3966,7 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA item = IDP_New(IDP_GROUP, &val, ""); IDP_AppendArray(idprop, item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */ - /* IDP_FreeProperty(item); */ + /* IDP_FreePropertyContent(item); */ MEM_freeN(item); rna_idproperty_touch(idprop); } @@ -3977,7 +3982,7 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA item = IDP_New(IDP_GROUP, &val, ""); IDP_AppendArray(idprop, item); /* IDP_AppendArray does a shallow copy (memcpy), only free memory */ - /* IDP_FreeProperty(item); */ + /* IDP_FreePropertyContent(item); */ MEM_freeN(item); } } @@ -6422,7 +6427,7 @@ void RNA_pointer_set(PointerRNA *ptr, const char *name, PointerRNA ptr_value) PropertyRNA *prop = RNA_struct_find_property(ptr, name); if (prop) { - RNA_property_pointer_set(ptr, prop, ptr_value); + RNA_property_pointer_set(ptr, prop, ptr_value, NULL); } else { printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name); @@ -7971,7 +7976,7 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) case PROP_POINTER: { PointerRNA value = RNA_property_pointer_get_default(ptr, prop); - RNA_property_pointer_set(ptr, prop, value); + RNA_property_pointer_set(ptr, prop, value, NULL); return true; } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index bb3585df24e..4e98db21089 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -214,7 +214,9 @@ static PointerRNA rna_Action_active_pose_marker_get(PointerRNA *ptr) ptr, &RNA_TimelineMarker, BLI_findlink(&act->markers, act->active_marker - 1)); } -static void rna_Action_active_pose_marker_set(PointerRNA *ptr, PointerRNA value) +static void rna_Action_active_pose_marker_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bAction *act = (bAction *)ptr->data; act->active_marker = BLI_findindex(&act->markers, value.data) + 1; @@ -339,7 +341,7 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_INCL_HIDDEN); RNA_def_property_ui_text( prop, "Display Hidden", "Include channels from objects/bone that are not visible"); - RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); + RNA_def_property_ui_icon(prop, ICON_OBJECT_HIDDEN, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); prop = RNA_def_property(srna, "use_datablock_sort", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 15429ec6b5e..6228414e4f4 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -72,6 +72,43 @@ const EnumPropertyItem rna_enum_keying_flag_items[] = { {0, NULL, 0, NULL, NULL}, }; +/* Contains additional flags suitable for use in Python API functions. */ +const EnumPropertyItem rna_enum_keying_flag_items_api[] = { + {INSERTKEY_NEEDED, + "INSERTKEY_NEEDED", + 0, + "Only Needed", + "Only insert keyframes where they're needed in the relevant F-Curves"}, + {INSERTKEY_MATRIX, + "INSERTKEY_VISUAL", + 0, + "Visual Keying", + "Insert keyframes based on 'visual transforms'"}, + {INSERTKEY_XYZ2RGB, + "INSERTKEY_XYZ_TO_RGB", + 0, + "XYZ=RGB Colors", + "Color for newly added transformation F-Curves (Location, Rotation, Scale) " + "and also Color is based on the transform axis"}, + {INSERTKEY_REPLACE, + "INSERTKEY_REPLACE", + 0, + "Replace Existing", + "Only replace existing keyframes"}, + {INSERTKEY_AVAILABLE, + "INSERTKEY_AVAILABLE", + 0, + "Only Available", + "Don't create F-Curves when they don't already exist"}, + {INSERTKEY_CYCLE_AWARE, + "INSERTKEY_CYCLE_AWARE", + 0, + "Cycle Aware Keying", + "When inserting into a curve with cyclic extrapolation, remap the keyframe inside " + "the cycle time range, and if changing an end key, also update the other one"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "BLI_math_base.h" @@ -114,7 +151,9 @@ static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_i return PROP_EDITABLE; } -static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value) +static void rna_AnimData_action_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { ID *ownerId = (ID *)ptr->id.data; @@ -424,7 +463,9 @@ static PointerRNA rna_KeyingSet_active_ksPath_get(PointerRNA *ptr) ptr, &RNA_KeyingSetPath, BLI_findlink(&ks->paths, ks->active_path - 1)); } -static void rna_KeyingSet_active_ksPath_set(PointerRNA *ptr, PointerRNA value) +static void rna_KeyingSet_active_ksPath_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { KeyingSet *ks = (KeyingSet *)ptr->data; KS_Path *ksp = (KS_Path *)value.data; @@ -575,7 +616,9 @@ static PointerRNA rna_NlaTrack_active_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_NlaTrack, track); } -static void rna_NlaTrack_active_set(PointerRNA *ptr, PointerRNA value) +static void rna_NlaTrack_active_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { AnimData *adt = (AnimData *)ptr->data; NlaTrack *track = (NlaTrack *)value.data; @@ -1266,6 +1309,9 @@ static void rna_def_animdata(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update"); + + /* Animation Data API */ + RNA_api_animdata(srna); } /* --- */ diff --git a/source/blender/makesrna/intern/rna_animation_api.c b/source/blender/makesrna/intern/rna_animation_api.c index f201b8e6e99..e063e5de22c 100644 --- a/source/blender/makesrna/intern/rna_animation_api.c +++ b/source/blender/makesrna/intern/rna_animation_api.c @@ -37,6 +37,7 @@ # include "BKE_context.h" # include "BKE_report.h" +# include "BKE_nla.h" # include "ED_keyframing.h" @@ -59,6 +60,11 @@ static void rna_KeyingSet_context_refresh(KeyingSet *ks, bContext *C, ReportList } } +static float rna_AnimData_nla_tweak_strip_time_to_scene(AnimData *adt, float frame, bool invert) +{ + return BKE_nla_tweakedit_remap(adt, frame, invert ? NLATIME_CONVERT_UNMAP : NLATIME_CONVERT_MAP); +} + #else void RNA_api_keyingset(StructRNA *srna) @@ -75,4 +81,25 @@ void RNA_api_keyingset(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); } +void RNA_api_animdata(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + /* Convert between action time and scene time when tweaking a NLA strip. */ + func = RNA_def_function( + srna, "nla_tweak_strip_time_to_scene", "rna_AnimData_nla_tweak_strip_time_to_scene"); + RNA_def_function_ui_description(func, + "Convert a time value from the local time of the tweaked strip " + "to scene time, exactly as done by built-in key editing tools. " + "Returns the input time unchanged if not tweaking."); + parm = RNA_def_float( + func, "frame", 0.0, MINAFRAME, MAXFRAME, "", "Input time", MINAFRAME, MAXFRAME); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "invert", false, "Invert", "Convert scene time to action time"); + parm = RNA_def_float( + func, "result", 0.0, MINAFRAME, MAXFRAME, "", "Converted time", MINAFRAME, MAXFRAME); + RNA_def_function_return(func, parm); +} + #endif diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 5461aaa0f1a..604be10d5ab 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -67,7 +67,9 @@ static void rna_Armature_dependency_update(Main *bmain, Scene *UNUSED(scene), Po WM_main_add_notifier(NC_GEOM | ND_DATA, id); } -static void rna_Armature_act_bone_set(PointerRNA *ptr, PointerRNA value) +static void rna_Armature_act_bone_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bArmature *arm = (bArmature *)ptr->data; @@ -89,7 +91,9 @@ static void rna_Armature_act_bone_set(PointerRNA *ptr, PointerRNA value) } } -static void rna_Armature_act_edit_bone_set(PointerRNA *ptr, PointerRNA value) +static void rna_Armature_act_edit_bone_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bArmature *arm = (bArmature *)ptr->data; @@ -395,7 +399,9 @@ static PointerRNA rna_EditBone_parent_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_EditBone, data->parent); } -static void rna_EditBone_parent_set(PointerRNA *ptr, PointerRNA value) +static void rna_EditBone_parent_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *pbone, *parbone = (EditBone *)value.data; @@ -463,7 +469,9 @@ static PointerRNA rna_EditBone_bbone_prev_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_EditBone, data->bbone_prev); } -static void rna_EditBone_bbone_prev_set(PointerRNA *ptr, PointerRNA value) +static void rna_EditBone_bbone_prev_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *hbone = (EditBone *)value.data; @@ -474,7 +482,9 @@ static void rna_EditBone_bbone_prev_set(PointerRNA *ptr, PointerRNA value) } } -static void rna_Bone_bbone_prev_set(PointerRNA *ptr, PointerRNA value) +static void rna_Bone_bbone_prev_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Bone *bone = (Bone *)ptr->data; Bone *hbone = (Bone *)value.data; @@ -491,7 +501,9 @@ static PointerRNA rna_EditBone_bbone_next_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_EditBone, data->bbone_next); } -static void rna_EditBone_bbone_next_set(PointerRNA *ptr, PointerRNA value) +static void rna_EditBone_bbone_next_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { EditBone *ebone = (EditBone *)(ptr->data); EditBone *hbone = (EditBone *)value.data; @@ -502,7 +514,9 @@ static void rna_EditBone_bbone_next_set(PointerRNA *ptr, PointerRNA value) } } -static void rna_Bone_bbone_next_set(PointerRNA *ptr, PointerRNA value) +static void rna_Bone_bbone_next_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Bone *bone = (Bone *)ptr->data; Bone *hbone = (Bone *)value.data; @@ -575,6 +589,20 @@ static void rna_Armature_bones_next(CollectionPropertyIterator *iter) iter->valid = (internal->link != NULL); } +/* not essential, but much faster then the default lookup function */ +static int rna_Armature_bones_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) +{ + bArmature *arm = (bArmature *)ptr->data; + Bone *bone = BKE_armature_find_bone_name(arm, key); + if (bone) { + RNA_pointer_create(ptr->id.data, &RNA_Bone, bone, r_ptr); + return true; + } + else { + return false; + } +} + static bool rna_Armature_is_editmode_get(PointerRNA *ptr) { bArmature *arm = (bArmature *)ptr->id.data; @@ -621,9 +649,10 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone) if (is_posebone == false) { prop = RNA_def_property(srna, "use_endroll_as_inroll", PROP_BOOLEAN, PROP_NONE); RNA_def_property_ui_text( - prop, "Inherit End Roll", "Use Roll Out of parent bone as Roll In of its children"); + prop, "Inherit End Roll", "Add Roll Out of the Start Handle bone to the Roll In value"); RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_ADD_PARENT_END_ROLL); - RNA_def_property_update(prop, 0, "rna_Armature_update_data"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Armature_dependency_update"); } /* Curve X/Y Offsets */ @@ -1285,8 +1314,15 @@ static void rna_def_armature(BlenderRNA *brna) /* Collections */ prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "bonebase", NULL); - RNA_def_property_collection_funcs( - prop, NULL, "rna_Armature_bones_next", NULL, NULL, NULL, NULL, NULL, NULL); + RNA_def_property_collection_funcs(prop, + NULL, + "rna_Armature_bones_next", + NULL, + NULL, + NULL, + NULL, + "rna_Armature_bones_lookup_string", + NULL); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_ui_text(prop, "Bones", ""); rna_def_armature_bones(brna, prop); @@ -1359,13 +1395,6 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); - prop = RNA_def_property(srna, "use_auto_ik", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_AUTO_IK); - RNA_def_property_ui_text( - prop, "Auto IK", "Add temporary IK constraints while grabbing bones in Pose Mode"); - RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); - RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); - prop = RNA_def_property(srna, "show_bone_custom_shapes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ARM_NO_CUSTOM); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 1f356624f3f..6bab07d2940 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -131,6 +131,38 @@ static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED( WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } +char *rna_CameraDOFSettings_path(PointerRNA *ptr) +{ + /* if there is ID-data, resolve the path using the index instead of by name, + * since the name used is the name of the texture assigned, but the texture + * may be used multiple times in the same stack + */ + if (ptr->id.data) { + if (GS(((ID *)ptr->id.data)->name) == ID_CA) { + return BLI_strdup("dof"); + } + } + + return BLI_strdup(""); +} + +static void rna_CameraDOFSettings_aperture_blades_set(PointerRNA *ptr, const int value) +{ + CameraDOFSettings *dofsettings = (CameraDOFSettings *)ptr->data; + + if (value == 1 || value == 2) { + if (dofsettings->aperture_blades == 0) { + dofsettings->aperture_blades = 3; + } + else { + dofsettings->aperture_blades = 0; + } + } + else { + dofsettings->aperture_blades = value; + } +} + #else static void rna_def_camera_background_image(BlenderRNA *brna) @@ -376,6 +408,68 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); } +static void rna_def_camera_dof_settings_data(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CameraDOFSettings", NULL); + RNA_def_struct_sdna(srna, "CameraDOFSettings"); + RNA_def_struct_path_func(srna, "rna_CameraDOFSettings_path"); + RNA_def_struct_ui_text(srna, "Depth of Field", "Depth of Field settings"); + + prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_DOF_ENABLED); + RNA_def_property_ui_text(prop, "Depth of Field", "Use Depth of Field"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + prop = RNA_def_property(srna, "focus_object", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_pointer_sdna(prop, NULL, "focus_object"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Focus Object", "Use this object to define the depth of field focal point"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update"); + + prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_default(prop, 10.0f); + // RNA_def_property_pointer_sdna(prop, NULL, "focus_distance"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 5000.0f, 1, 2); + RNA_def_property_ui_text( + prop, "Focus Distance", "Distance to the focus point for depth of field"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + prop = RNA_def_property(srna, "aperture_fstop", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text( + prop, + "F-Stop", + "F-Stop ratio (lower numbers give more defocus, higher numbers give a sharper image)"); + RNA_def_property_float_default(prop, 5.6f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + prop = RNA_def_property(srna, "aperture_blades", PROP_INT, PROP_NONE); + RNA_def_property_ui_text( + prop, "Blades", "Number of blades in aperture for polygonal bokeh (at least 3)"); + RNA_def_property_range(prop, 0, 16); + RNA_def_property_int_funcs(prop, NULL, "rna_CameraDOFSettings_aperture_blades_set", NULL); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + prop = RNA_def_property(srna, "aperture_rotation", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_ui_text(prop, "Rotation", "Rotation of blades in aperture"); + RNA_def_property_range(prop, -M_PI, M_PI); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + + prop = RNA_def_property(srna, "aperture_ratio", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_range(prop, 0.01f, FLT_MAX); + RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); +} + void RNA_def_camera(BlenderRNA *brna) { StructRNA *srna; @@ -525,12 +619,6 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Shift Y", "Camera vertical shift"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update"); - prop = RNA_def_property(srna, "dof_distance", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 5000.0f, 1, 2); - RNA_def_property_ui_text(prop, "DOF Distance", "Distance to the focus point for depth of field"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); - /* Stereo Settings */ prop = RNA_def_property(srna, "stereo", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -645,17 +733,9 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL); /* pointers */ - prop = RNA_def_property(srna, "dof_object", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_pointer_sdna(prop, NULL, "dof_ob"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, "DOF Object", "Use this object to define the depth of field focal point"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update"); - - prop = RNA_def_property(srna, "gpu_dof", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "GPUDOFSettings"); - RNA_def_property_ui_text(prop, "GPU Depth Of Field", ""); + prop = RNA_def_property(srna, "dof", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "CameraDOFSettings"); + RNA_def_property_ui_text(prop, "Depth Of Field", ""); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "background_images", PROP_COLLECTION, PROP_NONE); @@ -674,6 +754,7 @@ void RNA_def_camera(BlenderRNA *brna) /* *** Animated *** */ rna_def_camera_stereo_data(brna); + rna_def_camera_dof_settings_data(brna); /* Camera API */ RNA_api_camera(srna); diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 160634307f9..f5cb29b5e69 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -306,7 +306,9 @@ static PointerRNA rna_ClothSettings_rest_shape_key_get(PointerRNA *ptr) return rna_object_shapekey_index_get(ob->data, sim->shapekey_rest); } -static void rna_ClothSettings_rest_shape_key_set(PointerRNA *ptr, PointerRNA value) +static void rna_ClothSettings_rest_shape_key_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->id.data; ClothSimSettings *sim = (ClothSimSettings *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c index 501895eefc8..ae944f59a35 100644 --- a/source/blender/makesrna/intern/rna_collection.c +++ b/source/blender/makesrna/intern/rna_collection.c @@ -405,15 +405,15 @@ void RNA_def_collections(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1); - RNA_def_property_ui_text(prop, "Disable Select", "Disable collection for viewport selection"); + RNA_def_property_ui_text(prop, "Disable Selection", "Disable selection in viewport"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEW); + RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEWPORT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); - RNA_def_property_ui_text(prop, "Disable Viewport", "Disable collection in viewport"); + RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); @@ -421,7 +421,7 @@ void RNA_def_collections(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1); - RNA_def_property_ui_text(prop, "Disable Render", "Disable collection in renders"); + RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update"); } diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 40ee069657c..da2bf710428 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -525,6 +525,22 @@ static char *rna_ColorManagedViewSettings_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("view_settings"); } +static bool rna_ColorManagedColorspaceSettings_is_data_get(struct PointerRNA *ptr) +{ + ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data; + const char *data_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA); + return STREQ(colorspace->name, data_name); +} + +static void rna_ColorManagedColorspaceSettings_is_data_set(struct PointerRNA *ptr, bool value) +{ + ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data; + if (value) { + const char *data_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DATA); + STRNCPY(colorspace->name, data_name); + } +} + static int rna_ColorManagedColorspaceSettings_colorspace_get(struct PointerRNA *ptr) { ColorManagedColorspaceSettings *colorspace = (ColorManagedColorspaceSettings *)ptr->data; @@ -1120,7 +1136,7 @@ static void rna_def_colormanage(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem display_device_items[] = { - {0, "DEFAULT", 0, "Default", ""}, + {0, "NONE", 0, "None", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1227,6 +1243,7 @@ static void rna_def_colormanage(BlenderRNA *brna) prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, color_space_items); RNA_def_property_enum_funcs(prop, "rna_ColorManagedColorspaceSettings_colorspace_get", @@ -1235,6 +1252,17 @@ static void rna_def_colormanage(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Input Color Space", "Color space of the image or movie on disk"); RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update"); + prop = RNA_def_property(srna, "is_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_boolean_funcs(prop, + "rna_ColorManagedColorspaceSettings_is_data_get", + "rna_ColorManagedColorspaceSettings_is_data_set"); + RNA_def_property_ui_text( + prop, + "Is Data", + "Treat image as non-color data without color management, like normal or displacement maps"); + RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update"); + // srna = RNA_def_struct(brna, "ColorManagedSequencerColorspaceSettings", NULL); RNA_def_struct_path_func(srna, "rna_ColorManagedSequencerColorspaceSettings_path"); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index c1c235d497b..ac319a545ac 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -351,7 +351,9 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) } } -static void rna_ConstraintTargetBone_target_set(PointerRNA *ptr, PointerRNA value) +static void rna_ConstraintTargetBone_target_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; Object *ob = value.data; @@ -665,7 +667,9 @@ static bool rna_Constraint_cameraObject_poll(PointerRNA *ptr, PointerRNA value) return 0; } -static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, PointerRNA value) +static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bConstraint *con = (bConstraint *)ptr->data; bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; @@ -682,7 +686,9 @@ static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, PointerRNA va } } -static void rna_Constraint_followTrack_depthObject_set(PointerRNA *ptr, PointerRNA value) +static void rna_Constraint_followTrack_depthObject_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bConstraint *con = (bConstraint *)ptr->data; bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; @@ -712,7 +718,9 @@ static bool rna_Constraint_followTrack_depthObject_poll(PointerRNA *ptr, Pointer return 0; } -static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA value) +static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bConstraint *con = (bConstraint *)ptr->data; bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data; @@ -1327,6 +1335,13 @@ static void rna_def_constraint_size_like(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Copy Z", "Copy the target's Z scale"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "power", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "power"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3); + RNA_def_property_ui_text(prop, "Power", "Raise the target's scale to the specified power"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_OFFSET); RNA_def_property_ui_text(prop, "Offset", "Combine original scale with copied scale"); @@ -1346,13 +1361,34 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem volume_items[] = { + static const EnumPropertyItem axis_items[] = { {SAMEVOL_X, "SAMEVOL_X", 0, "X", ""}, {SAMEVOL_Y, "SAMEVOL_Y", 0, "Y", ""}, {SAMEVOL_Z, "SAMEVOL_Z", 0, "Z", ""}, {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem mode_items[] = { + {SAMEVOL_STRICT, + "STRICT", + 0, + "Strict", + "Volume is strictly preserved, overriding the scaling of non-free axes"}, + {SAMEVOL_UNIFORM, + "UNIFORM", + 0, + "Uniform", + "Volume is preserved when the object is scaled uniformly. " + "Deviations from uniform scale on non-free axes are passed through"}, + {SAMEVOL_SINGLE_AXIS, + "SINGLE_AXIS", + 0, + "Single Axis", + "Volume is preserved when the object is scaled only on the free axis. " + "Non-free axis scaling is passed through"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "MaintainVolumeConstraint", "Constraint"); RNA_def_struct_ui_text(srna, "Maintain Volume Constraint", @@ -1360,11 +1396,18 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna) RNA_def_struct_sdna_from(srna, "bSameVolumeConstraint", "data"); prop = RNA_def_property(srna, "free_axis", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "flag"); - RNA_def_property_enum_items(prop, volume_items); + RNA_def_property_enum_sdna(prop, NULL, "free_axis"); + RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Free Axis", "The free scaling axis of the object"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_ui_text( + prop, "Mode", "The way the constraint treats original non-free axis scaling"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_range(prop, 0.001f, 100.0f); RNA_def_property_ui_text(prop, "Volume", "Volume of the bone at rest"); @@ -2576,6 +2619,13 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna) "on top of the shape and scaling of the curve itself"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* take original scaling of the bone into account in volume preservation */ + prop = RNA_def_property(srna, "use_original_scale", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_SPLINEIK_USE_ORIGINAL_SCALE); + RNA_def_property_ui_text( + prop, "Use Original Scale", "Apply volume preservation over the original scaling"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + /* volume presevation for "volumetric" scale mode */ prop = RNA_def_property(srna, "bulge", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 100.f); diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 75f8b97b99d..a2ac7cb40ba 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -135,12 +135,6 @@ static PointerRNA rna_Context_main_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_BlendData, CTX_data_main(C)); } -static PointerRNA rna_Context_depsgraph_get(PointerRNA *ptr) -{ - bContext *C = (bContext *)ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, CTX_data_depsgraph(C)); -} - static PointerRNA rna_Context_scene_get(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; @@ -204,6 +198,11 @@ static int rna_Context_mode_get(PointerRNA *ptr) return CTX_data_mode_enum(C); } +static struct Depsgraph *rna_Context_evaluated_depsgraph_get(bContext *C) +{ + return CTX_data_evaluated_depsgraph(C); +} + #else void RNA_def_context(BlenderRNA *brna) @@ -211,6 +210,9 @@ void RNA_def_context(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "Context", NULL); RNA_def_struct_ui_text(srna, "Context", "Current windowmanager and data context"); RNA_def_struct_sdna(srna, "bContext"); @@ -267,11 +269,6 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_struct_type(prop, "BlendData"); RNA_def_property_pointer_funcs(prop, "rna_Context_main_get", NULL, NULL, NULL); - prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_struct_type(prop, "Depsgraph"); - RNA_def_property_pointer_funcs(prop, "rna_Context_depsgraph_get", NULL, NULL, NULL); - prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Scene"); @@ -310,6 +307,16 @@ void RNA_def_context(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_context_mode_items); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_funcs(prop, "rna_Context_mode_get", NULL, NULL); + + func = RNA_def_function(srna, "evaluated_depsgraph_get", "rna_Context_evaluated_depsgraph_get"); + RNA_def_function_ui_description( + func, + "Get the dependency graph for the current scene and view layer, to access to data-blocks " + "with animation and modifiers applied. If any data-blocks have been edited, the dependency " + "graph will be updated. This invalidates all references to evaluated data-blocks from the " + "dependency graph."); + parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "Evaluated dependency graph"); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 9c7ad60f378..89200240b08 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -438,7 +438,9 @@ static PointerRNA rna_Curve_bevelObject_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, NULL, NULL); } -static void rna_Curve_bevelObject_set(PointerRNA *ptr, PointerRNA value) +static void rna_Curve_bevelObject_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Curve *cu = (Curve *)ptr->id.data; Object *ob = (Object *)value.data; @@ -481,7 +483,9 @@ static PointerRNA rna_Curve_taperObject_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, NULL, NULL); } -static void rna_Curve_taperObject_set(PointerRNA *ptr, PointerRNA value) +static void rna_Curve_taperObject_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Curve *cu = (Curve *)ptr->id.data; Object *ob = (Object *)value.data; @@ -730,7 +734,9 @@ static PointerRNA rna_Curve_active_spline_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, NULL, NULL); } -static void rna_Curve_active_spline_set(PointerRNA *ptr, PointerRNA value) +static void rna_Curve_active_spline_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Curve *cu = (Curve *)ptr->data; Nurb *nu = value.data; diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 20fbbed572c..b1818cae62a 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -709,6 +709,14 @@ void RNA_define_animate_sdna(bool animate) } #endif +#ifndef RNA_RUNTIME +void RNA_define_fallback_property_update(int noteflag, const char *updatefunc) +{ + DefRNA.fallback.property_update.noteflag = noteflag; + DefRNA.fallback.property_update.updatefunc = updatefunc; +} +#endif + void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext) { #ifdef RNA_RUNTIME @@ -890,9 +898,9 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN srna->description = ""; /* may be overwritten later RNA_def_struct_translation_context */ srna->translation_context = BLT_I18NCONTEXT_DEFAULT_BPYRNA; - srna->flag |= STRUCT_UNDO; if (!srnafrom) { srna->icon = ICON_DOT; + srna->flag |= STRUCT_UNDO; } if (DefRNA.preprocess) { @@ -1413,6 +1421,12 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, } /* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */ +#ifndef RNA_RUNTIME + /* Both are typically cleared. */ + RNA_def_property_update( + prop, DefRNA.fallback.property_update.noteflag, DefRNA.fallback.property_update.updatefunc); +#endif + rna_addtail(&cont->properties, prop); return prop; diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 447318da744..df1727ff87c 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -36,11 +36,16 @@ #ifdef RNA_RUNTIME +# ifdef WITH_PYTHON +# include "BPY_extern.h" +# endif + # include "BLI_iterator.h" # include "BLI_math.h" # include "BKE_anim.h" # include "BKE_object.h" +# include "BKE_scene.h" # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_debug.h" @@ -256,6 +261,20 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result) outer); } +static void rna_Depsgraph_update(Depsgraph *depsgraph, Main *bmain) +{ +# ifdef WITH_PYTHON + /* Allow drivers to be evaluated */ + BPy_BEGIN_ALLOW_THREADS; +# endif + + BKE_scene_graph_update_tagged(depsgraph, bmain); + +# ifdef WITH_PYTHON + BPy_END_ALLOW_THREADS; +# endif +} + /* Iteration over objects, simple version */ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -603,21 +622,13 @@ static void rna_def_depsgraph(BlenderRNA *brna) func = RNA_def_function( srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz"); - parm = RNA_def_string_file_path(func, - "filename", - NULL, - FILE_MAX, - "File Name", - "File in which to store graphviz debug output"); + parm = RNA_def_string_file_path( + func, "filename", NULL, FILE_MAX, "File Name", "Output path for the graphviz debug file"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "debug_stats_gnuplot", "rna_Depsgraph_debug_stats_gnuplot"); - parm = RNA_def_string_file_path(func, - "filename", - NULL, - FILE_MAX, - "File Name", - "File in which to store graphviz debug output"); + parm = RNA_def_string_file_path( + func, "filename", NULL, FILE_MAX, "File Name", "Output path for the gnuplot debug file"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string_file_path(func, "output_filename", @@ -636,6 +647,15 @@ static void rna_def_depsgraph(BlenderRNA *brna) RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); + /* Updates. */ + + func = RNA_def_function(srna, "update", "rna_Depsgraph_update"); + RNA_def_function_ui_description( + func, + "Re-evaluate any modified data-blocks, for example for animation or modifiers. " + "This invalidates all references to evaluated data-blocks from this dependency graph."); + RNA_def_function_flag(func, FUNC_USE_MAIN); + /* Queries for original datablockls (the ones depsgraph is built for). */ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index c8df01a7dc7..741b73f4250 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -239,7 +239,9 @@ static void rna_DriverTarget_update_name(Main *bmain, Scene *scene, PointerRNA * /* ----------- */ /* note: this function exists only to avoid id refcounting */ -static void rna_DriverTarget_id_set(PointerRNA *ptr, PointerRNA value) +static void rna_DriverTarget_id_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { DriverTarget *dtar = (DriverTarget *)ptr->data; dtar->id = value.data; @@ -446,7 +448,9 @@ static void rna_FCurve_RnaPath_set(PointerRNA *ptr, const char *value) fcu->rna_path = NULL; } -static void rna_FCurve_group_set(PointerRNA *ptr, PointerRNA value) +static void rna_FCurve_group_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { ID *pid = (ID *)ptr->id.data; ID *vid = (ID *)value.id.data; @@ -520,18 +524,41 @@ static void rna_FCurve_range(FCurve *fcu, float range[2]) calc_fcurve_range(fcu, range, range + 1, false, false); } +static bool rna_FCurve_is_empty_get(PointerRNA *ptr) +{ + FCurve *fcu = (FCurve *)ptr->data; + return BKE_fcurve_is_empty(fcu); +} + +static void rna_tag_animation_update(Main *bmain, ID *id, bool flush) +{ + /* Actually recalculate object properties, or just update COW. */ + int tags = flush ? ID_RECALC_ANIMATION : ID_RECALC_ANIMATION_NO_FLUSH; + + AnimData *adt = BKE_animdata_from_id(id); + + if (adt && adt->action) { + /* action is separate datablock, needs separate tag */ + DEG_id_tag_update_ex(bmain, &adt->action->id, tags); + } + + DEG_id_tag_update_ex(bmain, id, tags); +} + /* allow scripts to update curve after editing manually */ -static void rna_FCurve_update_data_ex(FCurve *fcu) +static void rna_FCurve_update_data_ex(ID *id, FCurve *fcu, Main *bmain) { sort_time_fcurve(fcu); calchandles_fcurve(fcu); + + rna_tag_animation_update(bmain, id, true); } /* RNA update callback for F-Curves after curve shape changes */ -static void rna_FCurve_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_FCurve_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { BLI_assert(ptr->type == &RNA_FCurve); - rna_FCurve_update_data_ex((FCurve *)ptr->data); + rna_FCurve_update_data_ex((ID *)ptr->id.data, (FCurve *)ptr->data, bmain); } static void rna_FCurve_update_data_relations(Main *bmain, @@ -544,13 +571,9 @@ static void rna_FCurve_update_data_relations(Main *bmain, /* RNA update callback for F-Curves to indicate that there are copy-on-write tagging/flushing * needed (e.g. for properties that affect how animation gets evaluated). */ -static void rna_FCurve_update_eval(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_FCurve_update_eval(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { - IdAdtTemplate *iat = (IdAdtTemplate *)ptr->id.data; - if (iat && iat->adt && iat->adt->action) { - /* action is separate datablock, needs separate tag */ - DEG_id_tag_update(&iat->adt->action->id, ID_RECALC_ANIMATION); - } + rna_tag_animation_update(bmain, (ID *)ptr->id.data, true); } static PointerRNA rna_FCurve_active_modifier_get(PointerRNA *ptr) @@ -560,7 +583,9 @@ static PointerRNA rna_FCurve_active_modifier_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_FModifier, fcm); } -static void rna_FCurve_active_modifier_set(PointerRNA *ptr, PointerRNA value) +static void rna_FCurve_active_modifier_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { FCurve *fcu = (FCurve *)ptr->data; set_active_fmodifier(&fcu->modifiers, (FModifier *)value.data); @@ -659,28 +684,16 @@ static void rna_FModifier_blending_range( *max = fcm->efra - fcm->sfra; } -static void rna_FModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_FModifier_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; FModifier *fcm = (FModifier *)ptr->data; - AnimData *adt = BKE_animdata_from_id(id); - - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - - /* tag datablock for time update so that animation is recalculated, - * as FModifiers affect how animation plays... - */ - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - if (adt != NULL) { - if (adt->action != NULL) { - /* action is separate datablock, needs separate tag */ - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); - } - } if (fcm->curve && fcm->type == FMODIFIER_TYPE_CYCLES) { calchandles_fcurve(fcm->curve); } + + rna_tag_animation_update(bmain, id, true); } static void rna_FModifier_verify_data_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -897,14 +910,21 @@ static void rna_FModifierStepped_frame_end_set(PointerRNA *ptr, float value) } static BezTriple *rna_FKeyframe_points_insert( - FCurve *fcu, float frame, float value, int keyframe_type, int flag) + ID *id, FCurve *fcu, Main *bmain, float frame, float value, int keyframe_type, int flag) { int index = insert_vert_fcurve( fcu, frame, value, (char)keyframe_type, flag | INSERTKEY_NO_USERPREF); - return ((fcu->bezt) && (index >= 0)) ? (fcu->bezt + index) : NULL; + + if ((fcu->bezt) && (index >= 0)) { + rna_tag_animation_update(bmain, id, true); + + return fcu->bezt + index; + } + + return NULL; } -static void rna_FKeyframe_points_add(FCurve *fcu, int tot) +static void rna_FKeyframe_points_add(ID *id, FCurve *fcu, Main *bmain, int tot) { if (tot > 0) { BezTriple *bezt; @@ -921,13 +941,13 @@ static void rna_FKeyframe_points_add(FCurve *fcu, int tot) bezt->h1 = bezt->h2 = HD_AUTO_ANIM; bezt++; } + + rna_tag_animation_update(bmain, id, true); } } -static void rna_FKeyframe_points_remove(FCurve *fcu, - ReportList *reports, - PointerRNA *bezt_ptr, - bool do_fast) +static void rna_FKeyframe_points_remove( + ID *id, FCurve *fcu, Main *bmain, ReportList *reports, PointerRNA *bezt_ptr, bool do_fast) { BezTriple *bezt = bezt_ptr->data; int index = (int)(bezt - fcu->bezt); @@ -938,16 +958,19 @@ static void rna_FKeyframe_points_remove(FCurve *fcu, delete_fcurve_key(fcu, index, !do_fast); RNA_POINTER_INVALIDATE(bezt_ptr); + + rna_tag_animation_update(bmain, id, true); } -static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FModifier *fmod, - ReportList *reports, - float frame) +static FCM_EnvelopeData *rna_FModifierEnvelope_points_add( + ID *id, FModifier *fmod, Main *bmain, ReportList *reports, float frame) { FCM_EnvelopeData fed; FMod_Envelope *env = (FMod_Envelope *)fmod->data; int i; + rna_tag_animation_update(bmain, id, true); + /* init template data */ fed.min = -1.0f; fed.max = 1.0f; @@ -984,9 +1007,8 @@ static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FModifier *fmod, return (env->data + i); } -static void rna_FModifierEnvelope_points_remove(FModifier *fmod, - ReportList *reports, - PointerRNA *point) +static void rna_FModifierEnvelope_points_remove( + ID *id, FModifier *fmod, Main *bmain, ReportList *reports, PointerRNA *point) { FCM_EnvelopeData *cp = point->data; FMod_Envelope *env = (FMod_Envelope *)fmod->data; @@ -999,6 +1021,8 @@ static void rna_FModifierEnvelope_points_remove(FModifier *fmod, return; } + rna_tag_animation_update(bmain, id, true); + if (env->totvert > 1) { /* move data after the removed point */ @@ -1022,19 +1046,9 @@ static void rna_FModifierEnvelope_points_remove(FModifier *fmod, RNA_POINTER_INVALIDATE(point); } -static void rna_Keyframe_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Keyframe_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { - ID *id = ptr->id.data; - AnimData *adt = BKE_animdata_from_id(id); - - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - - if (adt != NULL) { - if (adt->action != NULL) { - /* action is separate datablock, needs separate tag */ - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); - } - } + rna_tag_animation_update(bmain, (ID *)ptr->id.data, true); } #else @@ -1205,7 +1219,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property func = RNA_def_function(srna, "add", "rna_FModifierEnvelope_points_add"); RNA_def_function_ui_description(func, "Add a control point to a FModifierEnvelope"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_float(func, "frame", 0.0f, @@ -1222,7 +1236,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property func = RNA_def_function(srna, "remove", "rna_FModifierEnvelope_points_remove"); RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer( func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); @@ -1534,6 +1548,7 @@ static void rna_def_fmodifier(BlenderRNA *brna) prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_items(prop, rna_enum_fmodifier_type_items); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ACTION); RNA_def_property_ui_text(prop, "Type", "F-Curve Modifier Type"); /* settings */ @@ -1645,6 +1660,7 @@ static void rna_def_drivertarget(BlenderRNA *brna) {DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""}, {DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""}, {DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""}, + {DTAR_TRANSCHAN_SCALE_AVG, "SCALE_AVG", 0, "Average Scale", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2097,6 +2113,7 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "insert", "rna_FKeyframe_points_insert"); RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); parm = RNA_def_float(func, "frame", 0.0f, @@ -2129,13 +2146,14 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "add", "rna_FKeyframe_points_add"); RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); parm = RNA_def_int( func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "remove", "rna_FKeyframe_points_remove"); RNA_def_function_ui_description(func, "Remove keyframe from an F-Curve"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Keyframe to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); @@ -2294,6 +2312,14 @@ static void rna_def_fcurve(BlenderRNA *brna) "when evaluating"); RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); + prop = RNA_def_property(srna, "is_empty", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_FCurve_is_empty_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Empty", + "True if the curve contributes no animation due to lack of " + "keyframes or useful modifiers, and should be deleted"); + /* Collections */ prop = RNA_def_property(srna, "sampled_points", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fpt", "totvert"); @@ -2339,6 +2365,7 @@ static void rna_def_fcurve(BlenderRNA *brna) /* -- update / recalculate -- */ func = RNA_def_function(srna, "update", "rna_FCurve_update_data_ex"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description( func, "Ensure keyframes are sorted in chronological order and handles are set correctly"); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 737dbe36d17..cf6d85adc62 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -76,6 +76,36 @@ static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_onion_keyframe_type_items[] = { + {-1, "ALL", ICON_ACTION, "All Types", "Include all Keyframe types"}, + {BEZT_KEYTYPE_KEYFRAME, + "KEYFRAME", + ICON_KEYTYPE_KEYFRAME_VEC, + "Keyframe", + "Normal keyframe - e.g. for key poses"}, + {BEZT_KEYTYPE_BREAKDOWN, + "BREAKDOWN", + ICON_KEYTYPE_BREAKDOWN_VEC, + "Breakdown", + "A breakdown pose - e.g. for transitions between key poses"}, + {BEZT_KEYTYPE_MOVEHOLD, + "MOVING_HOLD", + ICON_KEYTYPE_MOVING_HOLD_VEC, + "Moving Hold", + "A keyframe that is part of a moving hold"}, + {BEZT_KEYTYPE_EXTREME, + "EXTREME", + ICON_KEYTYPE_EXTREME_VEC, + "Extreme", + "An 'extreme' pose, or some other purpose as needed"}, + {BEZT_KEYTYPE_JITTER, + "JITTER", + ICON_KEYTYPE_JITTER_VEC, + "Jitter", + "A filler or baked keyframe for keying on ones, or some other purpose as needed"}, + {0, NULL, 0, NULL, NULL}, +}; + static const EnumPropertyItem rna_enum_gplayer_move_type_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, @@ -251,7 +281,9 @@ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char * } /* set parent object and inverse matrix */ -static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value) +static void rna_GPencilLayer_parent_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bGPDlayer *gpl = (bGPDlayer *)ptr->data; Object *par = (Object *)value.data; @@ -345,7 +377,9 @@ static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, NULL, NULL); } -static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value) +static void rna_GPencil_active_layer_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bGPdata *gpd = ptr->id.data; @@ -810,7 +844,7 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "pressure"); - RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); @@ -861,11 +895,11 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr "pressure", 1.0f, 0.0f, - 1.0f, + FLT_MAX, "Pressure", "Pressure for newly created points", 0.0f, - 1.0f); + FLT_MAX); RNA_def_float(func, "strength", 1.0f, @@ -1737,6 +1771,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "gstep"); RNA_def_property_range(prop, 0, 120); RNA_def_property_int_default(prop, 1); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Frames Before", "Maximum number of frames to show before current frame " @@ -1747,6 +1782,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "gstep_next"); RNA_def_property_range(prop, 0, 120); RNA_def_property_int_default(prop, 1); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Frames After", "Maximum number of frames to show after current frame " @@ -1756,6 +1792,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna( prop, NULL, "onion_flag", GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); @@ -1779,6 +1816,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_ALWAYS); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Always Show Ghosts", "Ghosts are shown in renders and animation playback. Useful for " @@ -1788,17 +1826,27 @@ static void rna_def_gpencil_data(BlenderRNA *brna) prop = RNA_def_property(srna, "onion_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "onion_mode"); RNA_def_property_enum_items(prop, rna_enum_gpencil_onion_modes_items); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Mode", "Mode to display frames"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "onion_keyframe_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "onion_keytype"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_enum_items(prop, rna_enum_onion_keyframe_type_items); + RNA_def_property_ui_text(prop, "Filter By Type", "Type of keyframe (for filtering)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_FADE); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text( prop, "Fade", "Display onion keyframes with a fade in color transparency"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "use_onion_loop", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_LOOP); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Loop", "Display first onion keyframes using next frame color to show " @@ -1809,6 +1857,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "onion_factor"); RNA_def_property_float_default(prop, 0.5f); RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Onion Opacity", "Change fade opacity of displayed onion frames"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index d1ae46a74f7..cca291a0aae 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -296,7 +296,8 @@ static void greasepencil_modifier_object_set(Object *self, } # define RNA_GP_MOD_OBJECT_SET(_type, _prop, _obtype) \ - static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, PointerRNA value) \ + static void rna_##_type##GpencilModifier_##_prop##_set( \ + PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) \ { \ _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \ greasepencil_modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ @@ -308,7 +309,9 @@ RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY); # undef RNA_GP_MOD_OBJECT_SET -static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, PointerRNA value) +static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { HookGpencilModifierData *hmd = ptr->data; Object *ob = (Object *)value.data; diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 34373e469c1..7f2eccf421e 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -332,7 +332,10 @@ static int rna_Image_frame_duration_get(PointerRNA *ptr) int duration = 1; if (BKE_image_has_anim(ima)) { - duration = IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN); + struct anim *anim = ((ImageAnim *)ima->anims.first)->anim; + if (anim) { + duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); + } } else { /* acquire ensures ima->anim is set, if possible! */ @@ -406,7 +409,8 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values) ((unsigned char *)ibuf->rect)[i] = unit_float_to_uchar_clamp(values[i]); } - ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID; + BKE_image_mark_dirty(ima, ibuf); if (!G.background) { GPU_free_image(ima); } @@ -478,7 +482,9 @@ static PointerRNA rna_render_slots_active_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_RenderSlot, render_slot); } -static void rna_render_slots_active_set(PointerRNA *ptr, PointerRNA value) +static void rna_render_slots_active_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Image *image = (Image *)ptr->id.data; if (value.id.data == image) { @@ -677,12 +683,26 @@ static void rna_def_image(BlenderRNA *brna) "STRAIGHT", 0, "Straight", - "Transparent RGB and alpha pixels are unmodified"}, + "Store RGB and alpha channels separately with alpha acting as a mask, also known as " + "unassociated alpha. Commonly used by image editing applications and file formats like " + "PNG"}, {IMA_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", - "Transparent RGB pixels are multiplied by the alpha channel"}, + "Store RGB channels with alpha multipled in, also known as associated alpha. The natural " + "format for renders and used by file formats like OpenEXR"}, + {IMA_ALPHA_CHANNEL_PACKED, + "CHANNEL_PACKED", + 0, + "Channel Packed", + "Different images are packed in the RGB and alpha channels, and they should not " + "affect each other. Channel packing is commonly used by game engines to save memory"}, + {IMA_ALPHA_IGNORE, + "NONE", + 0, + "None", + "Ignore alpha channel from the file and make image fully opaque"}, {0, NULL, 0, NULL, NULL}, }; @@ -741,15 +761,6 @@ static void rna_def_image(BlenderRNA *brna) "Apply render part of display transformation when displaying this image on the screen"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL); - prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA); - RNA_def_property_ui_text( - prop, - "Use Alpha", - "Use the alpha channel information from the image or make image fully opaque"); - RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update"); - prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index ca75f862b11..553dbeeb97b 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -211,69 +211,30 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he } } -static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int filter, int mag) +static int rna_Image_gl_load(Image *image, ReportList *reports, int frame) { - GPUTexture *tex = image->gputexture[TEXTARGET_TEXTURE_2D]; - int error = GL_NO_ERROR; - - if (tex) - return error; - ImageUser iuser = {NULL}; iuser.framenr = frame; iuser.ok = true; - void *lock; - ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); - - /* clean glError buffer */ - while (glGetError() != GL_NO_ERROR) { - } + GPUTexture *tex = GPU_texture_from_blender(image, &iuser, GL_TEXTURE_2D); - if (ibuf == NULL || ibuf->rect == NULL) { - BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2); - BKE_image_release_ibuf(image, ibuf, lock); + if (tex == NULL) { + BKE_reportf(reports, RPT_ERROR, "Failed to load image texture '%s'", image->id.name + 2); return (int)GL_INVALID_OPERATION; } - unsigned int bindcode = 0; - GPU_create_gl_tex(&bindcode, - ibuf->rect, - ibuf->rect_float, - ibuf->x, - ibuf->y, - GL_TEXTURE_2D, - (filter != GL_NEAREST && filter != GL_LINEAR), - false, - image); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag); - - /* TODO(merwin): validate input (dimensions, filter, mag) before calling OpenGL - * instead of trusting input & testing for error after */ - error = glGetError(); - - if (error) { - glDeleteTextures(1, (GLuint *)&bindcode); - } - else { - image->gputexture[TEXTARGET_TEXTURE_2D] = GPU_texture_from_bindcode(GL_TEXTURE_2D, bindcode); - } - - BKE_image_release_ibuf(image, ibuf, lock); - - return error; + return GL_NO_ERROR; } -static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int filter, int mag) +static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame) { int error = GL_NO_ERROR; BKE_image_tag_time(image); if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL) - error = rna_Image_gl_load(image, reports, frame, filter, mag); + error = rna_Image_gl_load(image, reports, frame); return error; } @@ -367,52 +328,20 @@ void RNA_api_image(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_int( func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX); - RNA_def_int(func, - "filter", - GL_LINEAR_MIPMAP_NEAREST, - -INT_MAX, - INT_MAX, - "Filter", - "The texture minifying function to use if the image wasn't loaded", - -INT_MAX, - INT_MAX); - RNA_def_int(func, - "mag", - GL_LINEAR, - -INT_MAX, - INT_MAX, - "Magnification", - "The texture magnification function to use if the image wasn't loaded", - -INT_MAX, - INT_MAX); /* return value */ parm = RNA_def_int( func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "gl_load", "rna_Image_gl_load"); - RNA_def_function_ui_description(func, "Load the image into OpenGL graphics memory"); + RNA_def_function_ui_description( + func, + "Load the image into an OpenGL texture. On success, image.bindcode will contain the " + "OpenGL texture bindcode. Colors read from the texture will be in scene linear color space " + "and have premultiplied alpha."); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_int( func, "frame", 0, 0, INT_MAX, "Frame", "Frame of image sequence or movie", 0, INT_MAX); - RNA_def_int(func, - "filter", - GL_LINEAR_MIPMAP_NEAREST, - -INT_MAX, - INT_MAX, - "Filter", - "The texture minifying function", - -INT_MAX, - INT_MAX); - RNA_def_int(func, - "mag", - GL_LINEAR, - -INT_MAX, - INT_MAX, - "Magnification", - "The texture magnification function", - -INT_MAX, - INT_MAX); /* return value */ parm = RNA_def_int( func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 3653f28c880..2659cdf227e 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -116,6 +116,16 @@ typedef struct BlenderDefRNA { ListBase allocs; struct StructRNA *laststruct; int error, silent, preprocess, verify, animate; + /* Keep last. */ +#ifndef RNA_RUNTIME + struct { + /** #RNA_def_property_update */ + struct { + int noteflag; + const char *updatefunc; + } property_update; + } fallback; +#endif } BlenderDefRNA; extern BlenderDefRNA DefRNA; @@ -277,7 +287,9 @@ int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current); /* ViewLayer related functions defined in rna_scene.c but required in rna_layer.c */ void rna_def_freestyle_settings(struct BlenderRNA *brna); struct PointerRNA rna_FreestyleLineSet_linestyle_get(struct PointerRNA *ptr); -void rna_FreestyleLineSet_linestyle_set(struct PointerRNA *ptr, struct PointerRNA value); +void rna_FreestyleLineSet_linestyle_set(struct PointerRNA *ptr, + struct PointerRNA value, + struct ReportList *reports); struct FreestyleLineSet *rna_FreestyleSettings_lineset_add(struct ID *id, struct FreestyleSettings *config, struct Main *bmain, @@ -339,9 +351,14 @@ bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct Poi char *rna_TextureSlot_path(struct PointerRNA *ptr); char *rna_Node_ImageUser_path(struct PointerRNA *ptr); +/* Set U.is_dirty and redraw. */ +void rna_userdef_is_dirty_update_impl(void); +void rna_userdef_is_dirty_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr); + /* API functions */ void RNA_api_action(StructRNA *srna); +void RNA_api_animdata(struct StructRNA *srna); void RNA_api_armature_edit_bone(StructRNA *srna); void RNA_api_bone(StructRNA *srna); void RNA_api_camera(StructRNA *srna); @@ -547,13 +564,6 @@ PointerRNA rna_pointer_inherit_refine(struct PointerRNA *ptr, struct StructRNA * int rna_parameter_size(struct PropertyRNA *parm); -struct Mesh *rna_Main_meshes_new_from_object(struct Main *bmain, - struct ReportList *reports, - struct Depsgraph *depsgraph, - struct Object *ob, - bool apply_modifiers, - bool calc_undeformed); - /* XXX, these should not need to be defined here~! */ struct MTex *rna_mtex_texture_slots_add(struct ID *self, struct bContext *C, diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 92c895bd854..ccead626bb6 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -37,6 +37,7 @@ struct IDProperty; struct Main; struct PointerRNA; struct PropertyRNA; +struct ReportList; struct Scene; struct StructRNA; struct bContext; @@ -85,7 +86,9 @@ typedef const EnumPropertyItem *(*PropEnumItemFunc)(struct bContext *C, bool *r_free); typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr); typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr); -typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value); +typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, + const PointerRNA value, + struct ReportList *reports); typedef bool (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value); typedef bool (*PropPointerPollFuncPy)(struct PointerRNA *ptr, const PointerRNA value, diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 1985099e060..c5997f27dc2 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -316,7 +316,9 @@ static PointerRNA rna_ShapeKey_relative_key_get(PointerRNA *ptr) return rna_object_shapekey_index_get(ptr->id.data, kb->relative); } -static void rna_ShapeKey_relative_key_set(PointerRNA *ptr, PointerRNA value) +static void rna_ShapeKey_relative_key_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { KeyBlock *kb = (KeyBlock *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index a71adec4e5c..cae59fc1285 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -67,7 +67,9 @@ static PointerRNA rna_ViewLayer_active_layer_collection_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, lc); } -static void rna_ViewLayer_active_layer_collection_set(PointerRNA *ptr, PointerRNA value) +static void rna_ViewLayer_active_layer_collection_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { ViewLayer *view_layer = (ViewLayer *)ptr->data; LayerCollection *lc = (LayerCollection *)value.data; @@ -84,7 +86,9 @@ static PointerRNA rna_LayerObjects_active_object_get(PointerRNA *ptr) ptr, &RNA_Object, view_layer->basact ? view_layer->basact->object : NULL); } -static void rna_LayerObjects_active_object_set(PointerRNA *ptr, PointerRNA value) +static void rna_LayerObjects_active_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { ViewLayer *view_layer = (ViewLayer *)ptr->data; if (value.data) @@ -187,6 +191,15 @@ static void rna_ObjectBase_select_update(Main *UNUSED(bmain), ED_object_base_select(base, mode); } +static void rna_ObjectBase_hide_viewport_update(bContext *C, PointerRNA *UNUSED(ptr)) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); +} + static void rna_LayerCollection_name_get(struct PointerRNA *ptr, char *value) { ID *id = (ID *)((LayerCollection *)ptr->data)->collection; @@ -199,12 +212,29 @@ int rna_LayerCollection_name_length(PointerRNA *ptr) return strlen(id->name + 2); } +static void rna_LayerCollection_exclude_update_recursive(ListBase *lb, const bool exclude) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + if (exclude) { + lc->flag |= LAYER_COLLECTION_EXCLUDE; + } + else { + lc->flag &= ~LAYER_COLLECTION_EXCLUDE; + } + rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, exclude); + } +} + static void rna_LayerCollection_exclude_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->id.data; LayerCollection *lc = (LayerCollection *)ptr->data; ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc); + /* Set/Unset it recursively to match the behaviour of excluding via the menu or shortcuts. */ + rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, + (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0); + BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); @@ -266,21 +296,26 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "LayerCollection"); RNA_def_property_ui_text(prop, "Children", "Child layer collections"); + /* Restriction flags. */ prop = RNA_def_property(srna, "exclude", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_EXCLUDE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Exclude", "Exclude collection from view layer"); + RNA_def_property_ui_text(prop, "Exclude from View Layer", "Exclude from view layer"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_exclude_update"); prop = RNA_def_property(srna, "holdout", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HOLDOUT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_icon(prop, ICON_HOLDOUT_OFF, 1); RNA_def_property_ui_text(prop, "Holdout", "Mask out objects in collection from view layer"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_update"); prop = RNA_def_property(srna, "indirect_only", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_INDIRECT_ONLY); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_icon(prop, ICON_INDIRECT_ONLY_OFF, 1); RNA_def_property_ui_text( prop, "Indirect Only", @@ -289,14 +324,13 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_update"); prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_RESTRICT_VIEW); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HIDE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); - RNA_def_property_ui_text( - prop, "Disable Viewport", "Disable collection in viewport for this view layer"); + RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_update"); + /* Run-time flags. */ prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "runtime_flag", LAYER_COLLECTION_VISIBLE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -374,6 +408,14 @@ static void rna_def_object_base(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", BASE_SELECTED); RNA_def_property_ui_text(prop, "Select", "Object base selection state"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ObjectBase_select_update"); + + prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BASE_HIDDEN); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1); + RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport"); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ObjectBase_hide_viewport_update"); } void RNA_def_view_layer(BlenderRNA *brna) @@ -428,7 +470,7 @@ void RNA_def_view_layer(BlenderRNA *brna) /* layer options */ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", VIEW_LAYER_RENDER); - RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render layer"); + RNA_def_property_ui_text(prop, "Enabled", "Enable or disable rendering of this View Layer"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL); prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index da2b5752a0f..a271b883e38 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -205,7 +205,7 @@ static void rna_def_light_energy(StructRNA *srna, bool distant) * scene unit scale. */ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER); RNA_def_property_float_default(prop, 10.0f); - RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 1, 5); + RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5); RNA_def_property_ui_text(prop, "Power", "Amount of light emitted"); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); } @@ -545,12 +545,20 @@ static void rna_def_spot_light(BlenderRNA *brna) static void rna_def_sun_light(BlenderRNA *brna) { StructRNA *srna; + PropertyRNA *prop; srna = RNA_def_struct(brna, "SunLight", "Light"); RNA_def_struct_sdna(srna, "Light"); RNA_def_struct_ui_text(srna, "Sun Light", "Constant direction parallel ray Light"); RNA_def_struct_ui_icon(srna, ICON_LIGHT_SUN); + prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "sun_angle"); + RNA_def_property_float_default(prop, DEG2RADF(0.526f)); + RNA_def_property_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f)); + RNA_def_property_ui_text(prop, "Angle", "Angular diameter of the Sun as seen from the Earth"); + RNA_def_property_update(prop, 0, "rna_Light_update"); + rna_def_light_energy(srna, true); rna_def_light_shadow(srna, true); } diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c index 125d2ade567..8b6b248eac2 100644 --- a/source/blender/makesrna/intern/rna_lightprobe.c +++ b/source/blender/makesrna/intern/rna_lightprobe.c @@ -77,7 +77,7 @@ static void rna_def_lightprobe(BlenderRNA *brna) srna = RNA_def_struct(brna, "LightProbe", "ID"); RNA_def_struct_ui_text( srna, "LightProbe", "Light Probe data-block for lighting capture objects"); - RNA_def_struct_ui_icon(srna, ICON_OUTLINER_OB_LIGHTPROBE); + RNA_def_struct_ui_icon(srna, ICON_OUTLINER_DATA_LIGHTPROBE); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, lightprobe_type_items); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 3a6f283e1dc..1ef5fb17ed8 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -356,7 +356,9 @@ static PointerRNA rna_LineStyle_active_texture_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex); } -static void rna_LineStyle_active_texture_set(PointerRNA *ptr, PointerRNA value) +static void rna_LineStyle_active_texture_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->id.data; diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index d5347e77348..bd06cfc1936 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -125,6 +125,14 @@ static void rna_Main_ID_remove(Main *bmain, bool do_ui_user) { ID *id = id_ptr->data; + if (id->tag & LIB_TAG_NO_MAIN) { + BKE_reportf(reports, + RPT_ERROR, + "%s '%s' is outside of main database and can not be removed from it", + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + return; + } if (do_unlink) { BKE_id_delete(bmain, id); RNA_POINTER_INVALIDATE(id_ptr); @@ -200,6 +208,13 @@ static void rna_Main_scenes_remove( static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char *name, ID *data) { + if (data != NULL && (data->tag & LIB_TAG_NO_MAIN)) { + BKE_report(reports, + RPT_ERROR, + "Can not create object in main database with an evaluated data data-block"); + return NULL; + } + char safe_name[MAX_ID_NAME - 2]; rna_idname_validate(name, safe_name); @@ -273,6 +288,15 @@ static void rna_Main_materials_gpencil_data(Main *UNUSED(bmain), PointerRNA *id_ BKE_material_init_gpencil_settings(ma); } +static void rna_Main_materials_gpencil_remove(Main *UNUSED(bmain), PointerRNA *id_ptr) +{ + ID *id = id_ptr->data; + Material *ma = (Material *)id; + if (ma->gp_style) { + MEM_SAFE_FREE(ma->gp_style); + } +} + static const EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), @@ -308,16 +332,9 @@ static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) } /* copied from Mesh_getFromObject and adapted to RNA interface */ -Mesh *rna_Main_meshes_new_from_object(Main *bmain, - ReportList *reports, - Depsgraph *depsgraph, - Object *ob, - bool apply_modifiers, - bool calc_undeformed) +static Mesh *rna_Main_meshes_new_from_object(Main *bmain, ReportList *reports, Object *object) { - Scene *sce = DEG_get_evaluated_scene(depsgraph); - - switch (ob->type) { + switch (object->type) { case OB_FONT: case OB_CURVE: case OB_SURF: @@ -329,7 +346,7 @@ Mesh *rna_Main_meshes_new_from_object(Main *bmain, return NULL; } - return BKE_mesh_new_from_object(depsgraph, bmain, sce, ob, apply_modifiers, calc_undeformed); + return BKE_mesh_new_from_object_to_bmain(bmain, object); } static Light *rna_Main_lights_new(Main *bmain, const char *name, int type) @@ -850,6 +867,11 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "Material"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + func = RNA_def_function(srna, "remove_gpencil_data", "rna_Main_materials_gpencil_remove"); + RNA_def_function_ui_description(func, "Remove grease pencil material settings"); + parm = RNA_def_pointer(func, "material", "Material", "", "Material"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); @@ -937,24 +959,13 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); func = RNA_def_function(srna, "new_from_object", "rna_Main_meshes_new_from_object"); - RNA_def_function_ui_description(func, - "Add a new mesh created from object with modifiers applied"); + RNA_def_function_ui_description( + func, + "Add a new mesh created from given object (undeformed geometry if object is original, and " + "final evaluated geometry, with all modifiers etc., if object is evaluated)"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, - "depsgraph", - "Depsgraph", - "Dependency Graph", - "Evaluated dependency graph within which to evaluate modifiers"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, - "calc_undeformed", - false, - "Calculate Undeformed", - "Calculate undeformed vertex coordinates"); parm = RNA_def_pointer(func, "mesh", "Mesh", diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 8b27c69604e..7334c5baec0 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -116,7 +116,9 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr) } /* note: this function exists only to avoid id refcounting */ -static void rna_MaskParent_id_set(PointerRNA *ptr, PointerRNA value) +static void rna_MaskParent_id_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MaskParent *mpar = (MaskParent *)ptr->data; @@ -191,7 +193,9 @@ static PointerRNA rna_Mask_layer_active_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MaskLayer, masklay); } -static void rna_Mask_layer_active_set(PointerRNA *ptr, PointerRNA value) +static void rna_Mask_layer_active_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Mask *mask = (Mask *)ptr->id.data; MaskLayer *masklay = (MaskLayer *)value.data; @@ -226,7 +230,9 @@ static PointerRNA rna_MaskLayer_active_spline_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MaskSpline, masklay->act_spline); } -static void rna_MaskLayer_active_spline_set(PointerRNA *ptr, PointerRNA value) +static void rna_MaskLayer_active_spline_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MaskLayer *masklay = (MaskLayer *)ptr->data; MaskSpline *spline = (MaskSpline *)value.data; @@ -245,7 +251,9 @@ static PointerRNA rna_MaskLayer_active_spline_point_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MaskSplinePoint, masklay->act_point); } -static void rna_MaskLayer_active_spline_point_set(PointerRNA *ptr, PointerRNA value) +static void rna_MaskLayer_active_spline_point_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MaskLayer *masklay = (MaskLayer *)ptr->data; MaskSpline *spline; diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index d66b4e5be44..df48b679235 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -330,7 +330,9 @@ static int rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr) return ((pcolor->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (pcolor->fill_style > 0)); } -static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, PointerRNA value) +static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MaterialGPencilStyle *pcolor = ptr->data; ID *id = value.data; @@ -339,7 +341,9 @@ static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, PointerRNA va pcolor->sima = (struct Image *)id; } -static void rna_GpencilColorData_fill_image_set(PointerRNA *ptr, PointerRNA value) +static void rna_GpencilColorData_fill_image_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data; ID *id = value.data; @@ -440,6 +444,17 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static EnumPropertyItem alignment_draw_items[] = { + {GP_STYLE_FOLLOW_PATH, "PATH", 0, "Path", "Follow stroke drawing path and object rotation"}, + {GP_STYLE_FOLLOW_OBJ, "OBJECT", 0, "Object", "Follow object rotation only"}, + {GP_STYLE_FOLLOW_FIXED, + "FIXED", + 0, + "Fixed", + "Do not follow drawing path or object rotation and keeps aligned with viewport"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "MaterialGPencilStyle", NULL); RNA_def_struct_sdna(srna, "MaterialGPencilStyle"); RNA_def_struct_ui_text(srna, "Grease Pencil Color", ""); @@ -611,10 +626,12 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Fill", "Show stroke fills of this material"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); - /* keep Dots and Boxes aligned to screen and not to drawing path */ - prop = RNA_def_property(srna, "use_follow_path", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_STYLE_COLOR_LOCK_DOTS); - RNA_def_property_ui_text(prop, "Follow Path", "Keep Dots and Boxes aligned to drawing path"); + /* Mode to align Dots and Boxes to drawing path and object rotation */ + prop = RNA_def_property(srna, "alignment_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "alignment_mode"); + RNA_def_property_enum_items(prop, alignment_draw_items); + RNA_def_property_ui_text( + prop, "Alignment", "Defines how align Dots and Boxes with drawing path and object rotation"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update"); /* pass index for future compositing and editing tools */ @@ -778,6 +795,12 @@ void RNA_def_material(BlenderRNA *brna) "(avoids transparency sorting problems)"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_backface_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_CULL_BACKFACE); + RNA_def_property_ui_text( + prop, "Backface Culling", "Use back face culling to hide the back side of faces"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_screen_refraction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_SS_REFRACTION); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 0b4056121b3..4082222340a 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3015,12 +3015,6 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_custom_normals_get", NULL); RNA_define_verify_sdna(true); - prop = RNA_def_property(srna, "show_double_sided", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_TWOSIDED); - RNA_def_property_ui_text( - prop, "Double Sided", "Display the mesh with double or single sided lighting (OpenGL only)"); - RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); - prop = RNA_def_property(srna, "texco_mesh", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "texcomesh"); RNA_def_property_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h index ff148408728..9c5b4f9d5b3 100644 --- a/source/blender/makesrna/intern/rna_mesh_utils.h +++ b/source/blender/makesrna/intern/rna_mesh_utils.h @@ -83,7 +83,8 @@ return rna_pointer_inherit_refine(ptr, &RNA_##layer_rna_type, layer); \ } \ \ - static void rna_Mesh_##collection_name##_##active_type##_set(PointerRNA *ptr, PointerRNA value) \ + static void rna_Mesh_##collection_name##_##active_type##_set( \ + PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) \ { \ Mesh *me = rna_mesh(ptr); \ CustomData *data = rna_mesh_##customdata_type(ptr); \ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 4f304f97cac..2a09abe5f8d 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -445,6 +445,8 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = { # include "BKE_object.h" # include "BKE_particle.h" +# include "BLI_sort_utils.h" + # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_query.h" @@ -717,7 +719,8 @@ static void modifier_object_set(Object *self, Object **ob_p, int type, PointerRN } # define RNA_MOD_OBJECT_SET(_type, _prop, _obtype) \ - static void rna_##_type##Modifier_##_prop##_set(PointerRNA *ptr, PointerRNA value) \ + static void rna_##_type##Modifier_##_prop##_set( \ + PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) \ { \ _type##ModifierData *tmd = (_type##ModifierData *)ptr->data; \ modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ @@ -739,14 +742,83 @@ RNA_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH); RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH); RNA_MOD_OBJECT_SET(SurfaceDeform, target, OB_MESH); -static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value) +static void rna_HookModifier_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { + Object *owner = (Object *)ptr->id.data; HookModifierData *hmd = ptr->data; Object *ob = (Object *)value.data; hmd->object = ob; id_lib_extern((ID *)ob); - BKE_object_modifier_hook_reset(ob, hmd); + BKE_object_modifier_hook_reset(owner, hmd); +} + +static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value) +{ + Object *owner = (Object *)ptr->id.data; + HookModifierData *hmd = ptr->data; + + BLI_strncpy(hmd->subtarget, value, sizeof(hmd->subtarget)); + BKE_object_modifier_hook_reset(owner, hmd); +} + +static int rna_HookModifier_vertex_indices_get_length(PointerRNA *ptr, + int length[RNA_MAX_ARRAY_DIMENSION]) +{ + HookModifierData *hmd = ptr->data; + int totindex = hmd->indexar ? hmd->totindex : 0; + return (length[0] = totindex); +} + +static void rna_HookModifier_vertex_indices_get(PointerRNA *ptr, int *values) +{ + HookModifierData *hmd = ptr->data; + if (hmd->indexar != NULL) { + memcpy(values, hmd->indexar, sizeof(int) * hmd->totindex); + } +} + +static void rna_HookModifier_vertex_indices_set(HookModifierData *hmd, + ReportList *reports, + int indices_len, + int *indices) +{ + if (indices_len == 0) { + MEM_SAFE_FREE(hmd->indexar); + hmd->totindex = 0; + } + else { + /* Reject negative indices. */ + for (int i = 0; i < indices_len; i++) { + if (indices[i] < 0) { + BKE_reportf(reports, RPT_ERROR, "Negative vertex index in vertex_indices_set"); + return; + } + } + + /* Copy and sort the index array. */ + size_t size = sizeof(int) * indices_len; + int *buffer = MEM_mallocN(size, "hook indexar"); + memcpy(buffer, indices, size); + + qsort(buffer, indices_len, sizeof(int), BLI_sortutil_cmp_int); + + /* Reject duplicate indices. */ + for (int i = 1; i < indices_len; i++) { + if (buffer[i] == buffer[i - 1]) { + BKE_reportf(reports, RPT_ERROR, "Duplicate index %d in vertex_indices_set", buffer[i]); + MEM_freeN(buffer); + return; + } + } + + /* Success - save the new array. */ + MEM_SAFE_FREE(hmd->indexar); + hmd->indexar = buffer; + hmd->totindex = indices_len; + } } static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr) @@ -755,7 +827,9 @@ static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Object, *ob); } -static void rna_UVProjector_object_set(PointerRNA *ptr, PointerRNA value) +static void rna_UVProjector_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object **ob_p = (Object **)ptr->data; Object *ob = (Object *)value.data; @@ -1328,7 +1402,8 @@ static PointerRNA rna_ParticleInstanceModifier_particle_system_get(PointerRNA *p } static void rna_ParticleInstanceModifier_particle_system_set(PointerRNA *ptr, - const PointerRNA value) + const PointerRNA value, + struct ReportList *UNUSED(reports)) { ParticleInstanceModifierData *psmd = ptr->data; @@ -2149,6 +2224,8 @@ static void rna_def_modifier_hook(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; srna = RNA_def_struct(brna, "HookModifier", "Modifier"); RNA_def_struct_ui_text( @@ -2181,9 +2258,10 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Falloff Curve", "Custom falloff curve"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "cent"); - RNA_def_property_ui_text(prop, "Hook Center", ""); + RNA_def_property_ui_text( + prop, "Hook Center", "Center of the hook, used for falloff and display"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); @@ -2206,6 +2284,7 @@ static void rna_def_modifier_hook(BlenderRNA *brna) prop, "Sub-Target", "Name of Parent Bone for hook (if applicable), also recalculates and clears offset"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookModifier_subtarget_set"); RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE); @@ -2221,6 +2300,26 @@ static void rna_def_modifier_hook(BlenderRNA *brna) "Name of Vertex Group which determines influence of modifier per point"); RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookModifier_name_set"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "vertex_indices", PROP_INT, PROP_UNSIGNED); + RNA_def_property_array(prop, RNA_MAX_ARRAY_LENGTH); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_HookModifier_vertex_indices_get_length"); + RNA_def_property_int_funcs(prop, "rna_HookModifier_vertex_indices_get", NULL, NULL); + RNA_def_property_ui_text(prop, + "Vertex Indices", + "Indices of vertices bound to the modifier. For bezier curves, " + "handles count as additional vertices"); + + func = RNA_def_function(srna, "vertex_indices_set", "rna_HookModifier_vertex_indices_set"); + RNA_def_function_ui_description( + func, "Validates and assigns the array of vertex indices bound to the modifier"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_int_array( + func, "indices", 1, NULL, INT_MIN, INT_MAX, "", "Vertex Indices", 0, INT_MAX); + RNA_def_property_array(parm, RNA_MAX_ARRAY_LENGTH); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED); } static void rna_def_modifier_softbody(BlenderRNA *brna) @@ -3100,6 +3199,7 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna) prop = RNA_def_property(srna, "use_children", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", eParticleInstanceFlag_Children); RNA_def_property_ui_text(prop, "Children", "Create instances from child particles"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_PARTICLESETTINGS); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_path", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index e4270f3854e..d634a34bc5b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -814,7 +814,9 @@ static PointerRNA rna_NodeTree_active_node_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Node, node); } -static void rna_NodeTree_active_node_set(PointerRNA *ptr, const PointerRNA value) +static void rna_NodeTree_active_node_set(PointerRNA *ptr, + const PointerRNA value, + struct ReportList *UNUSED(reports)) { bNodeTree *ntree = (bNodeTree *)ptr->data; bNode *node = (bNode *)value.data; @@ -1608,7 +1610,9 @@ static IDProperty *rna_Node_idprops(PointerRNA *ptr, bool create) return node->prop; } -static void rna_Node_parent_set(PointerRNA *ptr, PointerRNA value) +static void rna_Node_parent_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bNode *node = ptr->data; bNode *parent = value.data; @@ -2683,7 +2687,9 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * ED_node_tag_update_nodetree(bmain, ntree, node); } -static void rna_NodeGroup_node_tree_set(PointerRNA *ptr, const PointerRNA value) +static void rna_NodeGroup_node_tree_set(PointerRNA *ptr, + const PointerRNA value, + struct ReportList *UNUSED(reports)) { bNodeTree *ntree = ptr->id.data; bNode *node = ptr->data; @@ -2791,7 +2797,9 @@ static void rna_Matte_t2_set(PointerRNA *ptr, float value) chroma->t2 = value; } -static void rna_Node_scene_set(PointerRNA *ptr, PointerRNA value) +static void rna_Node_scene_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bNode *node = (bNode *)ptr->data; @@ -3345,7 +3353,9 @@ static PointerRNA rna_ShaderNodePointDensity_psys_get(PointerRNA *ptr) return value; } -static void rna_ShaderNodePointDensity_psys_set(PointerRNA *ptr, PointerRNA value) +static void rna_ShaderNodePointDensity_psys_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bNode *node = ptr->data; NodeShaderTexPointDensity *shader_point_density = node->storage; @@ -3987,21 +3997,6 @@ static void def_sh_tex_sky(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } -static const EnumPropertyItem sh_tex_prop_color_space_items[] = { - {SHD_COLORSPACE_COLOR, - "COLOR", - 0, - "Color", - "Image contains color data, and will be converted to linear color for rendering"}, - {SHD_COLORSPACE_NONE, - "NONE", - 0, - "Non-Color Data", - "Image contains non-color data, for example a displacement or normal map, " - "and will not be converted"}, - {0, NULL, 0, NULL, NULL}, -}; - static const EnumPropertyItem sh_tex_prop_interpolation_items[] = { {SHD_INTERP_LINEAR, "Linear", 0, "Linear", "Linear interpolation"}, {SHD_INTERP_CLOSEST, "Closest", 0, "Closest", "No interpolation (sample closest texel)"}, @@ -4038,12 +4033,6 @@ static void def_sh_tex_environment(StructRNA *srna) RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage"); def_sh_tex(srna); - prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); - RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); - RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); - RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text(prop, "Projection", "Projection of the input image"); @@ -4122,12 +4111,6 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage"); def_sh_tex(srna); - prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items); - RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR); - RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); - RNA_def_property_update(prop, 0, "rna_Node_update"); - prop = RNA_def_property(srna, "projection", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_projection_items); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 219445f629f..e2f566cfdab 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -427,7 +427,7 @@ static void rna_Object_dependency_update(Main *bmain, Scene *UNUSED(scene), Poin WM_main_add_notifier(NC_OBJECT | ND_PARENT, ptr->id.data); } -static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) +static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, struct ReportList *reports) { Object *ob = (Object *)ptr->data; ID *id = value.data; @@ -441,8 +441,13 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) return; } - BLI_assert(BKE_id_is_in_global_main(&ob->id)); - BLI_assert(BKE_id_is_in_global_main(id)); + if ((id->tag & LIB_TAG_NO_MAIN) != (ob->id.tag & LIB_TAG_NO_MAIN)) { + BKE_report(reports, + RPT_ERROR, + "Can only assign evaluated data to to evaluated object, or original data to " + "original object"); + return; + } if (ob->type == OB_EMPTY) { if (ob->data) { @@ -529,7 +534,9 @@ static bool rna_Object_data_poll(PointerRNA *ptr, const PointerRNA value) return true; } -static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value) +static void rna_Object_parent_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->data; Object *par = (Object *)value.data; @@ -614,7 +621,9 @@ static const EnumPropertyItem *rna_Object_instance_type_itemf(bContext *UNUSED(C return item; } -static void rna_Object_dup_collection_set(PointerRNA *ptr, PointerRNA value) +static void rna_Object_dup_collection_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->data; Collection *grp = (Collection *)value.data; @@ -890,7 +899,9 @@ static PointerRNA rna_Object_active_material_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Material, ma); } -static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value) +static void rna_Object_active_material_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->id.data; @@ -1089,7 +1100,9 @@ static PointerRNA rna_MaterialSlot_material_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Material, ma); } -static void rna_MaterialSlot_material_set(PointerRNA *ptr, PointerRNA value) +static void rna_MaterialSlot_material_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->id.data; int index = (Material **)ptr->data - ob->mat; @@ -1277,7 +1290,9 @@ static PointerRNA rna_Object_active_constraint_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con); } -static void rna_Object_active_constraint_set(PointerRNA *ptr, PointerRNA value) +static void rna_Object_active_constraint_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->id.data; BKE_constraints_active_set(&ob->constraints, (bConstraint *)value.data); @@ -2801,9 +2816,9 @@ static void rna_def_object(BlenderRNA *brna) /* restrict */ prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEW); + RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEWPORT); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_ui_text(prop, "Disable View", "Disable object in the viewport"); + RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); @@ -2811,14 +2826,14 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_SELECT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_ui_text(prop, "Disable Select", "Disable object selection in the viewport"); + RNA_def_property_ui_text(prop, "Disable Selection", "Disable selection in viewport"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_RENDER); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_ui_text(prop, "Disable Render", "Disable object in renders"); + RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 21300f22b95..7362f6ba610 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -375,18 +375,28 @@ static void rna_Object_camera_fit_coords( } /* copied from Mesh_getFromObject and adapted to RNA interface */ -/* settings: 0 - preview, 1 - render */ -static Mesh *rna_Object_to_mesh(Object *ob, - bContext *C, - ReportList *reports, - Depsgraph *depsgraph, - bool apply_modifiers, - bool calc_undeformed) +static Mesh *rna_Object_to_mesh(Object *object, ReportList *reports) { - Main *bmain = CTX_data_main(C); + /* TODO(sergey): Make it more re-usable function, de-duplicate with + * rna_Main_meshes_new_from_object. */ + switch (object->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + case OB_MBALL: + case OB_MESH: + break; + default: + BKE_report(reports, RPT_ERROR, "Object does not have geometry data"); + return NULL; + } - return rna_Main_meshes_new_from_object( - bmain, reports, depsgraph, ob, apply_modifiers, calc_undeformed); + return BKE_object_to_mesh(object); +} + +static void rna_Object_to_mesh_clear(Object *object) +{ + BKE_object_to_mesh_clear(object); } static PointerRNA rna_Object_shape_key_add( @@ -398,7 +408,7 @@ static PointerRNA rna_Object_shape_key_add( if ((kb = BKE_object_shapekey_insert(bmain, ob, name, from_mix))) { PointerRNA keyptr; - RNA_pointer_create((ID *)ob->data, &RNA_ShapeKey, kb, &keyptr); + RNA_pointer_create((ID *)BKE_key_from_object(ob), &RNA_ShapeKey, kb, &keyptr); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return keyptr; @@ -433,6 +443,14 @@ static void rna_Object_shape_key_remove(Object *ob, RNA_POINTER_INVALIDATE(kb_ptr); } +static void rna_Object_shape_key_clear(Object *ob, Main *bmain) +{ + BKE_object_shapekey_free(bmain, ob); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); +} + # if 0 static void rna_Mesh_assign_verts_to_group( Object *ob, bDeformGroup *group, int *indices, int totindex, float weight, int assignmode) @@ -874,28 +892,18 @@ void RNA_api_object(StructRNA *srna) /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied"); - RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); - parm = RNA_def_pointer(func, - "depsgraph", - "Depsgraph", - "Dependency Graph", - "Evaluated dependency graph within which to evaluate modifiers"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, - "calc_undeformed", - false, - "Calculate Undeformed", - "Calculate undeformed vertex coordinates"); - parm = RNA_def_pointer(func, - "mesh", - "Mesh", - "", - "Mesh created from object, remove it if it is only used for export"); + RNA_def_function_ui_description( + func, + "Create a Mesh data-block from the current state of the object. The object owns the " + "data-block. To force free it use to_mesh_clear(). " + "The result is temporary and can not be used by objects from the main database"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "to_mesh_clear", "rna_Object_to_mesh_clear"); + RNA_def_function_ui_description(func, "Clears mesh data-block created by to_mesh()"); + /* Armature */ func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature"); RNA_def_function_ui_description( @@ -921,6 +929,10 @@ void RNA_api_object(StructRNA *srna) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + func = RNA_def_function(srna, "shape_key_clear", "rna_Object_shape_key_clear"); + RNA_def_function_ui_description(func, "Remove all Shape Keys from this object"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + /* Ray Cast */ func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast"); RNA_def_function_ui_description( diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index c4f0eb35627..2abb1f3227a 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -754,7 +754,7 @@ static void rna_def_pointcache_common(StructRNA *srna) static const EnumPropertyItem point_cache_compress_items[] = { {PTCACHE_COMPRESS_NO, "NO", 0, "None", "No compression"}, - {PTCACHE_COMPRESS_LZO, "LIGHT", 0, "Light", "Fast but not so effective compression"}, + {PTCACHE_COMPRESS_LZO, "LIGHT", 0, "Lite", "Fast but not so effective compression"}, {PTCACHE_COMPRESS_LZMA, "HEAVY", 0, "Heavy", "Effective but slow compression"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c index 7b35092dea4..9af6387389c 100644 --- a/source/blender/makesrna/intern/rna_palette.c +++ b/source/blender/makesrna/intern/rna_palette.c @@ -74,7 +74,9 @@ static PointerRNA rna_Palette_active_color_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, NULL, NULL); } -static void rna_Palette_active_color_set(PointerRNA *ptr, PointerRNA value) +static void rna_Palette_active_color_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Palette *palette = ptr->data; PaletteColor *color = value.data; diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 8c3d16f9c8c..641bf4128d0 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -792,7 +792,9 @@ static PointerRNA rna_particle_settings_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ParticleSettings, part); } -static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value) +static void rna_particle_settings_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = ptr->id.data; ParticleSystem *psys = (ParticleSystem *)ptr->data; @@ -1318,7 +1320,9 @@ static PointerRNA rna_ParticleSettings_active_texture_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex); } -static void rna_ParticleSettings_active_texture_set(PointerRNA *ptr, PointerRNA value) +static void rna_ParticleSettings_active_texture_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { ParticleSettings *part = (ParticleSettings *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 1b4a7efbdd8..3ab41f72322 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -122,6 +122,11 @@ static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe BIK_clear_data(ob->pose); } +static char *rna_Pose_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("pose"); +} + static char *rna_PoseBone_path(PointerRNA *ptr) { bPoseChannel *pchan = ptr->data; @@ -284,6 +289,18 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value) ED_armature_bone_rename(G_MAIN, ob->data, oldname, newname); } +static PointerRNA rna_PoseChannel_bone_get(PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->id.data; + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + PointerRNA tmp_ptr = *ptr; + + /* Replace the id_data pointer with the Armature ID. */ + tmp_ptr.id.data = ob->data; + + return rna_pointer_inherit_refine(&tmp_ptr, &RNA_Bone, pchan->bone); +} + static bool rna_PoseChannel_has_ik_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; @@ -356,7 +373,9 @@ static void rna_Itasc_update_rebuild(Main *bmain, Scene *scene, PointerRNA *ptr) rna_Itasc_update(bmain, scene, ptr); } -static void rna_PoseChannel_bone_custom_set(PointerRNA *ptr, PointerRNA value) +static void rna_PoseChannel_bone_custom_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; @@ -385,7 +404,9 @@ static PointerRNA rna_PoseChannel_bone_group_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_BoneGroup, grp); } -static void rna_PoseChannel_bone_group_set(PointerRNA *ptr, PointerRNA value) +static void rna_PoseChannel_bone_group_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Object *ob = (Object *)ptr->id.data; bPose *pose = (ob) ? ob->pose : NULL; @@ -426,7 +447,9 @@ static PointerRNA rna_Pose_active_bone_group_get(PointerRNA *ptr) ptr, &RNA_BoneGroup, BLI_findlink(&pose->agroups, pose->active_group - 1)); } -static void rna_Pose_active_bone_group_set(PointerRNA *ptr, PointerRNA value) +static void rna_Pose_active_bone_group_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bPose *pose = (bPose *)ptr->data; pose->active_group = BLI_findindex(&pose->agroups, value.data) + 1; @@ -515,7 +538,9 @@ static PointerRNA rna_PoseChannel_active_constraint_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con); } -static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, PointerRNA value) +static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; BKE_constraints_active_set(&pchan->constraints, (bConstraint *)value.data); @@ -753,7 +778,9 @@ static bPoseChannel *rna_PoseChannel_ensure_own_pchan(Object *ob, return ref_pchan; } -static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr, PointerRNA value) +static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { bPoseChannel *pchan = (bPoseChannel *)ptr->data; Object *ob = (Object *)ptr->id.data; @@ -911,6 +938,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "Bone"); + RNA_def_property_pointer_funcs(prop, "rna_PoseChannel_bone_get", NULL, NULL, NULL); RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Bone", "Bone associated with this PoseBone"); @@ -1551,6 +1579,31 @@ static void rna_def_pose(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "IK Param", "Parameters for IK solver"); + /* pose edit options */ + prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_MIRROR_EDIT); + RNA_def_property_ui_text( + prop, "X-Axis Mirror", "Apply changes to matching bone on opposite side of X-Axis"); + RNA_def_struct_path_func(srna, "rna_Pose_path"); + RNA_def_property_update(prop, 0, "rna_Pose_update"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + + prop = RNA_def_property(srna, "use_mirror_relative", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_MIRROR_RELATIVE); + RNA_def_property_ui_text( + prop, "Relative Mirror", "Apply relative transformations in X-mirror mode"); + RNA_def_struct_path_func(srna, "rna_Pose_path"); + RNA_def_property_update(prop, 0, "rna_Pose_update"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + + prop = RNA_def_property(srna, "use_auto_ik", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_AUTO_IK); + RNA_def_property_ui_text( + prop, "Auto IK", "Add temporary IK constraints while grabbing bones in Pose Mode"); + RNA_def_struct_path_func(srna, "rna_Pose_path"); + RNA_def_property_update(prop, 0, "rna_Pose_update"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + /* animviz */ rna_def_animviz_common(srna); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 81ec7857487..2dc873ca17d 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -206,7 +206,9 @@ static void engine_bake(RenderEngine *engine, RNA_parameter_list_free(&list); } -static void engine_view_update(RenderEngine *engine, const struct bContext *context) +static void engine_view_update(RenderEngine *engine, + const struct bContext *context, + Depsgraph *depsgraph) { extern FunctionRNA rna_RenderEngine_view_update_func; PointerRNA ptr; @@ -218,12 +220,15 @@ static void engine_view_update(RenderEngine *engine, const struct bContext *cont RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "context", &context); + RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph); engine->type->ext.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); } -static void engine_view_draw(RenderEngine *engine, const struct bContext *context) +static void engine_view_draw(RenderEngine *engine, + const struct bContext *context, + Depsgraph *depsgraph) { extern FunctionRNA rna_RenderEngine_view_draw_func; PointerRNA ptr; @@ -235,6 +240,7 @@ static void engine_view_draw(RenderEngine *engine, const struct bContext *contex RNA_parameter_list_create(&list, &ptr, func); RNA_parameter_set_lookup(&list, "context", &context); + RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph); engine->type->ext.call(NULL, &ptr, func, &list); RNA_parameter_list_free(&list); @@ -554,12 +560,18 @@ static void rna_def_render_engine(BlenderRNA *brna) func = RNA_def_function(srna, "view_update", NULL); RNA_def_function_ui_description(func, "Update on data changes for viewport render"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); - RNA_def_pointer(func, "context", "Context", "", ""); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "view_draw", NULL); RNA_def_function_ui_description(func, "Draw viewport render"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); - RNA_def_pointer(func, "context", "Context", "", ""); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* shader script callbacks */ func = RNA_def_function(srna, "update_script_node", NULL); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 032a1f86fc0..b8d42397841 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -2373,7 +2373,7 @@ bool rna_property_override_apply_default(Main *UNUSED(bmain), switch (override_op) { case IDOVERRIDESTATIC_OP_REPLACE: - RNA_property_pointer_set(ptr_dst, prop_dst, value); + RNA_property_pointer_set(ptr_dst, prop_dst, value, NULL); break; default: BLI_assert(0 && "Unsupported RNA override operation on pointer"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 6f6699fa81b..894f9bfbe3e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -192,6 +192,45 @@ static const EnumPropertyItem snap_uv_element_items[] = { {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, {0, NULL, 0, NULL, NULL}, }; + +static const EnumPropertyItem rna_enum_scene_display_aa_methods[] = { + {SCE_DISPLAY_AA_OFF, + "OFF", + 0, + "No Anti-Aliasing", + "Scene will be rendering without any anti-aliasing"}, + {SCE_DISPLAY_AA_FXAA, + "FXAA", + 0, + "Single Pass Anti-Aliasing", + "Scene will be rendered using a single pass anti-aliasing method (FXAA)"}, + {SCE_DISPLAY_AA_SAMPLES_5, + "5", + 0, + "5 Samples", + "Scene will be rendered using 5 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_8, + "8", + 0, + "8 Samples", + "Scene will be rendered using 8 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_11, + "11", + 0, + "11 Samples", + "Scene will be rendered using 11 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_16, + "16", + 0, + "16 Samples", + "Scene will be rendered using 16 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_32, + "32", + 0, + "32 Samples", + "Scene will be rendered using 32 anti-aliasing samples"}, + {0, NULL, 0, NULL, NULL}, +}; #endif const EnumPropertyItem rna_enum_curve_fit_method_items[] = { @@ -733,7 +772,9 @@ static PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter) /* End of read-only Iterator of all the scene objects. */ -static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value) +static void rna_Scene_set_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Scene *scene = (Scene *)ptr->data; Scene *set = (Scene *)value.data; @@ -930,7 +971,9 @@ static PointerRNA rna_Scene_active_keying_set_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_KeyingSet, ANIM_scene_get_active_keyingset(scene)); } -static void rna_Scene_active_keying_set_set(PointerRNA *ptr, PointerRNA value) +static void rna_Scene_active_keying_set_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { Scene *scene = (Scene *)ptr->data; KeyingSet *ks = (KeyingSet *)value.data; @@ -1396,7 +1439,9 @@ static PointerRNA rna_RenderSettings_active_view_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_SceneRenderView, srv); } -static void rna_RenderSettings_active_view_set(PointerRNA *ptr, PointerRNA value) +static void rna_RenderSettings_active_view_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { RenderData *rd = (RenderData *)ptr->data; SceneRenderView *srv = (SceneRenderView *)value.data; @@ -1810,6 +1855,20 @@ static void rna_View3DCursor_rotation_axis_angle_set(PointerRNA *ptr, const floa copy_v3_v3(cursor->rotation_axis, &value[1]); } +static void rna_View3DCursor_matrix_get(PointerRNA *ptr, float *values) +{ + const View3DCursor *cursor = ptr->data; + BKE_scene_cursor_to_mat4(cursor, (float(*)[4])values); +} + +static void rna_View3DCursor_matrix_set(PointerRNA *ptr, const float *values) +{ + View3DCursor *cursor = ptr->data; + float unit_mat[4][4]; + normalize_m4_m4(unit_mat, (const float(*)[4])values); + BKE_scene_cursor_from_mat4(cursor, unit_mat, false); +} + static char *rna_View3DCursor_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("cursor"); @@ -1987,7 +2046,9 @@ PointerRNA rna_FreestyleLineSet_linestyle_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineStyle, lineset->linestyle); } -void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value) +void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data; @@ -2094,45 +2155,6 @@ void rna_FreestyleSettings_module_remove(ID *id, WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL); } -char *rna_GPUDOF_path(PointerRNA *ptr) -{ - /* if there is ID-data, resolve the path using the index instead of by name, - * since the name used is the name of the texture assigned, but the texture - * may be used multiple times in the same stack - */ - if (ptr->id.data) { - if (GS(((ID *)ptr->id.data)->name) == ID_CA) { - return BLI_strdup("gpu_dof"); - } - } - - return BLI_strdup(""); -} - -static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value) -{ - GPUDOFSettings *dofsettings = (GPUDOFSettings *)ptr->data; - - if (value == 1 || value == 2) { - if (dofsettings->num_blades == 0) { - dofsettings->num_blades = 3; - } - else { - dofsettings->num_blades = 0; - } - } - else { - dofsettings->num_blades = value; - } -} - -static void rna_GPUDOFSettings_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) -{ - /* TODO(sergey): Can be more selective here. */ - BKE_sequencer_cache_cleanup_all(bmain); - WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); -} - static void rna_Stereo3dFormat_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; @@ -2547,6 +2569,14 @@ static void rna_def_view3d_cursor(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, "rna_View3DCursor_rotation_mode_set", NULL); RNA_def_property_ui_text(prop, "Rotation Mode", ""); RNA_def_property_update(prop, NC_WINDOW, NULL); + + /* Matrix access to avoid having to check current rotation mode. */ + prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_flag(prop, PROP_THICK_WRAP); /* no reference to original data */ + RNA_def_property_ui_text(prop, "Transform Matrix", "Matrix combining loc/rot of the cursor"); + RNA_def_property_float_funcs( + prop, "rna_View3DCursor_matrix_get", "rna_View3DCursor_matrix_set", NULL); } static void rna_def_tool_settings(BlenderRNA *brna) @@ -2564,23 +2594,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem edge_tag_items[] = { - {EDGE_MODE_SELECT, "SELECT", 0, "Select", ""}, - {EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""}, - {EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""}, - {EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""}, - {EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""}, - {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - static EnumPropertyItem mod_weighted_strength[] = { - {FACE_STRENGTH_WEAK, "Weak", 0, "Weak", ""}, - {FACE_STRENGTH_MEDIUM, "Medium", 0, "Medium", ""}, - {FACE_STRENGTH_STRONG, "Strong", 0, "Strong", ""}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem draw_groupuser_items[] = { {OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""}, {OB_DRAW_GROUPUSER_ACTIVE, @@ -2766,7 +2779,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "proportional_objects", 0); RNA_def_property_ui_text( prop, "Proportional Editing Objects", "Proportional editing object mode"); - RNA_def_property_ui_icon(prop, ICON_PROP_ON, 0); + RNA_def_property_ui_icon(prop, ICON_PROP_OFF, 1); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ prop = RNA_def_property(srna, "use_proportional_projected", PROP_BOOLEAN, PROP_NONE); @@ -2810,6 +2823,8 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_items); RNA_def_property_ui_text( prop, "Proportional Editing Falloff", "Falloff type for proportional editing mode"); + /* Abusing id_curve :/ */ + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ prop = RNA_def_property(srna, "proportional_size", PROP_FLOAT, PROP_DISTANCE); @@ -2820,8 +2835,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "doublimit"); - RNA_def_property_ui_text( - prop, "Double Threshold", "Limit for removing duplicates and 'Auto Merge'"); + RNA_def_property_ui_text(prop, "Merge Threshold", "Threshold distance for Auto Merge"); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_range(prop, 0.0, 0.1, 0.01, 6); @@ -2842,7 +2856,8 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0); RNA_def_property_ui_text( - prop, "AutoMerge Editing", "Automatically merge vertices moved to the same location"); + prop, "Auto Merge", "Automatically merge vertices moved to the same location"); + RNA_def_property_ui_icon(prop, ICON_AUTOMERGE_OFF, 1); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ prop = RNA_def_property(srna, "use_snap", PROP_BOOLEAN, PROP_NONE); @@ -3120,13 +3135,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "vgroup_weight"); RNA_def_property_ui_text(prop, "Vertex Group Weight", "Weight to assign in vertex groups"); - /* use with MESH_OT_shortest_path_pick */ - prop = RNA_def_property(srna, "edge_path_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "edge_mode"); - RNA_def_property_enum_items(prop, edge_tag_items); - RNA_def_property_ui_text( - prop, "Edge Tag Mode", "The edge flag to tag when selecting the shortest path"); - prop = RNA_def_property(srna, "use_edge_path_live_unwrap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1); RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap"); @@ -3135,10 +3143,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply"); RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3); - prop = RNA_def_property(srna, "face_strength", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, mod_weighted_strength); - RNA_def_property_ui_text(prop, "Face Strength", "Set strength of face to specified value"); - /* Unified Paint Settings */ prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -3529,7 +3533,8 @@ static void rna_def_unit_settings(BlenderRNA *brna) /* Units */ prop = RNA_def_property(srna, "system", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, unit_systems); - RNA_def_property_ui_text(prop, "Unit System", "The unit system to use for button display"); + RNA_def_property_ui_text( + prop, "Unit System", "The unit system to use for user interface controls"); RNA_def_property_update(prop, NC_WINDOW, "rna_UnitSettings_system_update"); prop = RNA_def_property(srna, "system_rotation", PROP_ENUM, PROP_NONE); @@ -4662,60 +4667,6 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } -static void rna_def_gpu_dof_fx(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "GPUDOFSettings", NULL); - RNA_def_struct_ui_text(srna, "GPU DOF", "Settings for GPU based depth of field"); - RNA_def_struct_path_func(srna, "rna_GPUDOF_path"); - - prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_ui_text(prop, "Focus distance", "Viewport depth of field focus distance"); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.0f, 5000.0f, 1, 2); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - prop = RNA_def_property(srna, "focal_length", PROP_FLOAT, PROP_DISTANCE_CAMERA); - RNA_def_property_ui_text(prop, "Focal Length", "Focal length for dof effect"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 1, 2); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - prop = RNA_def_property(srna, "sensor", PROP_FLOAT, PROP_DISTANCE_CAMERA); - RNA_def_property_ui_text(prop, "Sensor", "Size of sensor"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 1, 2); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - prop = RNA_def_property(srna, "fstop", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "F-stop", "F-stop for dof effect"); - RNA_def_property_float_default(prop, 128.0f); - RNA_def_property_range(prop, 0.0f, FLT_MAX); - RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - prop = RNA_def_property(srna, "blades", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "num_blades"); - RNA_def_property_ui_text(prop, "Blades", "Blades for dof effect"); - RNA_def_property_range(prop, 0, 16); - RNA_def_property_int_funcs(prop, NULL, "rna_GPUDOFSettings_blades_set", NULL); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_ui_text(prop, "Rotation", "Rotation of blades in aperture"); - RNA_def_property_range(prop, -M_PI, M_PI); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh"); - RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_range(prop, 0.01f, FLT_MAX); - RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -} - static void rna_def_gpu_ssao_fx(BlenderRNA *brna) { StructRNA *srna; @@ -4760,23 +4711,10 @@ static void rna_def_gpu_fx(BlenderRNA *brna) PropertyRNA *prop; rna_def_gpu_ssao_fx(brna); - rna_def_gpu_dof_fx(brna); srna = RNA_def_struct(brna, "GPUFXSettings", NULL); RNA_def_struct_ui_text(srna, "GPU FX Settings", "Settings for GPU based compositing"); - prop = RNA_def_property(srna, "dof", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_struct_type(prop, "GPUDOFSettings"); - RNA_def_property_ui_text(prop, "Depth Of Field settings", ""); - - prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_DOF); - RNA_def_property_ui_text(prop, - "Depth Of Field", - "Use depth of field on viewport using the values from active camera"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "ssao", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "GPUSSAOSettings"); @@ -5434,16 +5372,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem alpha_mode_items[] = { - {R_ADDSKY, "SKY", 0, "Sky", "Transparent pixels are filled with sky color"}, - {R_ALPHAPREMUL, - "TRANSPARENT", - 0, - "Transparent", - "World background is transparent with premultiplied alpha"}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem display_mode_items[] = { {R_OUTPUT_SCREEN, "SCREEN", @@ -5477,14 +5405,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem fixed_oversample_items[] = { - {5, "5", 0, "5", ""}, - {8, "8", 0, "8", ""}, - {11, "11", 0, "11", ""}, - {16, "16", 0, "16", ""}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem threads_mode_items[] = { {0, "AUTO", @@ -5679,27 +5599,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop, "Filter Size", "Width over which the reconstruction filter combines samples"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "alphamode"); - RNA_def_property_enum_items(prop, alpha_mode_items); - RNA_def_property_ui_text( - prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); - - prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "mode", R_OSA); + prop = RNA_def_property(srna, "film_transparent", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "alphamode", R_ALPHAPREMUL); RNA_def_property_ui_text( prop, - "Anti-Aliasing", - "Render and combine multiple samples per pixel to prevent jagged edges"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - - prop = RNA_def_property(srna, "antialiasing_samples", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "osa"); - RNA_def_property_enum_items(prop, fixed_oversample_items); - RNA_def_property_ui_text( - prop, "Anti-Aliasing Samples", "Amount of anti-aliasing samples per pixel"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + "Transparent", + "World background is transparent, for compositing the render over another background"); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update"); prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -6573,6 +6479,18 @@ static void rna_def_scene_display(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Samples", "Number of samples"); RNA_def_property_range(prop, 1, 500); + prop = RNA_def_property(srna, "render_aa", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_scene_display_aa_methods); + RNA_def_property_ui_text( + prop, "Render Anti-Aliasing", "Method of anti-aliasing when rendering final image"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "viewport_aa", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_scene_display_aa_methods); + RNA_def_property_ui_text( + prop, "Viewport Anti-Aliasing", "Method of anti-aliasing when rendering 3d viewport"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + /* OpenGL render engine settings. */ prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Shading Settings", "Shading settings for OpenGL render engine"); @@ -6743,14 +6661,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* Screen Space Subsurface Scattering */ - prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_ENABLED); - RNA_def_property_boolean_default(prop, 0); - RNA_def_property_ui_text( - prop, "Subsurface Scattering", "Enable screen space subsurface scattering"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE); RNA_def_property_int_default(prop, 7); RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect"); @@ -6836,14 +6746,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* Volumetrics */ - prop = RNA_def_property(srna, "use_volumetric", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_ENABLED); - RNA_def_property_boolean_default(prop, 0); - RNA_def_property_ui_text( - prop, "Volumetrics", "Enable scattering and absorbance of volumetric material"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect"); @@ -6968,14 +6870,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* Depth of Field */ - prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_DOF_ENABLED); - RNA_def_property_boolean_default(prop, 0); - RNA_def_property_ui_text( - prop, "Depth of Field", "Enable depth of field using the values from the active camera"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); - prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_PIXEL); RNA_def_property_float_default(prop, 100.0f); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index e29891b60db..1d4d2e9cdd9 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -116,23 +116,6 @@ static void rna_Scene_uvedit_aspect(Scene *scene, Object *ob, float *aspect) aspect[0] = aspect[1] = 1.0f; } -static void rna_Scene_update_tagged(Scene *scene, Main *bmain) -{ -# ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; -# endif - - for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL; - view_layer = view_layer->next) { - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - BKE_scene_graph_update_tagged(depsgraph, bmain); - } - -# ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; -# endif -} - static void rna_SceneRender_get_frame_path( RenderData *rd, Main *bmain, int frame, bool preview, const char *view, char *name) { @@ -303,11 +286,6 @@ void RNA_api_scene(StructRNA *srna) func, "subframe", 0.0, 0.0, 1.0, "", "Sub-frame time, between 0.0 and 1.0", 0.0, 1.0); RNA_def_function_flag(func, FUNC_USE_MAIN); - func = RNA_def_function(srna, "update", "rna_Scene_update_tagged"); - RNA_def_function_ui_description( - func, "Update data tagged to be updated from previous access to data or operators"); - RNA_def_function_flag(func, FUNC_USE_MAIN); - func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect"); RNA_def_function_ui_description(func, "Get uv aspect for current object"); parm = RNA_def_pointer(func, "object", "Object", "", "Object"); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 3de946c1c8f..9c349d64953 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -93,7 +93,7 @@ static bool rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr)) static int rna_region_alignment_get(PointerRNA *ptr) { ARegion *region = ptr->data; - return (region->alignment & ~RGN_SPLIT_PREV); + return RGN_ALIGN_ENUM_FROM_MASK(region->alignment); } static bool rna_Screen_fullscreen_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 0b1e35e3a74..713ffe2fb08 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -465,7 +465,9 @@ static void rna_SequenceCrop_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P BKE_sequence_invalidate_cache(scene, seq); } -static void rna_Sequence_text_font_set(PointerRNA *ptr, PointerRNA ptr_value) +static void rna_Sequence_text_font_set(PointerRNA *ptr, + PointerRNA ptr_value, + struct ReportList *UNUSED(reports)) { Sequence *seq = ptr->data; TextVars *data = seq->effectdata; @@ -1189,25 +1191,25 @@ static void rna_def_strip_crop(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Sequence Crop", "Cropping parameters for a sequence strip"); RNA_def_struct_sdna(srna, "StripCrop"); - prop = RNA_def_property(srna, "max_y", PROP_INT, PROP_UNSIGNED); + prop = RNA_def_property(srna, "max_y", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "top"); RNA_def_property_ui_text(prop, "Top", "Number of pixels to crop from the top"); RNA_def_property_ui_range(prop, 0, 4096, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update"); - prop = RNA_def_property(srna, "min_y", PROP_INT, PROP_UNSIGNED); + prop = RNA_def_property(srna, "min_y", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "bottom"); RNA_def_property_ui_text(prop, "Bottom", "Number of pixels to crop from the bottom"); RNA_def_property_ui_range(prop, 0, 4096, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update"); - prop = RNA_def_property(srna, "min_x", PROP_INT, PROP_UNSIGNED); + prop = RNA_def_property(srna, "min_x", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "left"); RNA_def_property_ui_text(prop, "Left", "Number of pixels to crop from the left side"); RNA_def_property_ui_range(prop, 0, 4096, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceCrop_update"); - prop = RNA_def_property(srna, "max_x", PROP_INT, PROP_UNSIGNED); + prop = RNA_def_property(srna, "max_x", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "right"); RNA_def_property_ui_text(prop, "Right", "Number of pixels to crop from the right side"); RNA_def_property_ui_range(prop, 0, 4096, 1, -1); @@ -1225,14 +1227,14 @@ static void rna_def_strip_transform(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Sequence Transform", "Transform parameters for a sequence strip"); RNA_def_struct_sdna(srna, "StripTransform"); - prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "xofs"); RNA_def_property_ui_text( prop, "Offset X", "Amount to move the input on the X axis within its boundaries"); RNA_def_property_ui_range(prop, -4096, 4096, 1, -1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); - prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "yofs"); RNA_def_property_ui_text( prop, "Offset Y", "Amount to move the input on the Y axis within its boundaries"); diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 06c968534cc..4aa87055e1b 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -185,7 +185,8 @@ static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRN } # define RNA_FX_OBJECT_SET(_type, _prop, _obtype) \ - static void rna_##_type##ShaderFx_##_prop##_set(PointerRNA *ptr, PointerRNA value) \ + static void rna_##_type##ShaderFx_##_prop##_set( \ + PointerRNA *ptr, PointerRNA value, struct ReportList *UNUSED(reports)) \ { \ _type##ShaderFxData *tmd = (_type##ShaderFxData *)ptr->data; \ shaderfx_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index b6486d7a3f4..f4fba02efe5 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -463,7 +463,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem smoke_cache_comp_items[] = { - {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Light", "Fast but not so effective compression"}, + {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"}, {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 633164238e0..3e8b4274042 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -346,15 +346,15 @@ const EnumPropertyItem rna_enum_shading_type_items[] = { }; static const EnumPropertyItem rna_enum_viewport_lighting_items[] = { - {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"}, - {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"}, {V3D_LIGHTING_MATCAP, "MATCAP", 0, "MatCap", "Display using matcap material and lighting"}, + {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"}, + {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem rna_enum_shading_color_type_items[] = { - {V3D_SHADING_SINGLE_COLOR, "SINGLE", 0, "Single", "Show scene in a single color"}, {V3D_SHADING_MATERIAL_COLOR, "MATERIAL", 0, "Material", "Show material color"}, + {V3D_SHADING_SINGLE_COLOR, "SINGLE", 0, "Single", "Show scene in a single color"}, {V3D_SHADING_OBJECT_COLOR, "OBJECT", 0, "Object", "Show object color"}, {V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"}, {V3D_SHADING_VERTEX_COLOR, "VERTEX", 0, "Vertex", "Show active vertex color"}, @@ -633,7 +633,7 @@ static void rna_Space_show_region_header_set(PointerRNA *ptr, bool value) ScrArea *sa = rna_area_from_space(ptr); ARegion *ar_tool_header = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER); if (ar_tool_header != NULL) { - value = !(ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER); + value_for_tool_header = !(ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER); } } rna_Space_bool_from_region_flag_set_by_type( @@ -644,6 +644,20 @@ static void rna_Space_show_region_header_update(bContext *C, PointerRNA *ptr) rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_HEADER, RGN_FLAG_HIDDEN); } +/* Footer Region. */ +static bool rna_Space_show_region_footer_get(PointerRNA *ptr) +{ + return !rna_Space_bool_from_region_flag_get_by_type(ptr, RGN_TYPE_FOOTER, RGN_FLAG_HIDDEN); +} +static void rna_Space_show_region_footer_set(PointerRNA *ptr, bool value) +{ + rna_Space_bool_from_region_flag_set_by_type(ptr, RGN_TYPE_FOOTER, RGN_FLAG_HIDDEN, !value); +} +static void rna_Space_show_region_footer_update(bContext *C, PointerRNA *ptr) +{ + rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_FOOTER, RGN_FLAG_HIDDEN); +} + /* Tool Header Region. * * This depends on the 'RGN_TYPE_TOOL_HEADER' @@ -1069,10 +1083,10 @@ static const EnumPropertyItem *rna_View3DShading_color_type_itemf(bContext *UNUS if (shading->type == OB_SOLID) { RNA_enum_items_add_value( - &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR); - RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_MATERIAL_COLOR); RNA_enum_items_add_value( + &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR); + RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_OBJECT_COLOR); RNA_enum_items_add_value( &item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_RANDOM_COLOR); @@ -1315,7 +1329,9 @@ static bool rna_SpaceImageEditor_show_maskedit_get(PointerRNA *ptr) return ED_space_image_check_show_maskedit(sima, view_layer); } -static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceImage *sima = (SpaceImage *)(ptr->data); bScreen *sc = (bScreen *)ptr->id.data; @@ -1327,7 +1343,9 @@ static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value) ED_space_image_set(G_MAIN, sima, obedit, (Image *)value.data, false); } -static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceImage *sima = (SpaceImage *)(ptr->data); @@ -1493,7 +1511,9 @@ static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, bool value) st->left = 0; } -static void rna_SpaceTextEditor_text_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceTextEditor_text_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceText *st = (SpaceText *)(ptr->data); @@ -1515,7 +1535,9 @@ static void rna_SpaceTextEditor_updateEdited(Main *UNUSED(bmain), /* Space Properties */ /* note: this function exists only to avoid id refcounting */ -static void rna_SpaceProperties_pin_id_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceProperties_pin_id_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceProperties *sbuts = (SpaceProperties *)(ptr->data); sbuts->pinid = value.data; @@ -1717,7 +1739,9 @@ static void rna_ConsoleLine_cursor_index_range( /* Space Dopesheet */ -static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceAction *saction = (SpaceAction *)(ptr->data); bAction *act = (bAction *)value.data; @@ -1939,7 +1963,9 @@ static void rna_Sequencer_view_type_update(Main *UNUSED(bmain), /* Space Node Editor */ -static void rna_SpaceNodeEditor_node_tree_set(PointerRNA *ptr, const PointerRNA value) +static void rna_SpaceNodeEditor_node_tree_set(PointerRNA *ptr, + const PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceNode *snode = (SpaceNode *)ptr->data; ED_node_tree_start(snode, (bNodeTree *)value.data, NULL, NULL); @@ -2050,7 +2076,9 @@ static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode, snode->cursor[1] /= UI_DPI_FAC; } -static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceClip *sc = (SpaceClip *)(ptr->data); bScreen *screen = (bScreen *)ptr->id.data; @@ -2058,7 +2086,9 @@ static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr, PointerRNA value) ED_space_clip_set_clip(NULL, screen, sc, (MovieClip *)value.data); } -static void rna_SpaceClipEditor_mask_set(PointerRNA *ptr, PointerRNA value) +static void rna_SpaceClipEditor_mask_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { SpaceClip *sc = (SpaceClip *)(ptr->data); @@ -2454,12 +2484,16 @@ static void rna_def_space_generic_show_region_toggles(StructRNA *srna, int regio if (region_type_mask & (1 << RGN_TYPE_TOOL_HEADER)) { region_type_mask &= ~(1 << RGN_TYPE_TOOL_HEADER); - DEF_SHOW_REGION_PROPERTY(show_region_tool_header, "Tool Header", ""); + DEF_SHOW_REGION_PROPERTY(show_region_tool_header, "Tool Settings", ""); } if (region_type_mask & (1 << RGN_TYPE_HEADER)) { region_type_mask &= ~(1 << RGN_TYPE_HEADER); DEF_SHOW_REGION_PROPERTY(show_region_header, "Header", ""); } + if (region_type_mask & (1 << RGN_TYPE_FOOTER)) { + region_type_mask &= ~(1 << RGN_TYPE_FOOTER); + DEF_SHOW_REGION_PROPERTY(show_region_footer, "Footer", ""); + } if (region_type_mask & (1 << RGN_TYPE_TOOLS)) { region_type_mask &= ~(1 << RGN_TYPE_TOOLS); DEF_SHOW_REGION_PROPERTY(show_region_toolbar, "Toolbar", ""); @@ -2608,7 +2642,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) prop = RNA_def_property(srna, "edge_display_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "dt_uv"); RNA_def_property_enum_items(prop, dt_uv_items); - RNA_def_property_ui_text(prop, "Edge Display Type", "Display type for drawing UV edges"); + RNA_def_property_ui_text(prop, "Display As", "Display style for UV edges"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); prop = RNA_def_property(srna, "show_smooth_edges", PROP_BOOLEAN, PROP_NONE); @@ -2750,25 +2784,60 @@ static void rna_def_space_outliner(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_CASE_SENSITIVE); RNA_def_property_ui_text( prop, "Case Sensitive Matches Only", "Only use case sensitive matches of search string"); - RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_filter_complete", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE); RNA_def_property_ui_text( prop, "Complete Matches Only", "Only use complete matches of search string"); - RNA_def_property_ui_icon(prop, ICON_OUTLINER_DATA_FONT, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA); RNA_def_property_ui_text(prop, "Sort Alphabetically", ""); - RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); - prop = RNA_def_property(srna, "show_restrict_columns", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_HIDE_RESTRICTCOLS); - RNA_def_property_ui_text(prop, "Show Restriction Columns", "Show column"); + /* Granular restriction column option. */ + prop = RNA_def_property(srna, "show_restrict_column_enable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_ENABLE); + RNA_def_property_ui_text(prop, "Exclude from View Layer", "Exclude from view layer"); + RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_SELECT); + RNA_def_property_ui_text(prop, "Selectable", "Selectable"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_hide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_HIDE); + RNA_def_property_ui_text(prop, "Hide in Viewport", "Temporarily hide in viewport"); + RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_VIEWPORT); + RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_RENDER); + RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_holdout", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_HOLDOUT); + RNA_def_property_ui_text(prop, "Holdout", "Holdout"); + RNA_def_property_ui_icon(prop, ICON_HOLDOUT_ON, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + prop = RNA_def_property(srna, "show_restrict_column_indirect_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_INDIRECT_ONLY); + RNA_def_property_ui_text(prop, "Indirect Only", "Indirect only"); + RNA_def_property_ui_icon(prop, ICON_INDIRECT_ONLY_ON, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); /* Filters. */ @@ -3275,7 +3344,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development balls and palette"); + RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development spheres and palette"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE); @@ -4473,7 +4542,7 @@ static void rna_def_space_text(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceText"); RNA_def_struct_ui_text(srna, "Space Text Editor", "Text editor space data"); - rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI)); + rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_FOOTER)); /* text */ prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE); @@ -5146,7 +5215,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) "Show/hide Paint Curve data-blocks"}, {FILTER_ID_LP, "LIGHT_PROBE", - ICON_LIGHTPROBE_CUBEMAP, + ICON_OUTLINER_DATA_LIGHTPROBE, "Light Probes", "Show/hide Light Probe data-blocks"}, {FILTER_ID_SCE, "SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide Scene data-blocks"}, diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index 58a9429e528..52a197240da 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -50,7 +50,7 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C) ViewLayer *view_layer = WM_window_get_active_view_layer(win); Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL, false); break; } } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 1fbdac9df38..d08f7bc6035 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -144,7 +144,9 @@ static PointerRNA rna_tracking_active_track_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingTrack, act_track); } -static void rna_tracking_active_track_set(PointerRNA *ptr, PointerRNA value) +static void rna_tracking_active_track_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingTrack *track = (MovieTrackingTrack *)value.data; @@ -165,7 +167,9 @@ static PointerRNA rna_tracking_active_plane_track_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingPlaneTrack, act_plane_track); } -static void rna_tracking_active_plane_track_set(PointerRNA *ptr, PointerRNA value) +static void rna_tracking_active_plane_track_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)value.data; @@ -476,7 +480,9 @@ static PointerRNA rna_tracking_active_object_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingObject, object); } -static void rna_tracking_active_object_set(PointerRNA *ptr, PointerRNA value) +static void rna_tracking_active_object_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingObject *object = (MovieTrackingObject *)value.data; diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index faa16f4f146..0dbafbde71c 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -317,19 +317,21 @@ static StructRNA *rna_Panel_register(Main *bmain, pt->draw_header = (have_function[2]) ? panel_draw_header : NULL; pt->draw_header_preset = (have_function[3]) ? panel_draw_header_preset : NULL; - /* XXX use "no header" flag for some ordering of panels until we have real panel ordering */ - if (pt->flag & PNL_NO_HEADER) { - PanelType *pth = art->paneltypes.first; - while (pth && pth->flag & PNL_NO_HEADER) - pth = pth->next; - - if (pth) - BLI_insertlinkbefore(&art->paneltypes, pth, pt); - else - BLI_addtail(&art->paneltypes, pt); + /* Find position to insert panel based on order. */ + PanelType *pt_iter = art->paneltypes.last; + + for (; pt_iter; pt_iter = pt_iter->prev) { + /* No header has priority. */ + if ((pt->flag & PNL_NO_HEADER) && !(pt_iter->flag & PNL_NO_HEADER)) { + continue; + } + if (pt_iter->order <= pt->order) { + break; + } } - else - BLI_addtail(&art->paneltypes, pt); + + /* Insert into list. */ + BLI_insertlinkafter(&art->paneltypes, pt_iter, pt); if (parent) { pt->parent = parent; @@ -1347,6 +1349,14 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text(prop, "Units X", "When set, defines popup panel width"); + prop = RNA_def_property(srna, "bl_order", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "type->order"); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_ui_text( + prop, + "Order", + "Panels with lower numbers are default ordered before panels with higher numbers"); + prop = RNA_def_property(srna, "use_pin", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PNL_PIN); RNA_def_property_ui_text(prop, "Pin", ""); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 7ce9155e3d9..d50f97e88ca 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -95,13 +95,14 @@ static void rna_uiItemR(uiLayout *layout, int icon, bool expand, bool slider, - bool toggle, + int toggle, bool icon_only, bool event, bool full_event, bool emboss, int index, - int icon_value) + int icon_value, + bool invert_checkbox) { PropertyRNA *prop = RNA_struct_find_property(ptr, propname); int flag = 0; @@ -120,11 +121,17 @@ static void rna_uiItemR(uiLayout *layout, flag |= (slider) ? UI_ITEM_R_SLIDER : 0; flag |= (expand) ? UI_ITEM_R_EXPAND : 0; - flag |= (toggle) ? UI_ITEM_R_TOGGLE : 0; + if (toggle == 1) { + flag |= UI_ITEM_R_TOGGLE; + } + else if (toggle == 0) { + flag |= UI_ITEM_R_ICON_NEVER; + } flag |= (icon_only) ? UI_ITEM_R_ICON_ONLY : 0; flag |= (event) ? UI_ITEM_R_EVENT : 0; flag |= (full_event) ? UI_ITEM_R_FULL_EVENT : 0; flag |= (emboss) ? 0 : UI_ITEM_R_NO_BG; + flag |= (invert_checkbox) ? UI_ITEM_R_CHECKBOX_INVERT : 0; uiItemFullR(layout, ptr, prop, index, 0, flag, name, icon); } @@ -771,7 +778,17 @@ void RNA_api_ui_layout(StructRNA *srna) api_ui_item_common(func); RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail"); RNA_def_boolean(func, "slider", false, "", "Use slider widget for numeric values"); - RNA_def_boolean(func, "toggle", false, "", "Use toggle widget for boolean values"); + RNA_def_int(func, + "toggle", + -1, + -1, + 1, + "", + "Use toggle widget for boolean values, " + "or a checkbox when disabled " + "(the default is -1 which uses toggle only when an icon is displayed)", + -1, + 1); RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text"); RNA_def_boolean(func, "event", false, "", "Use button to input key events"); RNA_def_boolean( @@ -789,6 +806,7 @@ void RNA_api_ui_layout(StructRNA *srna) INT_MAX); /* RNA_NO_INDEX == -1 */ parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item"); + RNA_def_boolean(func, "invert_checkbox", false, "", "Draw checkbox value inverted"); func = RNA_def_function(srna, "props_enum", "uiItemsEnumR"); api_ui_item_rna_common(func); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index eade12be631..1f48e19d09a 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -42,6 +42,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "UI_interface_icons.h" + #include "rna_internal.h" #include "WM_api.h" @@ -99,6 +101,45 @@ static const EnumPropertyItem rna_enum_studio_light_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { + {SCE_DISPLAY_AA_OFF, + "OFF", + 0, + "No Anti-Aliasing", + "Scene will be rendering without any anti-aliasing"}, + {SCE_DISPLAY_AA_FXAA, + "FXAA", + 0, + "Single Pass Anti-Aliasing", + "Scene will be rendered using a single pass anti-aliasing method (FXAA)"}, + {SCE_DISPLAY_AA_SAMPLES_5, + "5", + 0, + "5 Samples", + "Scene will be rendered using 5 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_8, + "8", + 0, + "8 Samples", + "Scene will be rendered using 8 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_11, + "11", + 0, + "11 Samples", + "Scene will be rendered using 11 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_16, + "16", + 0, + "16 Samples", + "Scene will be rendered using 16 anti-aliasing samples"}, + {SCE_DISPLAY_AA_SAMPLES_32, + "32", + 0, + "32 Samples", + "Scene will be rendered using 32 anti-aliasing samples"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "BLI_math_vector.h" @@ -143,9 +184,42 @@ static void rna_userdef_version_get(PointerRNA *ptr, int *value) value[2] = userdef->subversionfile; } +# define USERDEF_TAG_DIRTY rna_userdef_is_dirty_update_impl() + +/* Use single function so we can more easily breakpoint it. */ +void rna_userdef_is_dirty_update_impl(void) +{ + /* We can't use 'ptr->data' because this update function + * is used for themes and other nested data. */ + if (U.runtime.is_dirty == false) { + U.runtime.is_dirty = true; + WM_main_add_notifier(NC_WINDOW, NULL); + } +} + +/** + * Use as a fallback update handler, + * never use 'ptr' unless it's type is checked. + */ +void rna_userdef_is_dirty_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *UNUSED(ptr)) +{ + rna_userdef_is_dirty_update_impl(); +} + +/** Take care not to use this if we expet 'is_dirty' to be tagged. */ +static void rna_userdef_ui_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *UNUSED(ptr)) +{ + WM_main_add_notifier(NC_WINDOW, NULL); +} + static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { WM_main_add_notifier(NC_WINDOW, NULL); + USERDEF_TAG_DIRTY; } static void rna_userdef_theme_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -156,6 +230,12 @@ static void rna_userdef_theme_update(Main *bmain, Scene *scene, PointerRNA *ptr) rna_userdef_update(bmain, scene, ptr); } +static void rna_userdef_theme_update_icons(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + UI_icons_reload_internal_textures(); + rna_userdef_theme_update(bmain, scene, ptr); +} + /* also used by buffer swap switching */ static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), @@ -166,24 +246,27 @@ static void rna_userdef_dpi_update(Main *UNUSED(bmain), WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ + USERDEF_TAG_DIRTY; } -static void rna_userdef_update_ui(Main *UNUSED(bmain), - Scene *UNUSED(scene), - PointerRNA *UNUSED(ptr)) +static void rna_userdef_screen_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *UNUSED(ptr)) { WM_main_add_notifier(NC_WINDOW, NULL); WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */ + USERDEF_TAG_DIRTY; } -static void rna_userdef_update_ui_header_default(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_userdef_screen_update_header_default(Main *bmain, Scene *scene, PointerRNA *ptr) { if (U.uiflag & USER_HEADER_FROM_PREF) { for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { BKE_screen_header_alignment_reset(screen); } - rna_userdef_update_ui(bmain, scene, ptr); + rna_userdef_screen_update(bmain, scene, ptr); } + USERDEF_TAG_DIRTY; } static void rna_userdef_language_update(Main *UNUSED(bmain), @@ -193,6 +276,7 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), BLF_cache_clear(); BLT_lang_set(NULL); UI_reinit_font(); + USERDEF_TAG_DIRTY; } static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), @@ -204,6 +288,8 @@ static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; else G.f |= G_FLAG_SCRIPT_AUTOEXEC; + + USERDEF_TAG_DIRTY; } static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -213,6 +299,8 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene) G.fileflags |= G_FILE_NO_UI; else G.fileflags &= ~G_FILE_NO_UI; + + USERDEF_TAG_DIRTY; } static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -265,6 +353,7 @@ static void rna_userdef_tablet_api_update(Main *UNUSED(bmain), PointerRNA *UNUSED(ptr)) { WM_init_tablet_api(); + USERDEF_TAG_DIRTY; } # ifdef WITH_INPUT_NDOF @@ -274,6 +363,7 @@ static void rna_userdef_ndof_deadzone_update(Main *UNUSED(bmain), { UserDef *userdef = ptr->data; WM_ndof_deadzone_set(userdef->ndof_deadzone); + USERDEF_TAG_DIRTY; } # endif @@ -283,6 +373,7 @@ static void rna_userdef_keyconfig_reload_update(bContext *C, PointerRNA *UNUSED(ptr)) { WM_keyconfig_reload(C); + USERDEF_TAG_DIRTY; } static void rna_userdef_timecode_style_set(PointerRNA *ptr, int value) @@ -352,6 +443,7 @@ static PointerRNA rna_UserDef_system_get(PointerRNA *ptr) static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { BKE_sound_init(bmain); + USERDEF_TAG_DIRTY; } static void rna_Userdef_memcache_update(Main *UNUSED(bmain), @@ -359,6 +451,7 @@ static void rna_Userdef_memcache_update(Main *UNUSED(bmain), PointerRNA *UNUSED(ptr)) { MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); + USERDEF_TAG_DIRTY; } static void rna_UserDef_weight_color_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -401,6 +494,7 @@ static bAddon *rna_userdef_addon_new(void) ListBase *addons_list = &U.addons; bAddon *addon = BKE_addon_new(); BLI_addtail(addons_list, addon); + USERDEF_TAG_DIRTY; return addon; } @@ -415,12 +509,14 @@ static void rna_userdef_addon_remove(ReportList *reports, PointerRNA *addon_ptr) BLI_remlink(addons_list, addon); BKE_addon_free(addon); RNA_POINTER_INVALIDATE(addon_ptr); + USERDEF_TAG_DIRTY; } static bPathCompare *rna_userdef_pathcompare_new(void) { bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare"); BLI_addtail(&U.autoexec_paths, path_cmp); + USERDEF_TAG_DIRTY; return path_cmp; } @@ -434,6 +530,7 @@ static void rna_userdef_pathcompare_remove(ReportList *reports, PointerRNA *path BLI_freelinkN(&U.autoexec_paths, path_cmp); RNA_POINTER_INVALIDATE(path_cmp_ptr); + USERDEF_TAG_DIRTY; } static void rna_userdef_temp_update(Main *UNUSED(bmain), @@ -441,6 +538,7 @@ static void rna_userdef_temp_update(Main *UNUSED(bmain), PointerRNA *UNUSED(ptr)) { BKE_tempdir_init(U.tempdir); + USERDEF_TAG_DIRTY; } static void rna_userdef_text_update(Main *UNUSED(bmain), @@ -450,6 +548,7 @@ static void rna_userdef_text_update(Main *UNUSED(bmain), BLF_cache_clear(); UI_reinit_font(); WM_main_add_notifier(NC_WINDOW, NULL); + USERDEF_TAG_DIRTY; } static PointerRNA rna_Theme_space_generic_get(PointerRNA *ptr) @@ -516,6 +615,7 @@ static void rna_userdef_opensubdiv_update(Main *bmain, for (object = bmain->objects.first; object; object = object->id.next) { DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM); } + USERDEF_TAG_DIRTY; } # endif @@ -1338,6 +1438,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); /* Icon colors. */ + prop = RNA_def_property(srna, "icon_scene", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "icon_scene"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scene", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "icon_collection", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "icon_collection"); RNA_def_property_array(prop, 4); @@ -1367,6 +1473,13 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Shading", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "icon_border_intensity", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "icon_border_intensity"); + RNA_def_property_ui_text( + prop, "Icon Border", "Control the intensity of the border around themes icons"); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update_icons"); } static void rna_def_userdef_theme_space_common(StructRNA *srna) @@ -2065,6 +2178,11 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scrubbing/Markers Region", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "window_sliders", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "shade1"); RNA_def_property_array(prop, 3); @@ -2155,6 +2273,26 @@ static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Selected Highlight", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "selected_object", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Selected Objects", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "active_object", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Active Object", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "edited_object", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Edited Object", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); } static void rna_def_userdef_theme_space_userpref(BlenderRNA *brna) @@ -2402,8 +2540,6 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); rna_def_userdef_theme_spaces_list_main(srna); - rna_def_userdef_theme_spaces_gpencil(srna); - prop = RNA_def_property(srna, "node_selected", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "select"); RNA_def_property_array(prop, 3); @@ -2578,7 +2714,6 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Image Editor", "Theme settings for the Image Editor"); rna_def_userdef_theme_spaces_main(srna); - rna_def_userdef_theme_spaces_gpencil(srna); rna_def_userdef_theme_spaces_vertex(srna); rna_def_userdef_theme_spaces_face(srna); @@ -2687,7 +2822,6 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Sequence Editor", "Theme settings for the Sequence Editor"); rna_def_userdef_theme_spaces_main(srna); - rna_def_userdef_theme_spaces_gpencil(srna); prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -2759,6 +2893,11 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scrubbing/Markers Region", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "keyframe", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "vertex_select"); RNA_def_property_array(prop, 3); @@ -2816,6 +2955,11 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scrubbing/Markers Region", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "value_sliders", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "face"); RNA_def_property_array(prop, 3); @@ -3108,6 +3252,11 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scrubbing/Markers Region", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); } static void rna_def_userdef_theme_colorset(BlenderRNA *brna) @@ -3159,8 +3308,6 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); rna_def_userdef_theme_spaces_list_main(srna); - rna_def_userdef_theme_spaces_gpencil(srna); - prop = RNA_def_property(srna, "marker_outline", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "marker_outline"); RNA_def_property_array(prop, 3); @@ -3215,6 +3362,11 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "scrubbing_background", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Scrubbing/Markers Region", ""); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "strip"); RNA_def_property_array(prop, 3); @@ -3945,7 +4097,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_LOCK_UI_LAYOUT); RNA_def_property_ui_text( prop, "Editor Corner Splitting", "Split and join editors by dragging from corners"); - RNA_def_property_update(prop, 0, "rna_userdef_update_ui"); + RNA_def_property_update(prop, 0, "rna_userdef_screen_update"); /* menus */ prop = RNA_def_property(srna, "use_mouse_over_open", PROP_BOOLEAN, PROP_NONE); @@ -4046,7 +4198,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_enum_items(prop, header_align_items); RNA_def_property_enum_bitflag_sdna(prop, NULL, "uiflag"); RNA_def_property_ui_text(prop, "Header Position", "Default header position for new space-types"); - RNA_def_property_update(prop, 0, "rna_userdef_update_ui_header_default"); + RNA_def_property_update(prop, 0, "rna_userdef_screen_update_header_default"); static const EnumPropertyItem text_hinting_items[] = { {0, "AUTO", 0, "Auto", ""}, @@ -4108,6 +4260,15 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Gizmo Size", "Diameter of the gizmo"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* Lookdev */ + prop = RNA_def_property(srna, "lookdev_sphere_size", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "lookdev_sphere_size"); + RNA_def_property_range(prop, 50, 400); + RNA_def_property_int_default(prop, 150); + RNA_def_property_ui_text( + prop, "Look Dev Spheres Size", "Maximum diameter of the look development sphere size"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* View2D Grid Displays */ prop = RNA_def_property(srna, "view2d_grid_spacing_min", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "v2d_min_gridsize"); @@ -4238,7 +4399,12 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "VIEW", 0, "View", - "Align newly added objects facing the active 3D View direction"}, + "Align newly added objects to the active 3D View direction"}, + {USER_ADD_CURSORALIGNED, + "CURSOR", + 0, + "3D Cursor", + "Align newly added objects to the 3D Cursor's rotation"}, {0, NULL, 0, NULL, NULL}, }; @@ -4697,12 +4863,11 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop, "Region Overlap", "Draw tool/property regions over the main region"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); - prop = RNA_def_property(srna, "gpu_viewport_quality", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "gpu_viewport_quality"); - RNA_def_property_float_default(prop, 0.6f); - RNA_def_property_range(prop, 0.0f, 1.0f); + prop = RNA_def_property(srna, "viewport_aa", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_userdef_viewport_aa_items); RNA_def_property_ui_text( - prop, "Viewport Quality", "Quality setting for Solid mode rendering in the 3d viewport"); + prop, "Viewport Anti-Aliasing", "Method of anti-aliasing in 3d viewport"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop = RNA_def_property(srna, "solid_lights", PROP_COLLECTION, PROP_NONE); @@ -5447,6 +5612,8 @@ static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyR void RNA_def_userdef(BlenderRNA *brna) { + RNA_define_fallback_property_update(0, "rna_userdef_is_dirty_update"); + StructRNA *srna; PropertyRNA *prop; @@ -5490,7 +5657,7 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_enum_items(prop, preference_section_items); RNA_def_property_ui_text( prop, "Active Section", "Active section of the preferences shown in the user interface"); - RNA_def_property_update(prop, 0, "rna_userdef_update"); + RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); /* don't expose this directly via the UI, modify via an operator */ prop = RNA_def_property(srna, "app_template", PROP_STRING, PROP_NONE); @@ -5586,6 +5753,16 @@ void RNA_def_userdef(BlenderRNA *brna) NULL); RNA_def_property_ui_text(prop, "Studio Lights", ""); + /* Preferences Flags */ + prop = RNA_def_property(srna, "use_preferences_save", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "pref_flag", USER_PREF_FLAG_SAVE); + RNA_def_property_ui_text(prop, "Save on Exit", "Save modified preferences on exit"); + + prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "runtime.is_dirty", 0); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Dirty", "Preferences have changed"); + rna_def_userdef_view(brna); rna_def_userdef_edit(brna); rna_def_userdef_input(brna); @@ -5597,6 +5774,8 @@ void RNA_def_userdef(BlenderRNA *brna) rna_def_userdef_studiolights(brna); rna_def_userdef_studiolight(brna); rna_def_userdef_pathcompare(brna); + + RNA_define_fallback_property_update(0, NULL); } #endif diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 3f904df6e00..14994340ad3 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -49,6 +49,8 @@ static const EnumPropertyItem event_keymouse_value_items[] = { {KM_CLICK, "CLICK", 0, "Click", ""}, {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""}, {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""}, + /* Used for NDOF and trackpad events. */ + {KM_NOTHING, "NOTHING", 0, "Nothing", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -382,7 +384,6 @@ const EnumPropertyItem rna_enum_event_type_items[] = { const EnumPropertyItem rna_enum_event_value_items[] = { {KM_ANY, "ANY", 0, "Any", ""}, - {KM_NOTHING, "NOTHING", 0, "Nothing", ""}, {KM_PRESS, "PRESS", 0, "Press", ""}, {KM_RELEASE, "RELEASE", 0, "Release", ""}, {KM_CLICK, "CLICK", 0, "Click", ""}, @@ -396,6 +397,7 @@ const EnumPropertyItem rna_enum_event_value_items[] = { {EVT_GESTURE_SW, "SOUTH_WEST", 0, "South-West", ""}, {EVT_GESTURE_W, "WEST", 0, "West", ""}, {EVT_GESTURE_NW, "NORTH_WEST", 0, "North-West", ""}, + {KM_NOTHING, "NOTHING", 0, "Nothing", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -451,11 +453,6 @@ static const EnumPropertyItem operator_flag_items[] = { "is enabled"}, {OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"}, {OPTYPE_INTERNAL, "INTERNAL", 0, "Internal", "Removes the operator from search results"}, - {OPTYPE_USE_EVAL_DATA, - "USE_EVAL_DATA", - 0, - "Use Evaluated Data", - "Uses evaluated data (i.e. needs a valid depsgraph for current context)"}, {0, NULL, 0, NULL, NULL}, }; #endif @@ -694,7 +691,9 @@ static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr) return rptr; } -static void rna_Window_scene_set(PointerRNA *ptr, PointerRNA value) +static void rna_Window_scene_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { wmWindow *win = ptr->data; @@ -738,7 +737,9 @@ static PointerRNA rna_Window_workspace_get(PointerRNA *ptr) ptr, &RNA_WorkSpace, BKE_workspace_active_get(win->workspace_hook)); } -static void rna_Window_workspace_set(PointerRNA *ptr, PointerRNA value) +static void rna_Window_workspace_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { wmWindow *win = (wmWindow *)ptr->data; @@ -774,7 +775,9 @@ PointerRNA rna_Window_screen_get(PointerRNA *ptr) ptr, &RNA_Screen, BKE_workspace_active_screen_get(win->workspace_hook)); } -static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value) +static void rna_Window_screen_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { wmWindow *win = ptr->data; WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); @@ -824,7 +827,9 @@ static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr) return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer); } -static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value) +static void rna_Window_view_layer_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { wmWindow *win = ptr->data; ViewLayer *view_layer = value.data; @@ -1028,7 +1033,9 @@ static PointerRNA rna_WindowManager_active_keyconfig_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_KeyConfig, kc); } -static void rna_WindowManager_active_keyconfig_set(PointerRNA *ptr, PointerRNA value) +static void rna_WindowManager_active_keyconfig_set(PointerRNA *ptr, + PointerRNA value, + struct ReportList *UNUSED(reports)) { wmWindowManager *wm = ptr->data; wmKeyConfig *kc = value.data; @@ -1868,6 +1875,7 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops"); RNA_def_struct_property_tags(srna, rna_enum_operator_property_tags); RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); } static void rna_def_macro_operator(BlenderRNA *brna) @@ -2105,6 +2113,7 @@ static void rna_def_event(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "shift", 1); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Shift", "True when the Shift key is held"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER); prop = RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 1); @@ -2601,6 +2610,7 @@ static void rna_def_keyconfig(BlenderRNA *brna) /* RNA_def_property_enum_sdna(prop, NULL, "shift"); */ /* RNA_def_property_enum_items(prop, keymap_modifiers_items); */ RNA_def_property_ui_text(prop, "Shift", "Shift key pressed"); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER); RNA_def_property_update(prop, 0, "rna_KeyMapItem_update"); prop = RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index a473f97d554..22162aa017b 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -384,6 +384,7 @@ static void rna_Gizmo_matrix_world_get(PointerRNA *ptr, float value[16]) RNA_GIZMO_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis); RNA_GIZMO_GENERIC_FLOAT_RW_DEF(line_width, line_width); +RNA_GIZMO_GENERIC_FLOAT_RW_DEF(select_bias, select_bias); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_GIZMO_DRAW_HOVER); RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_modal, flag, WM_GIZMO_DRAW_MODAL); @@ -1159,6 +1160,12 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + prop = RNA_def_property(srna, "select_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_text(prop, "Select Bias", "Depth bias used for selection"); + RNA_def_property_float_funcs( + prop, "rna_Gizmo_select_bias_get", "rna_Gizmo_select_bias_set", NULL); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + /* wmGizmo.flag */ /* WM_GIZMO_HIDDEN */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 6e5426bbf40..c61ebe0448c 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -195,7 +195,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes * Annoying and not so much black-boxed as far as sculpting goes, and * surely there is a better way of solving this. */ if (ctx->object->sculpt != NULL) { - ctx->object->sculpt->subdiv_ccg = result->runtime.subdiv_ccg; + SculptSession *sculpt_session = ctx->object->sculpt; + sculpt_session->subdiv_ccg = result->runtime.subdiv_ccg; + sculpt_session->multires = mmd; + sculpt_session->totvert = mesh->totvert; + sculpt_session->totpoly = mesh->totpoly; + sculpt_session->mvert = NULL; + sculpt_session->mpoly = NULL; + sculpt_session->mloop = NULL; } /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share * this pointer. Not sure if it's needed, but might have a second look diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 7fbaa24b579..0accbe607eb 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -35,6 +35,8 @@ #include "MOD_modifiertypes.h" #include "MOD_util.h" +#include "bmesh.h" + #define CLNORS_VALID_VEC_LEN (1e-6f) typedef struct ModePair { diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h index 916cb81953e..a3c553b983b 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.h @@ -60,13 +60,13 @@ #include "BLT_translation.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" #include "RE_pipeline.h" #include "RE_shader_ext.h" #include "GPU_material.h" +#include "GPU_texture.h" #include "GPU_uniformbuffer.h" bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index 37c35c0adc8..6c3e082f36a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -39,6 +39,8 @@ static bNodeSocketTemplate sh_node_bsdf_principled_in[] = { {SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, {SOCK_FLOAT, 1, N_("Transmission"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, {SOCK_FLOAT, 1, N_("Transmission Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + {SOCK_RGBA, 1, N_("Emission"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + {SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, {SOCK_VECTOR, 1, N_("Normal"), @@ -99,26 +101,25 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, GPUNodeLink *sss_scale; /* Normals */ - if (!in[17].link) { - GPU_link(mat, "world_normals_get", &in[17].link); + if (!in[19].link) { + GPU_link(mat, "world_normals_get", &in[19].link); } /* Clearcoat Normals */ - if (!in[18].link) { - GPU_link(mat, "world_normals_get", &in[18].link); + if (!in[20].link) { + GPU_link(mat, "world_normals_get", &in[20].link); } /* Tangents */ - if (!in[19].link) { + if (!in[21].link) { GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); - GPU_link(mat, "tangent_orco_z", orco, &in[19].link); + GPU_link(mat, "tangent_orco_z", orco, &in[21].link); GPU_link(mat, "node_tangent", - GPU_builtin(GPU_VIEW_NORMAL), - in[19].link, + GPU_builtin(GPU_WORLD_NORMAL), + in[21].link, GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &in[19].link); + &in[21].link); } /* SSS Profile */ diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c index 6f97efe9f73..df9a8ac8318 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c @@ -51,7 +51,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, in, out, GPU_builtin(GPU_VIEW_POSITION), - GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_WORLD_NORMAL), GPU_attribute(CD_ORCO, ""), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index d769a219fa0..4976d038065 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -84,52 +84,33 @@ static int gpu_shader_normal_map(GPUMaterial *mat, realnorm = GPU_constant(in[1].vec); } - negnorm = GPU_builtin(GPU_VIEW_NORMAL); + negnorm = GPU_builtin(GPU_WORLD_NORMAL); GPU_link(mat, "math_max", strength, GPU_constant(d), &strength); const char *color_to_normal_fnc_name = "color_to_normal_new_shading"; if (nm->space == SHD_SPACE_BLENDER_OBJECT || nm->space == SHD_SPACE_BLENDER_WORLD) { color_to_normal_fnc_name = "color_to_blender_normal_new_shading"; } + + GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); switch (nm->space) { case SHD_SPACE_TANGENT: - GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); GPU_link(mat, "node_normal_map", GPU_builtin(GPU_OBJECT_INFO), GPU_attribute(CD_TANGENT, nm->uv_map), - negnorm, + GPU_builtin(GPU_WORLD_NORMAL), realnorm, &realnorm); - GPU_link( - mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link); - /* for uniform scale this is sufficient to match Cycles */ - GPU_link(mat, - "direction_transform_m4v3", - out[0].link, - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &out[0].link); - GPU_link(mat, "vect_normalize", out[0].link, &out[0].link); - return true; + break; case SHD_SPACE_OBJECT: case SHD_SPACE_BLENDER_OBJECT: - GPU_link(mat, - "direction_transform_m4v3", - negnorm, - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &negnorm); - GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); GPU_link( mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); break; case SHD_SPACE_WORLD: case SHD_SPACE_BLENDER_WORLD: - GPU_link(mat, - "direction_transform_m4v3", - negnorm, - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - &negnorm); - GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); + /* Nothing to do. */ break; } diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c index 5520f6f325f..118b8136693 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c @@ -35,13 +35,17 @@ static int node_shader_gpu_object_info(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { + Material *ma = GPU_material_get_material(mat); + /* Convert to float. */ + float index = ma ? ma->index : 0; return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_OBJECT_INFO)); + GPU_builtin(GPU_OBJECT_INFO), + GPU_constant(&index)); } static void node_shader_exec_object_info(void *UNUSED(data), diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.c index 5512754d9a2..6795f48edb3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tangent.c +++ b/source/blender/nodes/shader/nodes/node_shader_tangent.c @@ -42,13 +42,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, NodeShaderTangent *attr = node->storage; if (attr->direction_type == SHD_TANGENT_UVMAP) { - return GPU_stack_link(mat, - node, - "node_tangentmap", - in, - out, - GPU_attribute(CD_TANGENT, ""), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX)); + return GPU_stack_link(mat, node, "node_tangentmap", in, out, GPU_attribute(CD_TANGENT, "")); } else { GPUNodeLink *orco = GPU_attribute(CD_ORCO, ""); @@ -68,10 +62,9 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, "node_tangent", in, out, - GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_WORLD_NORMAL), orco, - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX)); + GPU_builtin(GPU_OBJECT_MATRIX)); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index fd62e8ce960..0e34f2ca9b1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -42,10 +42,6 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, { Object *ob = (Object *)node->id; - if (ob != NULL) { - invert_m4_m4(ob->imat, ob->obmat); - } - GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) : GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); @@ -60,8 +56,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, in, out, GPU_builtin(GPU_VIEW_POSITION), - GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), + GPU_builtin(GPU_WORLD_NORMAL), inv_obmat, GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index c3b8bc8bfd0..615f55e4350 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -46,7 +46,6 @@ static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *no NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); - tex->color_space = SHD_COLORSPACE_COLOR; tex->projection = SHD_PROJ_EQUIRECTANGULAR; BKE_imageuser_default(&tex->iuser); @@ -68,7 +67,6 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, NodeTexImage *tex_original = node_original->storage; ImageUser *iuser = &tex_original->iuser; - int isdata = tex->color_space == SHD_COLORSPACE_NONE; GPUNodeLink *outalpha; if (!ima) { @@ -89,7 +87,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, "node_tex_environment_equirectangular", in[0].link, GPU_constant(&clamp_size), - GPU_image(ima, iuser, isdata), + GPU_image(ima, iuser), &in[0].link); } else { @@ -104,7 +102,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, GPU_link(mat, "node_tex_image_linear_no_mip", in[0].link, - GPU_image(ima, iuser, isdata), + GPU_image(ima, iuser), &out[0].link, &outalpha); break; @@ -112,26 +110,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, GPU_link(mat, "node_tex_image_nearest", in[0].link, - GPU_image(ima, iuser, isdata), + GPU_image(ima, iuser), &out[0].link, &outalpha); break; default: - GPU_link(mat, - "node_tex_image_cubic", - in[0].link, - GPU_image(ima, iuser, isdata), - &out[0].link, - &outalpha); + GPU_link( + mat, "node_tex_image_cubic", in[0].link, GPU_image(ima, iuser), &out[0].link, &outalpha); break; } - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && - GPU_material_do_color_management(mat)) { - GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link); + if (out[0].hasoutput) { + GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link); } - BKE_image_release_ibuf(ima, ibuf, NULL); return true; } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index 91d58bc41d0..786386bb63e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -57,7 +57,6 @@ static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node) NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); - tex->color_space = SHD_COLORSPACE_COLOR; BKE_imageuser_default(&tex->iuser); node->storage = tex; @@ -99,7 +98,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX) ? names_box[tex->interpolation] : names[tex->interpolation]; - bool do_color_correction = false; bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT); const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP); @@ -111,23 +109,13 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, } GPUNodeLink *norm, *col1, *col2, *col3, *input_coords, *gpu_image; - GPUNodeLink *vnor, *nor_mat_inv, *blend; + GPUNodeLink *vnor, *ob_mat, *blend; GPUNodeLink **texco = &in[0].link; - int isdata = tex->color_space == SHD_COLORSPACE_NONE; - if (!ima) { return GPU_stack_link(mat, node, "node_tex_image_empty", in, out); } - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - if ((tex->color_space == SHD_COLORSPACE_COLOR) && ibuf && - (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && - GPU_material_do_color_management(mat)) { - do_color_correction = true; - } - BKE_image_release_ibuf(ima, ibuf, NULL); - if (!*texco) { *texco = GPU_attribute(CD_MTFACE, ""); } @@ -140,25 +128,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, GPU_link(mat, "set_rgb", *texco, &input_coords); } if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco); + GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco); } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata)); + GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser)); break; case SHD_PROJ_BOX: - vnor = GPU_builtin(GPU_VIEW_NORMAL); - nor_mat_inv = GPU_builtin(GPU_INVERSE_NORMAL_MATRIX); + vnor = GPU_builtin(GPU_WORLD_NORMAL); + ob_mat = GPU_builtin(GPU_OBJECT_MATRIX); blend = GPU_uniform(&tex->projection_blend); - gpu_image = GPU_image(ima, iuser, isdata); - - GPU_link(mat, "mat3_mul", vnor, nor_mat_inv, &norm); - GPU_link( - mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser, isdata), &col1, &col2, &col3); - if (do_color_correction) { - GPU_link(mat, "srgb_to_linearrgb", col1, &col1); - GPU_link(mat, "srgb_to_linearrgb", col2, &col2); - GPU_link(mat, "srgb_to_linearrgb", col3, &col3); - } + gpu_image = GPU_image(ima, iuser); + + /* equivalent to normal_world_to_object */ + GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm); + GPU_link(mat, gpu_node_name, *texco, norm, GPU_image(ima, iuser), &col1, &col2, &col3); GPU_stack_link( mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend); break; @@ -170,9 +153,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, GPU_link(mat, "set_rgb", *texco, &input_coords); } if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco); + GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco); } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata)); + GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser)); break; case SHD_PROJ_TUBE: @@ -182,20 +165,31 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, GPU_link(mat, "set_rgb", *texco, &input_coords); } if (do_texco_extend) { - GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser, isdata), texco); + GPU_link(mat, "point_texco_clamp", *texco, GPU_image(ima, iuser), texco); } - GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata)); + GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser)); break; } if (tex->projection != SHD_PROJ_BOX) { if (do_texco_clip) { gpu_node_name = names_clip[tex->interpolation]; - GPU_stack_link( - mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata), out[0].link); + in[0].link = input_coords; + GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser), out[0].link); + } + } + + if (out[0].hasoutput) { + /* When the alpha socket is used, unpremultiply alpha. This makes it so + * that if we blend the color with a transparent shader using alpha as + * a factor, we don't multiply alpha into the color twice. */ + if (out[1].hasoutput && + !(ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || + IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name))) { + GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link); } - if (do_color_correction) { - GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link); + else { + GPU_link(mat, "tex_color_alpha_clear", out[0].link, &out[0].link); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c index cbc012040b0..ac8b49c4572 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c @@ -61,7 +61,7 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, in, out, GPU_attribute(CD_TANGENT, ""), - GPU_builtin(GPU_VIEW_NORMAL), + GPU_builtin(GPU_WORLD_NORMAL), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_VIEW_MATRIX)); } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index dd5baaa661c..30cad991b55 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -601,7 +601,6 @@ static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob) pval = PySequence_GetItem(vals, i); if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) { IDP_FreeProperty(prop); - MEM_freeN(prop); Py_XDECREF(keys); Py_XDECREF(vals); Py_XDECREF(key); @@ -690,7 +689,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, prop->prev = prop_exist->prev; prop->next = prop_exist->next; - IDP_FreeProperty(prop_exist); + IDP_FreePropertyContent(prop_exist); *prop_exist = *prop; MEM_freeN(prop); } diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 5ea747b5cdc..561aff41000 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -256,7 +256,6 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, false, true, "", - NULL, true, self->ofs, NULL); diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 7134bf520ac..dde3d026d47 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -61,6 +61,7 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(char *)"depsgraph_update_pre", (char *)"on depsgraph update (pre)"}, {(char *)"depsgraph_update_post", (char *)"on depsgraph update (post)"}, {(char *)"version_update", (char *)"on ending the versioning code"}, + {(char *)"load_factory_preferences_post", (char *)"on loading factory preferences (after)"}, {(char *)"load_factory_startup_post", (char *)"on loading factory startup (after)"}, /* sets the permanent tag */ diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index a87deeabc65..092c9061bb7 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1122,7 +1122,6 @@ static void pyrna_struct_dealloc(BPy_StructRNA *self) #ifdef PYRNA_FREE_SUPPORT if (self->freeptr && self->ptr.data) { IDP_FreeProperty(self->ptr.data); - MEM_freeN(self->ptr.data); self->ptr.data = NULL; } #endif /* PYRNA_FREE_SUPPORT */ @@ -2030,7 +2029,15 @@ static int pyrna_py_to_prop( else { /* data == NULL, assign to RNA */ if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type)) { - RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr); + ReportList reports; + BKE_reports_init(&reports, RPT_STORE); + RNA_property_pointer_set( + ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr, &reports); + int err = (BPy_reports_to_error(&reports, PyExc_RuntimeError, true)); + if (err == -1) { + Py_XDECREF(value_new); + return -1; + } } else { raise_error = true; diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 79c31c8caad..710ae0433e0 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -263,8 +263,9 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, /* flag may be null (no option currently for remove keyframes e.g.). */ if (r_options) { - if (pyoptions && (pyrna_set_to_enum_bitfield( - rna_enum_keying_flag_items, pyoptions, r_options, error_prefix) == -1)) { + if (pyoptions && + (pyrna_set_to_enum_bitfield( + rna_enum_keying_flag_items_api, pyoptions, r_options, error_prefix) == -1)) { return -1; } @@ -299,8 +300,11 @@ char pyrna_struct_keyframe_insert_doc[] = "F-Curves.\n" " - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n" " - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, " - "Rotation, Scale)\n" - " and also Color is based on the transform axis.\n" + "Rotation, Scale) is based on the transform axis.\n" + " - ``INSERTKEY_REPLACE`` Only replace already exising keyframes.\n" + " - ``INSERTKEY_AVAILABLE`` Only insert into already existing F-Curves.\n" + " - ``INSERTKEY_CYCLE_AWARE`` Take cyclic extrapolation into account " + "(Cycle-Aware Keying option).\n" " :type flag: set\n" " :return: Success of keyframe insertion.\n" " :rtype: boolean\n"; diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 7cc9ba50d90..2e664616639 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -585,6 +585,34 @@ static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value) return Matrix_CreatePyObject(&mat[0][0], 4, 4, (PyTypeObject *)cls); } +/* ----------------------------------mathutils.Matrix.Diagonal() ------------- */ +PyDoc_STRVAR(C_Matrix_Diagonal_doc, + ".. classmethod:: Diagonal(vector)\n" + "\n" + " Create a diagonal (scaling) matrix using the values from the vector.\n" + "\n" + " :arg vector: The vector of values for the diagonal.\n" + " :type vector: :class:`Vector`\n" + " :return: A diagonal matrix.\n" + " :rtype: :class:`Matrix`\n"); +static PyObject *C_Matrix_Diagonal(PyObject *cls, PyObject *value) +{ + float mat[16] = {0.0f}; + float vec[4]; + + int size = mathutils_array_parse( + vec, 2, 4, value, "mathutils.Matrix.Diagonal(vector), invalid vector arg"); + + if (size == -1) { + return NULL; + } + + for (int i = 0; i < size; i++) { + mat[size * i + i] = vec[i]; + } + + return Matrix_CreatePyObject(mat, size, size, (PyTypeObject *)cls); +} /* ----------------------------------mathutils.Matrix.Scale() ------------- */ /* mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. */ PyDoc_STRVAR(C_Matrix_Scale_doc, @@ -3085,6 +3113,7 @@ static struct PyMethodDef Matrix_methods[] = { {"Rotation", (PyCFunction)C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc}, {"Scale", (PyCFunction)C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc}, {"Shear", (PyCFunction)C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc}, + {"Diagonal", (PyCFunction)C_Matrix_Diagonal, METH_O | METH_CLASS, C_Matrix_Diagonal_doc}, {"Translation", (PyCFunction)C_Matrix_Translation, METH_O | METH_CLASS, diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 1092ab553e9..4f51f9874f8 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -93,8 +93,12 @@ typedef struct RenderEngineType { const int depth, void *result); - void (*view_update)(struct RenderEngine *engine, const struct bContext *context); - void (*view_draw)(struct RenderEngine *engine, const struct bContext *context); + void (*view_update)(struct RenderEngine *engine, + const struct bContext *context, + struct Depsgraph *depsgraph); + void (*view_draw)(struct RenderEngine *engine, + const struct bContext *context, + struct Depsgraph *depsgraph); void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 46d2df0acb5..db051d58d6c 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -284,21 +284,21 @@ bool RE_WriteRenderViewsMovie(struct ReportList *reports, bool preview); /* only RE_NewRender() needed, main Blender render calls */ -void RE_BlenderFrame(struct Render *re, - struct Main *bmain, - struct Scene *scene, - struct ViewLayer *single_layer, - struct Object *camera_override, - int frame, - const bool write_still); -void RE_BlenderAnim(struct Render *re, +void RE_RenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct ViewLayer *single_layer, struct Object *camera_override, - int sfra, - int efra, - int tfra); + int frame, + const bool write_still); +void RE_RenderAnim(struct Render *re, + struct Main *bmain, + struct Scene *scene, + struct ViewLayer *single_layer, + struct Object *camera_override, + int sfra, + int efra, + int tfra); #ifdef WITH_FREESTYLE void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, @@ -307,6 +307,9 @@ void RE_RenderFreestyleStrokes(struct Render *re, void RE_RenderFreestyleExternal(struct Render *re); #endif +/* Free memory and clear runtime data which is only needed during rendering. */ +void RE_CleanAfterRender(struct Render *re); + void RE_SetActiveRenderView(struct Render *re, const char *viewname); const char *RE_GetActiveRenderView(struct Render *re); diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 63fd3f1d0bd..e4a2afa4349 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -37,6 +37,7 @@ #include "RE_pipeline.h" +struct GHash; struct Main; struct Object; struct RenderEngine; @@ -112,7 +113,7 @@ struct Render { struct Object *camera_override; ThreadRWMutex partsmutex; - ListBase parts; + struct GHash *parts; /* render engine */ struct RenderEngine *engine; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 9a955b5e8f5..a5bf5adc243 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -29,9 +29,11 @@ #include "BLT_translation.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" +#include "BLI_rect.h" #include "BLI_string.h" -#include "BLI_utildefines.h" #include "DNA_object_types.h" @@ -169,18 +171,10 @@ void RE_engine_free(RenderEngine *engine) static RenderPart *get_part_from_result(Render *re, RenderResult *result) { - RenderPart *pa; - - for (pa = re->parts.first; pa; pa = pa->next) { - if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin && - result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin && - result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin && - result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin) { - return pa; - } - } + rcti key = result->tilerect; + BLI_rcti_translate(&key, re->disprect.xmin, re->disprect.ymin); - return NULL; + return BLI_ghash_lookup(re->parts, &key); } RenderResult *RE_engine_begin_result( @@ -458,7 +452,6 @@ rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_ { static rcti tiles_static[BLENDER_MAX_THREADS]; const int allocation_step = BLENDER_MAX_THREADS; - RenderPart *pa; int total_tiles = 0; rcti *tiles = tiles_static; int allocation_size = BLENDER_MAX_THREADS; @@ -467,13 +460,15 @@ rcti *RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_ *r_needs_free = false; - if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) { + if (!re->parts || (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0)) { *r_total_tiles = 0; BLI_rw_mutex_unlock(&re->partsmutex); return NULL; } - for (pa = re->parts.first; pa; pa = pa->next) { + GHashIterator pa_iter; + GHASH_ITER (pa_iter, re->parts) { + RenderPart *pa = BLI_ghashIterator_getValue(&pa_iter); if (pa->status == PART_STATUS_IN_PROGRESS) { if (total_tiles >= allocation_size) { /* Just in case we're using crazy network rendering with more diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index c147794dae7..1aa16dc1019 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -233,7 +233,7 @@ int imagewrap(Tex *tex, /* keep this before interpolation [#29761] */ if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = true; } @@ -1056,7 +1056,7 @@ static int imagewraposa_aniso(Tex *tex, image_mipmap_test(tex, ibuf); if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = 1; } @@ -1512,7 +1512,7 @@ int imagewraposa(Tex *tex, image_mipmap_test(tex, ibuf); if (ima) { - if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) { + if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) { if ((tex->imaflag & TEX_CALCALPHA) == 0) { texres->talpha = true; } diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 4540e4e2cc2..acdd801bd86 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_ghash.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -245,7 +246,10 @@ void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4 void RE_parts_free(Render *re) { - BLI_freelistN(&re->parts); + if (re->parts) { + BLI_ghash_free(re->parts, NULL, MEM_freeN); + re->parts = NULL; + } } void RE_parts_clamp(Render *re) @@ -262,6 +266,9 @@ void RE_parts_init(Render *re) RE_parts_free(re); + re->parts = BLI_ghash_new( + BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, "render parts"); + /* this is render info for caller, is not reset when parts are freed! */ re->i.totpart = 0; re->i.curpart = 0; @@ -323,7 +330,7 @@ void RE_parts_init(Render *re) pa->rectx = rectx; pa->recty = recty; - BLI_addtail(&re->parts, pa); + BLI_ghash_insert(re->parts, &pa->disprect, pa); re->i.totpart++; } } diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 237debceb83..878a774ab37 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -1458,7 +1458,8 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result) bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter); - ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID; + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(ima, ibuf); if (ibuf->rect_float) { ibuf->userflags |= IB_RECT_INVALID; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7d3002ea71d..9c1c713ab94 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1988,7 +1988,7 @@ const char *RE_GetActiveRenderView(Render *re) /* evaluating scene options for general Blender render */ static int render_initialize_from_main(Render *re, - RenderData *rd, + const RenderData *rd, Main *bmain, Scene *scene, ViewLayer *single_layer, @@ -2072,13 +2072,13 @@ void RE_SetReports(Render *re, ReportList *reports) } /* general Blender frame render call */ -void RE_BlenderFrame(Render *re, - Main *bmain, - Scene *scene, - ViewLayer *single_layer, - Object *camera_override, - int frame, - const bool write_still) +void RE_RenderFrame(Render *re, + Main *bmain, + Scene *scene, + ViewLayer *single_layer, + Object *camera_override, + int frame, + const bool write_still) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); @@ -2090,6 +2090,7 @@ void RE_BlenderFrame(Render *re, if (render_initialize_from_main( re, &scene->r, bmain, scene, single_layer, camera_override, 0, 0)) { + const RenderData rd = scene->r; MEM_reset_peak_memory(); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE); @@ -2097,18 +2098,18 @@ void RE_BlenderFrame(Render *re, do_render_all_options(re); if (write_still && !G.is_break) { - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + if (BKE_imtype_is_movie(rd.im_format.imtype)) { /* operator checks this but in case its called from elsewhere */ printf("Error: cant write single images with a movie format!\n"); } else { char name[FILE_MAX]; BKE_image_path_from_imformat(name, - scene->r.pic, + rd.pic, BKE_main_blendfile_path(bmain), scene->r.cfra, - &scene->r.im_format, - (scene->r.scemode & R_EXTENSION) != 0, + &rd.im_format, + (rd.scemode & R_EXTENSION) != 0, false, NULL); @@ -2117,7 +2118,8 @@ void RE_BlenderFrame(Render *re, } } - BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); if (write_still) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } @@ -2126,8 +2128,7 @@ void RE_BlenderFrame(Render *re, BLI_callback_exec( re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE); - /* Destroy the opengl context in the correct thread. */ - RE_gl_context_destroy(re); + RE_CleanAfterRender(re); /* UGLY WARNING */ G.is_rendering = false; @@ -2427,7 +2428,10 @@ static int do_write_image_or_movie(Render *re, return ok; } -static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height) +static void get_videos_dimensions(const Render *re, + const RenderData *rd, + size_t *r_width, + size_t *r_height) { size_t width, height; if (re->r.mode & R_BORDER) { @@ -2461,23 +2465,23 @@ static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos) } /* saves images to disk */ -void RE_BlenderAnim(Render *re, - Main *bmain, - Scene *scene, - ViewLayer *single_layer, - Object *camera_override, - int sfra, - int efra, - int tfra) -{ - RenderData rd = scene->r; +void RE_RenderAnim(Render *re, + Main *bmain, + Scene *scene, + ViewLayer *single_layer, + Object *camera_override, + int sfra, + int efra, + int tfra) +{ + const RenderData rd = scene->r; bMovieHandle *mh = NULL; - int cfrao = scene->r.cfra; + const int cfrao = rd.cfra; int nfra, totrendered = 0, totskipped = 0; const int totvideos = BKE_scene_multiview_num_videos_get(&rd); - const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); - const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 && - (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); + const bool is_movie = BKE_imtype_is_movie(rd.im_format.imtype); + const bool is_multiview_name = ((rd.scemode & R_MULTIVIEW) != 0 && + (rd.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); @@ -2493,7 +2497,7 @@ void RE_BlenderAnim(Render *re, get_videos_dimensions(re, &rd, &width, &height); - mh = BKE_movie_handle_get(scene->r.im_format.imtype); + mh = BKE_movie_handle_get(rd.im_format.imtype); if (mh == NULL) { BKE_report(re->reports, RPT_ERROR, "Movie format unsupported"); return; @@ -2530,23 +2534,6 @@ void RE_BlenderAnim(Render *re, for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) { char name[FILE_MAX]; - /* Special case for 'mh->get_next_frame' - * this overrides regular frame stepping logic */ - if (mh && mh->get_next_frame) { - while (G.is_break == false) { - int nfra_test = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports); - if (nfra_test >= 0 && nfra_test >= sfra && nfra_test <= efra) { - nfra = nfra_test; - break; - } - else { - if (re->test_break(re->tbh)) { - G.is_break = true; - } - } - } - } - /* Here is a feedback loop exists -- render initialization requires updated * render layers settings which could be animated, but scene evaluation for * the frame happens later because it depends on what layers are visible to @@ -2582,18 +2569,18 @@ void RE_BlenderAnim(Render *re, /* Touch/NoOverwrite options are only valid for image's */ if (is_movie == false) { - if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) { + if (rd.mode & (R_NO_OVERWRITE | R_TOUCH)) { BKE_image_path_from_imformat(name, - scene->r.pic, + rd.pic, BKE_main_blendfile_path(bmain), scene->r.cfra, - &scene->r.im_format, - (scene->r.scemode & R_EXTENSION) != 0, + &rd.im_format, + (rd.scemode & R_EXTENSION) != 0, true, NULL); } - if (scene->r.mode & R_NO_OVERWRITE) { + if (rd.mode & R_NO_OVERWRITE) { if (!is_multiview_name) { if (BLI_exists(name)) { printf("skipping existing frame \"%s\"\n", name); @@ -2626,7 +2613,7 @@ void RE_BlenderAnim(Render *re, } } - if (scene->r.mode & R_TOUCH) { + if (rd.mode & R_TOUCH) { if (!is_multiview_name) { if (!BLI_exists(name)) { BLI_make_existing_file(name); /* makes the dir if its not there */ @@ -2675,7 +2662,7 @@ void RE_BlenderAnim(Render *re, if (G.is_break == true) { /* remove touched file */ if (is_movie == false) { - if ((scene->r.mode & R_TOUCH)) { + if ((rd.mode & R_TOUCH)) { if (!is_multiview_name) { if ((BLI_file_size(name) == 0)) { /* BLI_exists(name) is implicit */ @@ -2706,8 +2693,8 @@ void RE_BlenderAnim(Render *re, } if (G.is_break == false) { - BLI_callback_exec( - re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } } @@ -2730,8 +2717,7 @@ void RE_BlenderAnim(Render *re, re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE); BKE_sound_reset_scene_specs(scene); - /* Destroy the opengl context in the correct thread. */ - RE_gl_context_destroy(re); + RE_CleanAfterRender(re); /* UGLY WARNING */ G.is_rendering = false; @@ -2756,6 +2742,12 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce) do_render_3d(re); } +void RE_CleanAfterRender(Render *re) +{ + /* Destroy the opengl context in the correct thread. */ + RE_gl_context_destroy(re); +} + /* note; repeated win/disprect calc... solve that nicer, also in compo */ /* only the temp file! */ diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 9ca9472e571..04dabad611f 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_hash_md5.h" #include "BLI_path_util.h" @@ -1174,13 +1175,14 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons void render_result_save_empty_result_tiles(Render *re) { - RenderPart *pa; RenderResult *rr; RenderLayer *rl; for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { - for (pa = re->parts.first; pa; pa = pa->next) { + GHashIterator pa_iter; + GHASH_ITER (pa_iter, re->parts) { + RenderPart *pa = BLI_ghashIterator_getValue(&pa_iter); if (pa->status != PART_STATUS_MERGED) { int party = pa->disprect.ymin - re->disprect.ymin; int partx = pa->disprect.xmin - re->disprect.xmin; diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 7e53c652ab5..64f506f03a8 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC intern/wm_toolsystem.c intern/wm_tooltip.c intern/wm_uilist_type.c + intern/wm_utils.c intern/wm_window.c gizmo/intern/wm_gizmo.c gizmo/intern/wm_gizmo_group.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index f1037dadf85..4a7953d7a24 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -60,6 +60,7 @@ struct wmEvent; struct wmEventHandler; struct wmEventHandler_Keymap; struct wmEventHandler_UI; +struct wmGenericUserData; struct wmGesture; struct wmJob; struct wmMsgSubscribeKey; @@ -373,7 +374,8 @@ int WM_operator_confirm_message_ex(struct bContext *C, struct wmOperator *op, const char *title, const int icon, - const char *message); + const char *message, + const short opcontext); int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message); /* operator api */ @@ -400,6 +402,10 @@ int WM_operator_name_call(struct bContext *C, const char *opstring, short context, struct PointerRNA *properties); +int WM_operator_name_call_with_properties(struct bContext *C, + const char *opstring, + short context, + struct IDProperty *properties); int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short context, @@ -660,6 +666,7 @@ enum { WM_JOB_TYPE_SHADER_COMPILATION, WM_JOB_TYPE_STUDIOLIGHT, WM_JOB_TYPE_LIGHT_BAKE, + WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE, /* add as needed, screencast, seq proxy build * if having hard coded values is a problem */ }; @@ -789,6 +796,12 @@ void WM_tooltip_init(struct bContext *C, struct wmWindow *win); void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win); double WM_tooltip_time_closed(void); +/* wm_utils.c */ +struct wmGenericCallback *WM_generic_callback_steal(struct wmGenericCallback *callback); +void WM_generic_callback_free(struct wmGenericCallback *callback); + +void WM_generic_user_data_free(struct wmGenericUserData *user_data); + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 154c4837a68..eddea3b2062 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -120,6 +120,19 @@ struct wmWindowManager; /* Include external gizmo API's */ #include "gizmo/WM_gizmo_api.h" +typedef struct wmGenericUserData { + void *data; + /** When NULL, use #MEM_freeN. */ + void (*free_fn)(void *data); + bool use_free; +} wmGenericUserData; + +typedef struct wmGenericCallback { + void (*exec)(struct bContext *C, void *user_data); + void *user_data; + void (*free_user_data)(void *user_data); +} wmGenericCallback; + /* ************** wmOperatorType ************************ */ /* flag */ @@ -442,8 +455,7 @@ typedef struct wmGesture { /* customdata for straight line is a recti: (xmin,ymin) is start, (xmax, ymax) is end */ /* free pointer to use for operator allocs (if set, its freed on exit)*/ - void *userdata; - bool userdata_free; + wmGenericUserData user_data; } wmGesture; /* ************** wmEvent ************************ */ @@ -605,7 +617,7 @@ typedef struct wmOperatorType { * that the operator might still fail to execute even if this return true */ bool (*poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT; - /* Use to check of properties should be displayed in auto-generated UI. + /* Use to check if properties should be displayed in auto-generated UI. * Use 'check' callback to enforce refreshing. */ bool (*poll_property)(const struct bContext *C, struct wmOperator *op, diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index 1c298f378a4..7d38194db1b 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -198,6 +198,10 @@ struct wmGizmo { /** For single click button gizmos, use a different part as a fallback, -1 when unused. */ int drag_part; + /** Distance to bias this gizmo above others when picking + * (in worldspace, scaled by the gizmo scale - when used). */ + float select_bias; + /** * Transformation of the gizmo in 2d or 3d space. * - Matrix axis are expected to be unit length (scale is applied after). diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c index e2e5096ef99..b05865aa7bb 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c @@ -754,7 +754,6 @@ void WM_gizmo_properties_free(PointerRNA *ptr) if (properties) { IDP_FreeProperty(properties); - MEM_freeN(properties); ptr->data = NULL; /* just in case */ } } diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 31c5e1fb94c..9f36af8b616 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -25,8 +25,10 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_rect.h" #include "BLI_ghash.h" +#include "BLI_array.h" #include "BKE_context.h" #include "BKE_global.h" @@ -470,7 +472,8 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap, static void gizmo_draw_select_3D_loop(const bContext *C, ListBase *visible_gizmos, - const wmGizmo *gz_stop) + const wmGizmo *gz_stop, + bool *r_use_select_bias) { int select_id = 0; wmGizmo *gz; @@ -511,6 +514,10 @@ static void gizmo_draw_select_3D_loop(const bContext *C, is_depth_skip_prev = is_depth_skip; } + if (gz->select_bias != 0.0) { + *r_use_select_bias = true; + } + /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */ gz->type->draw_select(C, gz, select_id << 8); @@ -543,24 +550,68 @@ static int gizmo_find_intersected_3d_intern(ListBase *visible_gizmos, ED_view3d_draw_setup_view( CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect); + bool use_select_bias = false; + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); /* do the drawing */ - gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop); + gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop, &use_select_bias); hits = GPU_select_end(); if (hits > 0) { GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop); + gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop, &use_select_bias); GPU_select_end(); } ED_view3d_draw_setup_view( CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL); - const GLuint *hit_near = GPU_select_buffer_near(buffer, hits); - - return hit_near ? hit_near[3] : -1; + if (use_select_bias && (hits > 1)) { + wmGizmo **gizmo_table = NULL; + BLI_array_staticdeclare(gizmo_table, 1024); + for (LinkData *link = visible_gizmos->first; link; link = link->next) { + BLI_array_append(gizmo_table, link->data); + } + float co_direction[3]; + float co_screen[3] = {co[0], co[1], 0.0f}; + ED_view3d_win_to_vector(ar, (float[2]){UNPACK2(co)}, co_direction); + + RegionView3D *rv3d = ar->regiondata; + const int viewport[4] = {0, 0, ar->winx, ar->winy}; + float co_3d_origin[3]; + + GPU_matrix_unproject_model_inverted( + co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); + + GLuint *buf_iter = buffer; + int hit_found = -1; + float dot_best = FLT_MAX; + + for (int i = 0; i < hits; i++, buf_iter += 4) { + BLI_assert(buf_iter[3] != -1); + wmGizmo *gz = gizmo_table[buf_iter[3] >> 8]; + float co_3d[3]; + co_screen[2] = int_as_float(buf_iter[1]); + GPU_matrix_unproject_model_inverted(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d); + float select_bias = gz->select_bias; + if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { + select_bias *= gz->scale_final; + } + sub_v3_v3(co_3d, co_3d_origin); + const float dot_test = dot_v3v3(co_3d, co_direction) - select_bias; + if (dot_best > dot_test) { + dot_best = dot_test; + hit_found = buf_iter[3]; + } + } + BLI_array_free(gizmo_table); + return hit_found; + } + else { + const GLuint *hit_near = GPU_select_buffer_near(buffer, hits); + return hit_near ? hit_near[3] : -1; + } } /** diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 7647e9f558f..77e17ad4687 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -82,7 +82,6 @@ void WM_operator_free(wmOperator *op) if (op->properties) { IDP_FreeProperty(op->properties); - MEM_freeN(op->properties); } if (op->reports && (op->reports->flag & RPT_FREE)) { diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 30311d83509..e4ecf7e6e94 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -442,7 +442,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize); } else { - UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8, text_col); + UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); } } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 6ecbf4ef5ac..6b6a04cacad 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -917,6 +917,17 @@ void WM_draw_region_free(ARegion *ar) ar->visible = 0; } +void wm_draw_region_test(bContext *C, ScrArea *sa, ARegion *ar) +{ + /* Function for redraw timer benchmark. */ + bool use_viewport = wm_region_use_viewport(sa, ar); + wm_draw_region_buffer_create(ar, false, use_viewport); + wm_draw_region_bind(ar, 0); + ED_region_do_draw(C, ar); + wm_draw_region_unbind(ar, 0); + ar->do_draw = false; +} + void WM_redraw_windows(bContext *C) { wmWindow *win_prev = CTX_wm_window(C); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 13b6260e2b9..6683085e6d3 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1293,7 +1293,6 @@ static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_ IDP_MergeGroup(op->properties, replaceprops, true); IDP_FreeProperty(replaceprops); - MEM_freeN(replaceprops); return changed; } @@ -1316,7 +1315,6 @@ bool WM_operator_last_properties_store(wmOperator *op) { if (op->type->last_properties) { IDP_FreeProperty(op->type->last_properties); - MEM_freeN(op->type->last_properties); op->type->last_properties = NULL; } @@ -1680,6 +1678,17 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin return 0; } +int WM_operator_name_call_with_properties(struct bContext *C, + const char *opstring, + short context, + struct IDProperty *properties) +{ + PointerRNA props_ptr; + wmOperatorType *ot = WM_operatortype_find(opstring, false); + RNA_pointer_create(NULL, ot->srna, properties, &props_ptr); + return WM_operator_name_call_ptr(C, ot, context, &props_ptr); +} + /** * Call an existent menu. The menu can be created in C or Python. */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 6d90d4745a6..097db49aea6 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -76,6 +76,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -98,6 +99,7 @@ #include "ED_datafiles.h" #include "ED_fileselect.h" +#include "ED_image.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" @@ -488,18 +490,21 @@ void wm_file_read_report(bContext *C, Main *bmain) static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool is_factory_startup, + const bool use_data, + const bool use_userdef, const bool reset_app_template) { bool addons_loaded = false; wmWindowManager *wm = CTX_wm_manager(C); - if (!G.background) { - /* remove windows which failed to be added via WM_check */ - wm_window_ghostwindows_remove_invalid(C, wm); + if (use_data) { + if (!G.background) { + /* remove windows which failed to be added via WM_check */ + wm_window_ghostwindows_remove_invalid(C, wm); + } + CTX_wm_window_set(C, wm->windows.first); } - CTX_wm_window_set(C, wm->windows.first); - #ifdef WITH_PYTHON if (is_startup_file) { /* possible python hasn't been initialized */ @@ -513,41 +518,56 @@ static void wm_file_read_post(bContext *C, /* sync addons, these may have changed from the defaults */ BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); } - BPY_python_reset(C); + if (use_data) { + BPY_python_reset(C); + } addons_loaded = true; } } else { /* run any texts that were loaded in and flagged as modules */ - BPY_python_reset(C); + if (use_data) { + BPY_python_reset(C); + } addons_loaded = true; } #else UNUSED_VARS(is_startup_file, reset_app_template); #endif /* WITH_PYTHON */ - WM_operatortype_last_properties_clear_all(); - - /* important to do before NULL'ing the context */ Main *bmain = CTX_data_main(C); - BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE); - BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST); - if (is_factory_startup) { - BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST); + + if (use_userdef) { + if (is_factory_startup) { + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST); + } + } + + if (use_data) { + /* important to do before NULL'ing the context */ + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE); + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST); + if (is_factory_startup) { + BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST); + } } - /* After load post, so for example the driver namespace can be filled - * before evaluating the depsgraph. */ - DEG_on_visible_update(bmain, true); - wm_event_do_depsgraph(C); + if (use_data) { + WM_operatortype_last_properties_clear_all(); - ED_editors_init(C); + /* After load post, so for example the driver namespace can be filled + * before evaluating the depsgraph. */ + DEG_on_visible_update(bmain, true); + wm_event_do_depsgraph(C); + + ED_editors_init(C); #if 1 - WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); + WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); #else - WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ); + WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ); #endif + } /* report any errors. * currently disabled if addons aren't yet loaded */ @@ -555,25 +575,29 @@ static void wm_file_read_post(bContext *C, wm_file_read_report(C, bmain); } - if (!G.background) { - if (wm->undo_stack == NULL) { - wm->undo_stack = BKE_undosys_stack_create(); - } - else { - BKE_undosys_stack_clear(wm->undo_stack); + if (use_data) { + if (!G.background) { + if (wm->undo_stack == NULL) { + wm->undo_stack = BKE_undosys_stack_create(); + } + else { + BKE_undosys_stack_clear(wm->undo_stack); + } + BKE_undosys_stack_init_from_main(wm->undo_stack, bmain); + BKE_undosys_stack_init_from_context(wm->undo_stack, C); } - BKE_undosys_stack_init_from_main(wm->undo_stack, bmain); - BKE_undosys_stack_init_from_context(wm->undo_stack, C); } - if (!G.background) { - /* in background mode this makes it hard to load - * a blend file and do anything since the screen - * won't be set to a valid value again */ - CTX_wm_window_set(C, NULL); /* exits queues */ + if (use_data) { + if (!G.background) { + /* in background mode this makes it hard to load + * a blend file and do anything since the screen + * won't be set to a valid value again */ + CTX_wm_window_set(C, NULL); /* exits queues */ - /* Ensure tools are registered. */ - WM_toolsystem_init(C); + /* Ensure tools are registered. */ + WM_toolsystem_init(C); + } } } @@ -600,6 +624,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { + bool use_data = true; + bool use_userdef = false; const int G_f_orig = G.f; ListBase wmbase; @@ -638,6 +664,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { /* in case a userdef is read from regular .blend */ wm_init_userdef(bmain, false); + use_userdef = true; } if (retval != BKE_BLENDFILE_READ_FAIL) { @@ -646,7 +673,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - wm_file_read_post(C, false, false, false); + wm_file_read_post(C, false, false, use_data, use_userdef, false); success = true; } @@ -716,26 +743,6 @@ const char *WM_init_state_app_template_get(void) return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL; } -static bool wm_app_template_has_userpref(const char *app_template) -{ - /* Test if app template provides a userpref.blend. If not, we will - * share user preferences with the rest of Blender. */ - if (!app_template && app_template[0]) { - return false; - } - - char app_template_path[FILE_MAX]; - if (!BKE_appdir_app_template_id_search( - app_template, app_template_path, sizeof(app_template_path))) { - return false; - } - - char userpref_path[FILE_MAX]; - BLI_path_join( - userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL); - return BLI_exists(userpref_path); -} - /** * Called on startup, (context entirely filled with NULLs) * or called for 'New File' both startup.blend and userpref.blend are checked. @@ -758,6 +765,7 @@ void wm_homefile_read(bContext *C, ReportList *reports, bool use_factory_settings, bool use_empty_data, + bool use_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override, @@ -788,7 +796,14 @@ void wm_homefile_read(bContext *C, * And in this case versioning code is to be run. */ bool read_userdef_from_memory = false; - eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF; + eBLOReadSkip skip_flags = 0; + + if (use_data == false) { + skip_flags |= BLO_READ_SKIP_DATA; + } + if (use_userdef == false) { + skip_flags |= BLO_READ_SKIP_USERDEF; + } /* True if we load startup.blend from memory * or use app-template startup.blend which the user hasn't saved. */ @@ -801,14 +816,16 @@ void wm_homefile_read(bContext *C, SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC); } - BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); + if (use_data) { + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); - UI_view2d_zoom_cache_reset(); + G.relbase_valid = 0; - G.relbase_valid = 0; + /* put aside screens to match with persistent windows later */ + wm_window_match_init(C, &wmbase); + } - /* put aside screens to match with persistent windows later */ - wm_window_match_init(C, &wmbase); + UI_view2d_zoom_cache_reset(); filepath_startup[0] = '\0'; filepath_userdef[0] = '\0'; @@ -931,7 +948,9 @@ void wm_homefile_read(bContext *C, } if (success) { if (update_defaults) { - BLO_update_defaults_startup_blend(CTX_data_main(C), app_template); + if (use_data) { + BLO_update_defaults_startup_blend(CTX_data_main(C), app_template); + } } is_factory_startup = filepath_startup_is_factory; } @@ -1010,10 +1029,12 @@ void wm_homefile_read(bContext *C, BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template)); } - /* Prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. - * Screws up autosaves otherwise can remove this eventually, - * only in a 2.53 and older, now its not written. */ - G.fileflags &= ~G_FILE_RELATIVE_REMAP; + if (use_data) { + /* Prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. + * Screws up autosaves otherwise can remove this eventually, + * only in a 2.53 and older, now its not written. */ + G.fileflags &= ~G_FILE_RELATIVE_REMAP; + } bmain = CTX_data_main(C); @@ -1023,8 +1044,10 @@ void wm_homefile_read(bContext *C, reset_app_template = true; } - /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); + if (use_data) { + /* match the read WM with current WM */ + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); + } if (use_factory_settings) { /* Clear keymaps because the current default keymap may have been initialized @@ -1036,14 +1059,16 @@ void wm_homefile_read(bContext *C, } } - WM_check(C); /* opens window(s), checks keymaps */ + if (use_data) { + WM_check(C); /* opens window(s), checks keymaps */ - bmain->name[0] = '\0'; + bmain->name[0] = '\0'; - /* start with save preference untitled.blend */ - G.save_over = 0; + /* start with save preference untitled.blend */ + G.save_over = 0; + } - wm_file_read_post(C, true, is_factory_startup, reset_app_template); + wm_file_read_post(C, true, is_factory_startup, use_data, use_userdef, reset_app_template); if (r_is_factory_startup) { *r_is_factory_startup = is_factory_startup; @@ -1245,7 +1270,6 @@ static ImBuf *blend_file_thumb(const bContext *C, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, - V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, @@ -1653,6 +1677,7 @@ static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED { bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare"); BLI_addtail(&U.autoexec_paths, path_cmp); + U.runtime.is_dirty = true; return OPERATOR_FINISHED; } @@ -1673,6 +1698,7 @@ static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index); if (path_cmp) { BLI_freelinkN(&U.autoexec_paths, path_cmp); + U.runtime.is_dirty = true; } return OPERATOR_FINISHED; } @@ -1694,69 +1720,141 @@ void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot) static int wm_userpref_write_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); - char filepath[FILE_MAX]; - const char *cfgdir; - bool ok = true; - bool use_template_userpref = wm_app_template_has_userpref(U.app_template); - /* update keymaps in user preferences */ + /* Update keymaps in user preferences. */ WM_keyconfig_update(wm); - if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) { - bool ok_write; - BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + const bool ok = BKE_blendfile_userdef_write_all(op->reports); - printf("Writing userprefs: '%s' ", filepath); - if (use_template_userpref) { - ok_write = BKE_blendfile_userdef_write_app_template(filepath, op->reports); - } - else { - ok_write = BKE_blendfile_userdef_write(filepath, op->reports); - } + return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} - if (ok_write) { - printf("ok\n"); - } - else { - printf("fail\n"); - ok = false; - } - } - else { - BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path"); - } +void WM_OT_save_userpref(wmOperatorType *ot) +{ + ot->name = "Save Preferences"; + ot->idname = "WM_OT_save_userpref"; + ot->description = "Save preferences separately, overrides startup file preferences"; - if (use_template_userpref) { - if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) { - /* Also save app-template prefs */ - BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL); + ot->invoke = WM_operator_confirm; + ot->exec = wm_userpref_write_exec; +} - printf("Writing userprefs app-template: '%s' ", filepath); - if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) { - printf("ok\n"); +static void rna_struct_update_when_changed(bContext *C, + Main *bmain, + PointerRNA *ptr_a, + PointerRNA *ptr_b) +{ + CollectionPropertyIterator iter; + PropertyRNA *iterprop = RNA_struct_iterator_property(ptr_a->type); + BLI_assert(ptr_a->type == ptr_b->type); + RNA_property_collection_begin(ptr_a, iterprop, &iter); + for (; iter.valid; RNA_property_collection_next(&iter)) { + PropertyRNA *prop = iter.ptr.data; + if (STREQ(RNA_property_identifier(prop), "rna_type")) { + continue; + } + switch (RNA_property_type(prop)) { + case PROP_POINTER: { + PointerRNA ptr_sub_a = RNA_property_pointer_get(ptr_a, prop); + PointerRNA ptr_sub_b = RNA_property_pointer_get(ptr_b, prop); + rna_struct_update_when_changed(C, bmain, &ptr_sub_a, &ptr_sub_b); + break; } - else { - printf("fail\n"); - ok = false; + case PROP_COLLECTION: + /* Don't handle collections. */ + break; + default: { + if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, RNA_EQ_STRICT)) { + RNA_property_update(C, ptr_b, prop); + } } } - else { - BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path"); - ok = false; - } } + RNA_property_collection_end(&iter); +} - return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +static void wm_userpref_update_when_changed(bContext *C, + Main *bmain, + UserDef *userdef_prev, + UserDef *userdef_curr) +{ + PointerRNA ptr_a, ptr_b; + RNA_pointer_create(NULL, &RNA_Preferences, userdef_prev, &ptr_a); + RNA_pointer_create(NULL, &RNA_Preferences, userdef_curr, &ptr_b); + const bool is_dirty = userdef_curr->runtime.is_dirty; + + rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b); + +#ifdef WITH_PYTHON + BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); +#endif + + WM_keyconfig_reload(C); + userdef_curr->runtime.is_dirty = is_dirty; } -void WM_OT_save_userpref(wmOperatorType *ot) +static int wm_userpref_read_exec(bContext *C, wmOperator *op) { - ot->name = "Save Preferences"; - ot->idname = "WM_OT_save_userpref"; - ot->description = "Save preferences separately, overrides startup file preferences"; + const bool use_data = false; + const bool use_userdef = true; + const bool use_factory_settings = STREQ(op->type->idname, "WM_OT_read_factory_userpref"); + + UserDef U_backup = U; + + wm_homefile_read(C, + op->reports, + use_factory_settings, + false, + use_data, + use_userdef, + NULL, + WM_init_state_app_template_get(), + NULL); + +#define USERDEF_RESTORE(member) \ + { \ + U.member = U_backup.member; \ + } \ + ((void)0) + + USERDEF_RESTORE(userpref); + +#undef USERDEF_RESTORE + + Main *bmain = CTX_data_main(C); + + wm_userpref_update_when_changed(C, bmain, &U_backup, &U); + + if (use_factory_settings) { + U.runtime.is_dirty = true; + } + + /* Needed to recalculate UI scaling values (eg, #UserDef.inv_dpi_fac). */ + wm_window_clear_drawable(bmain->wm.first); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; +} + +void WM_OT_read_userpref(wmOperatorType *ot) +{ + ot->name = "Load Preferences"; + ot->idname = "WM_OT_read_userpref"; + ot->description = "Load last saved preferences"; ot->invoke = WM_operator_confirm; - ot->exec = wm_userpref_write_exec; + ot->exec = wm_userpref_read_exec; +} + +void WM_OT_read_factory_userpref(wmOperatorType *ot) +{ + ot->name = "Load Factory Preferences"; + ot->idname = "WM_OT_read_factory_userpref"; + ot->description = "Load default preferences"; + + ot->invoke = WM_operator_confirm; + ot->exec = wm_userpref_read_exec; } static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) @@ -1816,14 +1914,15 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template"); const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash"); const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty"); + const bool use_temporary_preferences = RNA_boolean_get(op->ptr, "use_temporary_preferences"); if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) { RNA_property_string_get(op->ptr, prop_app_template, app_template_buf); app_template = app_template_buf; /* Always load preferences when switching templates with own preferences. */ - use_userdef = wm_app_template_has_userpref(app_template) || - wm_app_template_has_userpref(U.app_template); + use_userdef = BKE_appdir_app_template_has_userpref(app_template) || + BKE_appdir_app_template_has_userpref(U.app_template); /* Turn override off, since we're explicitly loading a different app-template. */ WM_init_state_app_template_set(NULL); @@ -1833,10 +1932,12 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) app_template = WM_init_state_app_template_get(); } + bool use_data = true; wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, + use_data, use_userdef, filepath, app_template, @@ -1844,20 +1945,56 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) if (use_splash) { WM_init_splash(C); } + SET_FLAG_FROM_TEST(G.f, use_temporary_preferences, G_FLAG_USERPREF_NO_SAVE_ON_EXIT); + return OPERATOR_FINISHED; } +static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data) +{ + WM_operator_name_call_with_properties( + C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data); +} + +static void wm_free_operator_properties_callback(void *user_data) +{ + IDProperty *properties = (IDProperty *)user_data; + IDP_FreeProperty(properties); +} + static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - wmWindowManager *wm = CTX_wm_manager(C); - if (U.uiflag & USER_SAVE_PROMPT && !wm->file_saved) { - return WM_operator_confirm_message(C, op, "Changes in current file will be lost. Continue?"); + if (U.uiflag & USER_SAVE_PROMPT && wm_file_or_image_is_modified(C)) { + wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__); + callback->exec = wm_homefile_read_after_dialog_callback; + callback->user_data = IDP_CopyProperty(op->properties); + callback->free_user_data = wm_free_operator_properties_callback; + wm_close_file_dialog(C, callback); + return OPERATOR_INTERFACE; } else { return wm_homefile_read_exec(C, op); } } +static void read_homefile_props(wmOperatorType *ot) +{ + PropertyRNA *prop; + + prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, + "use_temporary_preferences", + false, + "Temporary Preferences", + "Don't save preferences on exit"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + void WM_OT_read_homefile(wmOperatorType *ot) { PropertyRNA *prop; @@ -1877,23 +2014,17 @@ void WM_OT_read_homefile(wmOperatorType *ot) ot->srna, "load_ui", true, "Load UI", "Load user interface setup from the .blend file"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - /* So the splash can be kept open after loading a file (for templates). */ prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + read_homefile_props(ot); /* omit poll to run in background mode */ } void WM_OT_read_factory_settings(wmOperatorType *ot) { - PropertyRNA *prop; - ot->name = "Load Factory Settings"; ot->idname = "WM_OT_read_factory_settings"; ot->description = "Load default file and preferences"; @@ -1901,12 +2032,7 @@ void WM_OT_read_factory_settings(wmOperatorType *ot) ot->invoke = WM_operator_confirm; ot->exec = wm_homefile_read_exec; - prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - + read_homefile_props(ot); /* omit poll to run in background mode */ } @@ -1939,13 +2065,88 @@ static bool wm_file_read_opwrap(bContext *C, return success; } -/* currently fits in a pointer */ -struct FileRuntime { - bool is_untrusted; +/* Generic operator state utilities + *********************************************/ + +static void create_operator_state(wmOperatorType *ot, int first_state) +{ + PropertyRNA *prop = RNA_def_int( + ot->srna, "state", first_state, INT32_MIN, INT32_MAX, "State", "", INT32_MIN, INT32_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN); +} + +static int get_operator_state(wmOperator *op) +{ + return RNA_int_get(op->ptr, "state"); +} + +static void set_next_operator_state(wmOperator *op, int state) +{ + RNA_int_set(op->ptr, "state", state); +} + +typedef struct OperatorDispatchTarget { + int state; + int (*run)(bContext *C, wmOperator *op); +} OperatorDispatchTarget; + +static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatchTarget *targets) +{ + int state = get_operator_state(op); + for (int i = 0; targets[i].run; i++) { + OperatorDispatchTarget target = targets[i]; + if (target.state == state) { + return target.run(C, op); + } + } + BLI_assert(false); + return OPERATOR_CANCELLED; +} + +/* Open Mainfile operator + ********************************************/ + +enum { + OPEN_MAINFILE_STATE_DISCARD_CHANGES, + OPEN_MAINFILE_STATE_SELECT_FILE_PATH, + OPEN_MAINFILE_STATE_OPEN, }; -static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op); + +static void wm_open_mainfile_after_dialog_callback(bContext *C, void *user_data) { + WM_operator_name_call_with_properties( + C, "WM_OT_open_mainfile", WM_OP_INVOKE_DEFAULT, (IDProperty *)user_data); +} + +static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op) +{ + if (RNA_boolean_get(op->ptr, "display_file_selector")) { + set_next_operator_state(op, OPEN_MAINFILE_STATE_SELECT_FILE_PATH); + } + else { + set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN); + } + + if (U.uiflag & USER_SAVE_PROMPT && wm_file_or_image_is_modified(C)) { + wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__); + callback->exec = wm_open_mainfile_after_dialog_callback; + callback->user_data = IDP_CopyProperty(op->properties); + callback->free_user_data = wm_free_operator_properties_callback; + wm_close_file_dialog(C, callback); + return OPERATOR_INTERFACE; + } + else { + return wm_open_mainfile_dispatch(C, op); + } +} + +static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op) +{ + set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN); + Main *bmain = CTX_data_main(C); const char *openname = BKE_main_blendfile_path(bmain); @@ -1973,7 +2174,7 @@ static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U return OPERATOR_RUNNING_MODAL; } -static int wm_open_mainfile_exec(bContext *C, wmOperator *op) +static int wm_open_mainfile__open(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; bool success; @@ -2011,6 +2212,33 @@ static int wm_open_mainfile_exec(bContext *C, wmOperator *op) } } +static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[] = { + {OPEN_MAINFILE_STATE_DISCARD_CHANGES, wm_open_mainfile__discard_changes}, + {OPEN_MAINFILE_STATE_SELECT_FILE_PATH, wm_open_mainfile__select_file_path}, + {OPEN_MAINFILE_STATE_OPEN, wm_open_mainfile__open}, + {0, NULL}, +}; + +static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op) +{ + return operator_state_dispatch(C, op, wm_open_mainfile_dispatch_targets); +} + +static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return wm_open_mainfile_dispatch(C, op); +} + +static int wm_open_mainfile_exec(bContext *C, wmOperator *op) +{ + return wm_open_mainfile__open(C, op); +} + +/* currently fits in a pointer */ +struct FileRuntime { + bool is_untrusted; +}; + static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op) { struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata; @@ -2091,6 +2319,12 @@ void WM_OT_open_mainfile(wmOperatorType *ot) "Trusted Source", "Allow .blend file to execute scripts automatically, default available from " "system preferences"); + + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "display_file_selector", true, "Display File Selector", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + create_operator_state(ot, OPEN_MAINFILE_STATE_DISCARD_CHANGES); } /** \} */ @@ -2629,9 +2863,228 @@ void wm_test_autorun_warning(bContext *C) if (win) { wmWindow *prevwin = CTX_wm_window(C); CTX_wm_window_set(C, win); - UI_popup_block_invoke(C, block_create_autorun_warning, NULL); + UI_popup_block_invoke(C, block_create_autorun_warning, NULL, NULL); CTX_wm_window_set(C, prevwin); } } +/* Close File Dialog + *************************************/ + +static char save_images_when_file_is_closed = true; + +static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data)) +{ + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, arg_block); +} + +static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data) +{ + wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data); + + /* Close the popup before executing the callback. Otherwise + * the popup might be closed by the callback, which will lead + * to a crash. */ + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, arg_block); + + callback->exec(C, callback->user_data); + WM_generic_callback_free(callback); +} + +static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data) +{ + wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data); + bool execute_callback = true; + + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, arg_block); + + if (save_images_when_file_is_closed) { + ReportList *reports = CTX_wm_reports(C); + if (!ED_image_save_all_modified(C, reports)) { + execute_callback = false; + } + WM_report_banner_show(); + } + + Main *bmain = CTX_data_main(C); + bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0'; + + if (file_has_been_saved_before) { + WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL); + } + else { + WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, NULL); + execute_callback = false; + } + + if (execute_callback) { + callback->exec(C, callback->user_data); + } + WM_generic_callback_free(callback); +} + +static void wm_block_file_close_cancel_button(uiBlock *block, wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut( + block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); + UI_but_func_set(but, wm_block_file_close_cancel, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); +} + +static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut( + block, UI_BTYPE_BUT, 0, 0, IFACE_("Discard Changes"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); + UI_but_func_set(but, wm_block_file_close_discard, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); +} + +static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *post_action) +{ + uiBut *but = uiDefIconTextBut( + block, UI_BTYPE_BUT, 0, 0, IFACE_("Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); + UI_but_func_set(but, wm_block_file_close_save, block, post_action); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); +} + +static const char *close_file_dialog_name = "file_close_popup"; + +static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegion *ar, void *arg1) +{ + wmGenericCallback *post_action = (wmGenericCallback *)arg1; + Main *bmain = CTX_data_main(C); + + uiStyle *style = UI_style_get(); + uiBlock *block = UI_block_begin(C, ar, close_file_dialog_name, UI_EMBOSS); + + UI_block_flag_enable( + block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); + UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + UI_block_emboss_set(block, UI_EMBOSS); + + uiLayout *layout = UI_block_layout(block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + 10, + 2, + U.widget_unit * 24, + U.widget_unit * 6, + 0, + style); + + /* Title */ + bool blend_file_is_saved = BKE_main_blendfile_path(bmain)[0] != '\0'; + if (blend_file_is_saved) { + uiItemL(layout, "This file has unsaved changes.", ICON_INFO); + } + else { + uiItemL(layout, "This file has not been saved yet.", ICON_INFO); + } + + /* Image Saving */ + ReportList reports; + BKE_reports_init(&reports, RPT_STORE); + uint modified_images_count = ED_image_save_all_modified_info(C, &reports); + + if (modified_images_count > 0) { + char message[64]; + BLI_snprintf(message, + sizeof(message), + (modified_images_count == 1) ? "Save %u modified image" : + "Save %u modified images", + modified_images_count); + uiDefButBitC(block, + UI_BTYPE_CHECKBOX, + 1, + 0, + message, + 0, + 0, + 0, + UI_UNIT_Y, + &save_images_when_file_is_closed, + 0, + 0, + 0, + 0, + ""); + + LISTBASE_FOREACH (Report *, report, &reports.list) { + uiItemL(layout, report->message, ICON_ERROR); + } + } + + BKE_reports_clear(&reports); + + uiItemL(layout, "", ICON_NONE); + + /* Buttons */ +#ifdef _WIN32 + const bool windows_layout = true; +#else + const bool windows_layout = false; +#endif + + uiLayout *split = uiLayoutSplit(layout, 0.0f, true); + + if (windows_layout) { + /* Windows standard layout. */ + uiLayout *col = uiLayoutColumn(split, false); + uiItemS(col); + + col = uiLayoutColumn(split, false); + wm_block_file_close_save_button(block, post_action); + + col = uiLayoutColumn(split, false); + wm_block_file_close_discard_button(block, post_action); + + col = uiLayoutColumn(split, false); + wm_block_file_close_cancel_button(block, post_action); + } + else { + /* macOS and Linux standard layout. */ + uiLayout *col = uiLayoutColumn(split, false); + wm_block_file_close_discard_button(block, post_action); + + col = uiLayoutColumn(split, false); + uiItemS(col); + + col = uiLayoutColumn(split, false); + wm_block_file_close_cancel_button(block, post_action); + + col = uiLayoutColumn(split, false); + wm_block_file_close_save_button(block, post_action); + } + + UI_block_bounds_set_centered(block, 10); + return block; +} + +static void free_post_file_close_action(void *arg) +{ + wmGenericCallback *action = (wmGenericCallback *)arg; + WM_generic_callback_free(action); +} + +void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action) +{ + if (!UI_popup_block_name_exists(C, close_file_dialog_name)) { + UI_popup_block_invoke( + C, block_create__close_file_dialog, post_action, free_post_file_close_action); + } + else { + WM_generic_callback_free(post_action); + } +} + +bool wm_file_or_image_is_modified(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + return !wm->file_saved || ED_image_should_save_modified(C); +} + /** \} */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index b12bb89ea9f..e117a1bcdfe 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -62,7 +62,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) gesture->type = type; gesture->event_type = event->type; gesture->winrct = ar->winrct; - gesture->userdata_free = true; /* Free if userdata is set. */ + gesture->user_data.use_free = true; /* Free if userdata is set. */ gesture->modal_state = GESTURE_MODAL_NOP; if (ELEM(type, @@ -106,9 +106,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture) } BLI_remlink(&win->gesture, gesture); MEM_freeN(gesture->customdata); - if (gesture->userdata && gesture->userdata_free) { - MEM_freeN(gesture->userdata); - } + WM_generic_user_data_free(&gesture->user_data); MEM_freeN(gesture); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 97ba9190351..04a3115992f 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -52,6 +52,7 @@ #include "BLO_writefile.h" #include "BLO_undofile.h" +#include "BKE_blendfile.h" #include "BKE_blender.h" #include "BKE_blender_undo.h" #include "BKE_context.h" @@ -254,11 +255,15 @@ void WM_init(bContext *C, int argc, const char **argv) /* get the default database, plus a wm */ bool is_factory_startup = true; + const bool use_data = true; + const bool use_userdef = true; + wm_homefile_read(C, NULL, G.factory_startup, false, - true, + use_data, + use_userdef, NULL, WM_init_state_app_template_get(), &is_factory_startup); @@ -469,6 +474,14 @@ void WM_exit_ext(bContext *C, const bool do_python) WM_event_remove_handlers(C, &win->modalhandlers); ED_screen_exit(C, win, WM_window_get_active_screen(win)); } + + if (!G.background) { + if ((U.pref_flag & USER_PREF_FLAG_SAVE) && ((G.f & G_FLAG_USERPREF_NO_SAVE_ON_EXIT) == 0)) { + if (U.runtime.is_dirty) { + BKE_blendfile_userdef_write_all(NULL); + } + } + } } BLI_timer_free(); diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index bae9a5de1e6..a4ee735d911 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -310,6 +310,7 @@ bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) { if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) { BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr)); + U.runtime.is_dirty = true; WM_keyconfig_update_tag(NULL, NULL); } @@ -360,6 +361,9 @@ void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname) WM_keyconfig_update(wm); BLI_strncpy(U.keyconfigstr, idname, sizeof(U.keyconfigstr)); + if (wm->initialized & WM_KEYCONFIG_IS_INITIALIZED) { + U.runtime.is_dirty = true; + } WM_keyconfig_update_tag(NULL, NULL); WM_keyconfig_update(wm); @@ -1120,7 +1124,8 @@ const char *WM_key_event_string(const short type, const bool compact) if (platform == MACOS) { icon_glyph = "\xe2\x87\xa7"; } - return key_event_icon_or_text(font_id, IFACE_("Shift"), icon_glyph); + return key_event_icon_or_text( + font_id, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Shift"), icon_glyph); } case LEFTCTRLKEY: case RIGHTCTRLKEY: @@ -1407,7 +1412,6 @@ static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap, } IDP_FreeProperty(properties_default); - MEM_freeN(properties_default); } } } @@ -1581,7 +1585,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, } IDP_FreeProperty(properties_temp); - MEM_freeN(properties_temp); } } @@ -1620,7 +1623,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C, } IDP_FreeProperty(properties_default); - MEM_freeN(properties_default); } } } @@ -2017,7 +2019,6 @@ void WM_keymap_item_restore_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapIt if (orig->properties) { if (kmi->properties) { IDP_FreeProperty(kmi->properties); - MEM_freeN(kmi->properties); kmi->properties = NULL; } diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index ece57f5a63b..3ad7247d993 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -94,7 +94,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot, } if (flag & WM_FILESEL_FILES) { - RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); + prop = RNA_def_collection_runtime( + ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } if (action == FILE_SAVE) { @@ -344,11 +346,11 @@ void WM_operator_properties_gesture_box(wmOperatorType *ot) void WM_operator_properties_select_operation(wmOperatorType *ot) { static const EnumPropertyItem select_mode_items[] = { - {SEL_OP_SET, "SET", 0, "New", ""}, - {SEL_OP_ADD, "ADD", 0, "Add", ""}, - {SEL_OP_SUB, "SUB", 0, "Subtract", ""}, - {SEL_OP_XOR, "XOR", 0, "Difference", ""}, - {SEL_OP_AND, "AND", 0, "Intersect", ""}, + {SEL_OP_SET, "SET", ICON_SELECT_SET, "Set", "Set a new selection"}, + {SEL_OP_ADD, "ADD", ICON_SELECT_EXTEND, "Extend", "Extend existing selection"}, + {SEL_OP_SUB, "SUB", ICON_SELECT_SUBTRACT, "Subtract", "Subtract existing selection"}, + {SEL_OP_XOR, "XOR", ICON_SELECT_DIFFERENCE, "Difference", "Inverts existing selection"}, + {SEL_OP_AND, "AND", ICON_SELECT_INTERSECT, "Intersect", "Intersect existing selection"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", ""); @@ -359,9 +361,9 @@ void WM_operator_properties_select_operation(wmOperatorType *ot) void WM_operator_properties_select_operation_simple(wmOperatorType *ot) { static const EnumPropertyItem select_mode_items[] = { - {SEL_OP_SET, "SET", 0, "New", ""}, - {SEL_OP_ADD, "ADD", 0, "Add", ""}, - {SEL_OP_SUB, "SUB", 0, "Subtract", ""}, + {SEL_OP_SET, "SET", ICON_SELECT_SET, "Set", "Set a new selection"}, + {SEL_OP_ADD, "ADD", ICON_SELECT_EXTEND, "Extend", "Extend existing selection"}, + {SEL_OP_SUB, "SUB", ICON_SELECT_SUBTRACT, "Subtract", "Subtract existing selection"}, {0, NULL, 0, NULL, NULL}, }; PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", ""); diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 3585cffc615..179b4402200 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -156,7 +156,6 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot) if (ot->last_properties) { IDP_FreeProperty(ot->last_properties); - MEM_freeN(ot->last_properties); } if (ot->macro.first) { @@ -194,7 +193,6 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot) { if (ot->last_properties) { IDP_FreeProperty(ot->last_properties); - MEM_freeN(ot->last_properties); } if (ot->macro.first) { @@ -279,7 +277,6 @@ void WM_operatortype_last_properties_clear_all(void) if (ot->last_properties) { IDP_FreeProperty(ot->last_properties); - MEM_freeN(ot->last_properties); ot->last_properties = NULL; } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ec803c9bba7..4a99c2de6e7 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -691,7 +691,6 @@ void WM_operator_properties_free(PointerRNA *ptr) if (properties) { IDP_FreeProperty(properties); - MEM_freeN(properties); ptr->data = NULL; /* just in case */ } } @@ -870,7 +869,7 @@ int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, search_menu.prv_cols = prv_cols; search_menu.prv_rows = prv_rows; - UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu); + UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL); return OPERATOR_INTERFACE; } @@ -879,13 +878,17 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve { static struct EnumSearchMenu search_menu; search_menu.op = op; - UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu); + UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL); return OPERATOR_INTERFACE; } /* Can't be used as an invoke directly, needs message arg (can be NULL) */ -int WM_operator_confirm_message_ex( - bContext *C, wmOperator *op, const char *title, const int icon, const char *message) +int WM_operator_confirm_message_ex(bContext *C, + wmOperator *op, + const char *title, + const int icon, + const char *message, + const short opcontext) { uiPopupMenu *pup; uiLayout *layout; @@ -900,8 +903,7 @@ int WM_operator_confirm_message_ex( pup = UI_popup_menu_begin(C, title, icon); layout = UI_popup_menu_layout(pup); - uiItemFullO_ptr( - layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0, NULL); + uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, opcontext, 0, NULL); UI_popup_menu_end(C, pup); return OPERATOR_INTERFACE; @@ -909,7 +911,8 @@ int WM_operator_confirm_message_ex( int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message) { - return WM_operator_confirm_message_ex(C, op, IFACE_("OK?"), ICON_QUESTION, message); + return WM_operator_confirm_message_ex( + C, op, IFACE_("OK?"), ICON_QUESTION, message, WM_OP_EXEC_REGION_WIN); } int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) @@ -1398,7 +1401,7 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - UI_popup_block_invoke(C, wm_block_create_redo, op); + UI_popup_block_invoke(C, wm_block_create_redo, op, NULL); return OPERATOR_CANCELLED; } @@ -1710,7 +1713,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - UI_popup_block_invoke(C, wm_block_create_splash, NULL); + UI_popup_block_invoke(C, wm_block_create_splash, NULL, NULL); return OPERATOR_FINISHED; } @@ -1816,7 +1819,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv data.size[0] = UI_searchbox_size_x() * 2; data.size[1] = UI_searchbox_size_y(); - UI_popup_block_invoke(C, wm_block_search_menu, &data); + UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL); return OPERATOR_INTERFACE; } @@ -3082,8 +3085,7 @@ static void redraw_timer_step(bContext *C, { if (type == eRTDrawRegion) { if (ar) { - ED_region_do_draw(C, ar); - ar->do_draw = false; + wm_draw_region_test(C, sa, ar); } } else if (type == eRTDrawRegionSwap) { @@ -3107,8 +3109,7 @@ static void redraw_timer_step(bContext *C, for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) { if (ar_iter->visible) { CTX_wm_region_set(C, ar_iter); - ED_region_do_draw(C, ar_iter); - ar_iter->do_draw = false; + wm_draw_region_test(C, sa_iter, ar_iter); } } } @@ -3153,6 +3154,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); + wmWindowManager *wm = CTX_wm_manager(C); double time_start, time_delta; const int type = RNA_enum_get(op->ptr, "type"); const int iter = RNA_int_get(op->ptr, "iterations"); @@ -3166,6 +3168,8 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) time_start = PIL_check_seconds_timer(); + wm_window_make_drawable(wm, win); + for (a = 0; a < iter; a++) { redraw_timer_step(C, bmain, scene, depsgraph, win, sa, ar, type, cfra); iter_steps += 1; @@ -3504,6 +3508,8 @@ void wm_operatortypes_register(void) WM_operatortype_append(WM_OT_read_factory_settings); WM_operatortype_append(WM_OT_save_homefile); WM_operatortype_append(WM_OT_save_userpref); + WM_operatortype_append(WM_OT_read_userpref); + WM_operatortype_append(WM_OT_read_factory_userpref); WM_operatortype_append(WM_OT_userpref_autoexec_path_add); WM_operatortype_append(WM_OT_userpref_autoexec_path_remove); WM_operatortype_append(WM_OT_window_fullscreen_toggle); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 844316bc925..7cc44bcad99 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -1063,7 +1063,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) break; } - case GHOST_kEventQuit: + case GHOST_kEventQuitRequest: case GHOST_kEventWindowClose: { ps->go = false; break; diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index f429415bee9..3ea58d8c4e5 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -574,6 +574,20 @@ void WM_toolsystem_refresh_active(bContext *C) } } } + + BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT); + + LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) { + if (workspace->id.tag & LIB_TAG_DOIT) { + workspace->id.tag &= ~LIB_TAG_DOIT; + /* Refresh to ensure data is initialized. + * This is needed because undo can load a state which no longer has the underlying DNA data + * needed for the tool (un-initialized paint-slots for eg), see: T64339. */ + for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) { + toolsystem_refresh_ref(C, workspace, tref); + } + } + } } void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa) @@ -712,7 +726,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case SPACE_IMAGE: switch (tkey->mode) { case SI_MODE_PAINT: - return "builtin_brush.draw"; + return "builtin_brush.Draw"; } break; case SPACE_NODE: { diff --git a/source/blender/windowmanager/intern/wm_utils.c b/source/blender/windowmanager/intern/wm_utils.c new file mode 100644 index 00000000000..c0ee1ec44db --- /dev/null +++ b/source/blender/windowmanager/intern/wm_utils.c @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + * + * Generic helper utilies that aren't assosiated with a particular area. + */ + +#include "WM_types.h" +#include "WM_api.h" + +#include "MEM_guardedalloc.h" + +/* -------------------------------------------------------------------- */ +/** \name Generic Callback + * \{ */ + +void WM_generic_callback_free(wmGenericCallback *callback) +{ + if (callback->free_user_data) { + callback->free_user_data(callback->user_data); + } + MEM_freeN(callback); +} + +static void do_nothing(struct bContext *UNUSED(C), void *UNUSED(user_data)) +{ +} + +wmGenericCallback *WM_generic_callback_steal(wmGenericCallback *callback) +{ + wmGenericCallback *new_callback = MEM_dupallocN(callback); + callback->exec = do_nothing; + callback->free_user_data = NULL; + callback->user_data = NULL; + return new_callback; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generic User Data + * \{ */ + +void WM_generic_user_data_free(wmGenericUserData *wm_userdata) +{ + if (wm_userdata->data && wm_userdata->use_free) { + if (wm_userdata->free_fn) { + wm_userdata->free_fn(wm_userdata->data); + } + else { + MEM_freeN(wm_userdata->data); + } + } +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index e98067d78cc..7ae572e5685 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -61,6 +61,7 @@ #include "WM_types.h" #include "wm.h" #include "wm_draw.h" +#include "wm_files.h" #include "wm_window.h" #include "wm_event_system.h" @@ -356,150 +357,9 @@ wmWindow *wm_window_copy_test(bContext *C, /** \name Quit Confirmation Dialog * \{ */ -/** Cancel quitting and close the dialog */ -static void wm_block_confirm_quit_cancel(bContext *C, void *arg_block, void *UNUSED(arg)) +static void wm_save_file_on_quit_dialog_callback(bContext *C, void *UNUSED(user_data)) { - wmWindow *win = CTX_wm_window(C); - UI_popup_block_close(C, win, arg_block); -} - -/** Discard the file changes and quit */ -ATTR_NORETURN -static void wm_block_confirm_quit_discard(bContext *C, void *arg_block, void *UNUSED(arg)) -{ - wmWindow *win = CTX_wm_window(C); - UI_popup_block_close(C, win, arg_block); - WM_exit(C); -} - -/* Save changes and quit */ -static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSED(arg)) -{ - PointerRNA props_ptr; - wmWindow *win = CTX_wm_window(C); - - UI_popup_block_close(C, win, arg_block); - - wmOperatorType *ot = WM_operatortype_find("WM_OT_save_mainfile", false); - - WM_operator_properties_create_ptr(&props_ptr, ot); - RNA_boolean_set(&props_ptr, "exit", true); - /* No need for second confirmation popup. */ - RNA_boolean_set(&props_ptr, "check_existing", false); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); - WM_operator_properties_free(&props_ptr); -} - -/* Build the confirm dialog UI */ -static uiBlock *block_create_confirm_quit(struct bContext *C, - struct ARegion *ar, - void *UNUSED(arg1)) -{ - Main *bmain = CTX_data_main(C); - - uiStyle *style = UI_style_get(); - uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS); - - UI_block_flag_enable( - block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); - UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - UI_block_emboss_set(block, UI_EMBOSS); - - uiLayout *layout = UI_block_layout(block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - 10, - 2, - U.widget_unit * 24, - U.widget_unit * 6, - 0, - style); - - /* Text and some vertical space */ - { - char *message; - if (BKE_main_blendfile_path(bmain)[0] == '\0') { - message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?")); - } - else { - const char *basename = BLI_path_basename(BKE_main_blendfile_path(bmain)); - message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename); - } - uiItemL(layout, message, ICON_ERROR); - MEM_freeN(message); - } - - uiItemS(layout); - uiItemS(layout); - - /* Buttons */ - uiBut *but; - - uiLayout *split = uiLayoutSplit(layout, 0.0f, true); - - uiLayout *col = uiLayoutColumn(split, false); - - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_SCREEN_BACK, - IFACE_("Cancel"), - 0, - 0, - 0, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Do not quit")); - UI_but_func_set(but, wm_block_confirm_quit_cancel, block, NULL); - - /* empty space between buttons */ - col = uiLayoutColumn(split, false); - uiItemS(col); - - col = uiLayoutColumn(split, 1); - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_CANCEL, - IFACE_("Discard Changes"), - 0, - 0, - 50, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Discard changes and quit")); - UI_but_func_set(but, wm_block_confirm_quit_discard, block, NULL); - - col = uiLayoutColumn(split, 1); - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_FILE_TICK, - IFACE_("Save & Quit"), - 0, - 0, - 50, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Save and quit")); - UI_but_func_set(but, wm_block_confirm_quit_save, block, NULL); - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); - - UI_block_bounds_set_centered(block, 10); - - return block; + wm_exit_schedule_delayed(C); } /** @@ -508,16 +368,9 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, */ static void wm_confirm_quit(bContext *C) { - wmWindow *win = CTX_wm_window(C); - - if (GHOST_SupportsNativeDialogs() == 0) { - if (!UI_popup_block_name_exists(C, "confirm_quit_popup")) { - UI_popup_block_invoke(C, block_create_confirm_quit, NULL); - } - } - else if (GHOST_confirmQuit(win->ghostwin)) { - wm_exit_schedule_delayed(C); - } + wmGenericCallback *action = MEM_callocN(sizeof(*action), __func__); + action->exec = wm_save_file_on_quit_dialog_callback; + wm_close_file_dialog(C, action); } /** @@ -529,7 +382,6 @@ static void wm_confirm_quit(bContext *C) */ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) { - wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_ctx = CTX_wm_window(C); /* The popup will be displayed in the context window which may not be set @@ -537,7 +389,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) CTX_wm_window_set(C, win); if (U.uiflag & USER_SAVE_PROMPT) { - if (!wm->file_saved && !G.background) { + if (wm_file_or_image_is_modified(C) && !G.background) { wm_confirm_quit(C); } else { @@ -672,6 +524,7 @@ void WM_window_set_dpi(wmWindow *win) U.dpi = dpi / pixelsize; U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; U.dpi_fac = ((U.pixelsize * (float)U.dpi) / 72.0f); + U.inv_dpi_fac = 1.0f / U.dpi_fac; /* Set user preferences globals for drawing, and for forward compatibility. */ U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; @@ -1264,8 +1117,25 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr GHOST_TEventType type = GHOST_GetEventType(evt); int time = GHOST_GetEventTime(evt); - if (type == GHOST_kEventQuit) { - WM_exit(C); + if (type == GHOST_kEventQuitRequest) { + /* Find an active window to display quit dialog in. */ + GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt); + wmWindow *win; + + if (ghostwin && GHOST_ValidWindow(g_system, ghostwin)) { + win = GHOST_GetWindowUserData(ghostwin); + } + else { + win = wm->winactive; + } + + /* Display quit dialog or quit immediately. */ + if (win) { + wm_quit_with_optional_confirmation_prompt(C, win); + } + else { + wm_exit_schedule_delayed(C); + } } else { GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt); diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index ede2b3191b9..0a07eb998cf 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -38,6 +38,7 @@ typedef struct wmDrawBuffer { } wmDrawBuffer; struct ARegion; +struct ScrArea; struct bContext; struct wmWindow; @@ -45,6 +46,7 @@ struct wmWindow; void wm_draw_update(struct bContext *C); void wm_draw_region_clear(struct wmWindow *win, struct ARegion *ar); void wm_draw_region_blend(struct ARegion *ar, int view, bool blend); +void wm_draw_region_test(struct bContext *C, struct ScrArea *sa, struct ARegion *ar); struct GPUTexture *wm_draw_region_texture(struct ARegion *ar, int view); diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index c60df27e24b..0aa4357a8f4 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -25,6 +25,7 @@ #define __WM_FILES_H__ struct Main; +struct wmGenericCallback; struct wmOperatorType; /* wm_files.c */ @@ -33,16 +34,22 @@ void wm_homefile_read(struct bContext *C, struct ReportList *reports, bool use_factory_settings, bool use_empty_data, + bool use_data, bool use_userdef, const char *filepath_startup_override, const char *app_template_override, bool *r_is_factory_startup); void wm_file_read_report(bContext *C, struct Main *bmain); +void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); +bool wm_file_or_image_is_modified(const struct bContext *C); + void WM_OT_save_homefile(struct wmOperatorType *ot); void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot); void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot); void WM_OT_save_userpref(struct wmOperatorType *ot); +void WM_OT_read_userpref(struct wmOperatorType *ot); +void WM_OT_read_factory_userpref(struct wmOperatorType *ot); void WM_OT_read_history(struct wmOperatorType *ot); void WM_OT_read_homefile(struct wmOperatorType *ot); void WM_OT_read_factory_settings(struct wmOperatorType *ot); |