diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2018-01-28 15:34:02 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2018-01-28 16:18:10 +0300 |
commit | 49c19ca679ea89209a18374d51377084f378f289 (patch) | |
tree | 7111a90a709920ed09386d0f1e8c00aaa8905ad7 /source/blender | |
parent | e15dd419d43182f9b826210e9ae90803cb7626a4 (diff) | |
parent | dfbe4153721b6764a41c2e8de8f41c6cdab6fe7e (diff) |
Merge branch 'blender2.8' into hair_guides
Diffstat (limited to 'source/blender')
153 files changed, 4474 insertions, 2801 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 27223afe4ff..ceb466ebdcd 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 280 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index cb72f0859d5..b3122f8adb9 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -46,7 +46,7 @@ struct MFace; typedef struct LinkNode BVHCache; /** - * struct that kepts basic information about a BVHTree build from a editmesh + * Struct that stores basic information about a BVHTree built from a edit-mesh. */ typedef struct BVHTreeFromEditMesh { struct BVHTree *tree; @@ -66,7 +66,7 @@ typedef struct BVHTreeFromEditMesh { } BVHTreeFromEditMesh; /** - * struct that kepts basic information about a BVHTree build from a mesh + * Struct that stores basic information about a BVHTree built from a mesh. */ typedef struct BVHTreeFromMesh { struct BVHTree *tree; diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 055c530d255..02912739e86 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -32,6 +32,10 @@ #include "BLI_compiler_attrs.h" +#ifdef __cplusplus +extern "C" { +#endif + struct IDProperty; struct ID; @@ -119,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop); void IDP_RelinkProperty(struct IDProperty *prop); +void IDP_Reset(IDProperty *prop, const IDProperty *reference); + #define IDP_Int(prop) ((prop)->data.val) #define IDP_Array(prop) ((prop)->data.pointer) /* C11 const correctness for casts */ @@ -151,4 +157,8 @@ void IDP_RelinkProperty(struct IDProperty *prop); void IDP_spit(IDProperty *prop); #endif +#ifdef __cplusplus +} +#endif + #endif /* __BKE_IDPROP_H__ */ diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 77f760a7843..b605b208f66 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -33,7 +33,6 @@ extern "C" { #endif -#define TODO_LAYER_SYNC_FILTER /* syncing of filter_objects across all trees */ #define TODO_LAYER_OVERRIDE /* CollectionOverride */ #define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */ #define TODO_LAYER /* generic todo */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 30889b2f145..5abf9139226 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -51,9 +51,9 @@ struct PointerRNA; struct PropertyRNA; size_t BKE_libblock_get_alloc_info(short type, const char **name); -void *BKE_libblock_alloc_notest(short type); -void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BKE_libblock_init_empty(struct ID *id); +void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT; +void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1); /** * New ID creation/copying options. diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 3156749070e..4e30cb076d4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -448,6 +448,7 @@ struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree, struct bNode struct bNodeSocket *next_sock, const char *identifier, const char *name); void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void nodeRemoveAllSockets(struct bNodeTree *ntree, struct bNode *node); +void nodeModifySocketType(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock, int type, int subtype); struct bNode *nodeAddNode(const struct bContext *C, struct bNodeTree *ntree, const char *idname); struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type); @@ -799,6 +800,7 @@ struct ShadeResult; #define SH_NODE_BSDF_PRINCIPLED 193 #define SH_NODE_EEVEE_SPECULAR 195 #define SH_NODE_BEVEL 197 +#define SH_NODE_DISPLACEMENT 198 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index edd29f793ec..ca77969ccaa 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -117,13 +117,9 @@ static void collection_free(SceneCollection *sc, const bool do_id_user) for (LinkData *link = sc->objects.first; link; link = link->next) { id_us_min(link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - id_us_min(link->data); - } } BLI_freelistN(&sc->objects); - BLI_freelistN(&sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { collection_free(nsc, do_id_user); @@ -265,13 +261,6 @@ void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, } } - BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects); - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) { - id_us_plus(link->data); - } - } - BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections); for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first; nsc_src; @@ -404,7 +393,6 @@ bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc BLI_remlink(&sc->objects, link); MEM_freeN(link); - TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ BKE_layer_sync_object_unlink(owner_id, sc, ob); if (GS(owner_id->name) == ID_SCE) { diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b00a62a1a87..33a665ba06e 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1094,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop) prop->len = prop->totallen = 0; } +void IDP_Reset(IDProperty *prop, const IDProperty *reference) +{ + if (prop == NULL) { + return; + } + IDP_ClearProperty(prop); + if (reference != NULL) { + IDP_MergeGroup(prop, reference, true); + } +} + /** \} */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index c63cefbcd8c..c6515d0c47a 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -99,7 +99,7 @@ ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const st /** * This is a placeholder to know which areas of the code need to be addressed for the Workspace changes. - * Never use this, you should either use BKE_view_layer_workspace_active or get ViewLayer explicitly. + * Never use this, you should either use BKE_view_layer_from_workspace_get or get ViewLayer explicitly. */ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) { @@ -1042,9 +1042,7 @@ static void layer_collection_object_add(ViewLayer *view_layer, LayerCollection * { Base *base = object_base_add(view_layer, ob); - /* Only add an object once - prevent SceneCollection->objects and - * SceneCollection->filter_objects to add the same object. */ - + /* Only add an object once. */ if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { return; } @@ -1085,7 +1083,6 @@ static void layer_collection_objects_populate(ViewLayer *view_layer, LayerCollec static void layer_collection_populate(ViewLayer *view_layer, LayerCollection *lc, SceneCollection *sc) { layer_collection_objects_populate(view_layer, lc, &sc->objects); - layer_collection_objects_populate(view_layer, lc, &sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { layer_collection_add(view_layer, lc, nsc); @@ -1195,7 +1192,6 @@ void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object /** * Remove the equivalent object base to all layers that have this collection - * also remove all reference to ob in the filter_objects */ void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index fde8bd06563..da765ca45af 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -450,10 +450,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (LinkData *link = sc->objects.first; link; link = link->next) { CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); } - - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); - } } FOREACH_SCENE_COLLECTION_END diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 8d1d657fbd9..87e45990a6c 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -207,9 +207,11 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id id->tag |= LIB_TAG_DOIT; } - /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ + /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL + * (otherwise, we follow common NEVER_NULL flags). + * (skipped_indirect too). */ if ((is_never_null && skip_never_null) || - (is_obj_editmode && (((Object *)id)->data == *id_p)) || + (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) || (skip_indirect && is_indirect) || (is_reference && skip_reference)) { diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c index d5dbbe873a2..057b6aaaf65 100644 --- a/source/blender/blenkernel/intern/lightprobe.c +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -52,6 +52,7 @@ void BKE_lightprobe_init(LightProbe *probe) probe->clipend = 40.0f; probe->vis_bias = 1.0f; probe->vis_blur = 0.2f; + probe->intensity = 1.0f; probe->data_draw_size = 1.0f; probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 8eb1a7733c1..8bfeacd256c 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -434,6 +434,11 @@ bool modifiers_isParticleEnabled(Object *ob) return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } +/** + * Check whether is enabled. + * + * \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called. + */ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -441,7 +446,7 @@ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode md->scene = scene; if ((md->mode & required_mode) != required_mode) return false; - if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; + if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; if (md->mode & eModifierMode_DisableTemporary) return false; if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index ab9e2665ff0..cac2aab26dd 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -506,6 +506,26 @@ static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_ou return sock; } +void nodeModifySocketType(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, + int type, int subtype) +{ + const char *idname = nodeStaticSocketType(type, subtype); + + if (!idname) { + printf("Error: static node socket type %d undefined\n", type); + return; + } + + if (sock->default_value) { + MEM_freeN(sock->default_value); + sock->default_value = NULL; + } + + sock->type = type; + BLI_strncpy(sock->idname, idname, sizeof(sock->idname)); + node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname)); +} + bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname, const char *identifier, const char *name) { @@ -3569,6 +3589,7 @@ static void registerShaderNodes(void) register_node_type_sh_attribute(); register_node_type_sh_bevel(); + register_node_type_sh_displacement(); register_node_type_sh_geometry(); register_node_type_sh_light_path(); register_node_type_sh_light_falloff(); diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index fb8aebe3004..99291b14b88 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -446,10 +446,14 @@ void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx), Object *object, Base *base, bool is_from_set) { DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + /* Make sure we have the base collection settings is already populated. - * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet - * Which usually means a missing call to DEG_id_tag_update(). */ + * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet. + * + * Which usually means a missing call to DEG_id_tag_update(id, DEG_TAG_BASE_FLAGS_UPDATE). + * Either of the entire scene, or of the newly added objects.*/ BLI_assert(!BLI_listbase_is_empty(&base->collection_properties->data.group)); + /* Copy flags and settings from base. */ object->base_flag = base->flag; if (is_from_set) { diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 6bd88099792..754f59d2e33 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -429,6 +429,9 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->areabase); BKE_previewimg_free(&sc->preview); + + /* Region and timer are freed by the window manager. */ + MEM_SAFE_FREE(sc->tool_tip); } /* for depsgraph */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 1b8939db185..424f4269f3c 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -4505,7 +4505,8 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame) /* Only use strips that generate an image, not ones that combine * other strips or apply some effect. */ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, - SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR, SEQ_TYPE_TEXT)) { + SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR, SEQ_TYPE_TEXT)) + { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 4e887d21f4f..618f495dbf1 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -175,7 +175,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) settings.userdata_chunk = &nearest; settings.userdata_chunk_size = sizeof(nearest); BLI_task_parallel_range(0, calc->numVerts, - &data,shrinkwrap_calc_nearest_vertex_cb_ex, + &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings); free_bvhtree_from_mesh(&treeData); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 5e2fb220327..1c3ff352126 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -67,6 +67,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_scene.h" @@ -1552,7 +1553,7 @@ static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop) BLI_edgehash_insert(ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i)); } - atomic_cas_ptr((void**)&ccgdm->ehash, ccgdm->ehash, ehash); + atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash); } BLI_mutex_unlock(&ccgdm->loops_cache_lock); } @@ -4190,7 +4191,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGKey key; - int numGrids, grid_pbvh; + int numGrids; CCG_key_top_level(&key, ccgdm->ss); @@ -4202,35 +4203,85 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (!ob->sculpt) return NULL; - /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ - grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); + bool grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); + if ((ob->mode & OB_MODE_SCULPT) == 0) { + /* In vwpaint, we may use a grid_pbvh for multires/subsurf, under certain conditions. + * More complex cases break 'history' trail back to original vertices, in that case we fall back to + * deformed cage only (i.e. original deformed mesh). */ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + + grid_pbvh = true; + bool has_one_ccg_modifier = false; + for (; md; md = md->next) { + /* We can only accept to use this ccgdm if: + * - it's the only active ccgdm in the stack. + * - there is no topology-modifying modifier in the stack. + * Otherwise, there is no way to map back to original geometry from grid-generated PBVH. + */ + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (!modifier_isEnabled(NULL, md, eModifierMode_Realtime)) { + continue; + } + if (ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical)) { + continue; + } + + if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) { + if (has_one_ccg_modifier) { + /* We only allow a single active ccg modifier in the stack. */ + grid_pbvh = false; + break; + } + has_one_ccg_modifier = true; + continue; + } + + /* Any other non-deforming modifier makes it impossible to use grid pbvh. */ + grid_pbvh = false; + break; + } + } if (ob->sculpt->pbvh) { + /* Note that we have to clean up exisitng pbvh instead of updating it in case it does not match current + * grid_pbvh status. */ if (grid_pbvh) { - /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm - * but this can be freed on ccgdm release, this updates the pointers - * when the ccgdm gets remade, the assumption is that the topology - * does not change. */ - ccgdm_create_grids(dm); - BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, - ccgdm->gridFlagMats, ccgdm->gridHidden); + if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) { + /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm + * but this can be freed on ccgdm release, this updates the pointers + * when the ccgdm gets remade, the assumption is that the topology + * does not change. */ + ccgdm_create_grids(dm); + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, + ccgdm->gridFlagMats, ccgdm->gridHidden); + } + else { + BKE_pbvh_free(ob->sculpt->pbvh); + ob->sculpt->pbvh = NULL; + } + } + else if (BKE_pbvh_get_ccgdm(ob->sculpt->pbvh) != NULL) { + BKE_pbvh_free(ob->sculpt->pbvh); + ob->sculpt->pbvh = NULL; } ccgdm->pbvh = ob->sculpt->pbvh; } if (ccgdm->pbvh) { - /* For vertex paint, keep track of ccgdm */ - if (!(ob->mode & OB_MODE_SCULPT)) { + /* For grid pbvh, keep track of ccgdm */ + if (grid_pbvh) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; } - /* no pbvh exists yet, we need to create one. only in case of multires + /* No pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ - /* Note: vwpaint always builds a pbvh over the modified mesh. */ + /* Note: vwpaint tries to always build a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); @@ -4256,6 +4307,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata, looptri, looptris_num); + + if (ob->sculpt->modifiers_active && ob->derivedDeform != NULL) { + DerivedMesh *deformdm = ob->derivedDeform; + float (*vertCos)[3]; + int totvert; + + totvert = deformdm->getNumVerts(deformdm); + vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos"); + deformdm->getVertCos(deformdm, vertCos); + BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos); + MEM_freeN(vertCos); + } } if (ccgdm->pbvh != NULL) { @@ -4263,8 +4326,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) pbvh_show_mask_set(ccgdm->pbvh, ob->sculpt->show_mask); } - /* For vertex paint, keep track of ccgdm */ - if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { + /* For grid pbvh, keep track of ccgdm. */ + if (grid_pbvh && ccgdm->pbvh) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 1285e24e567..d03010af8d2 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -182,7 +182,7 @@ typedef struct ParallelRangeSettings { } ParallelRangeSettings; BLI_INLINE void BLI_parallel_range_settings_defaults( - ParallelRangeSettings* settings); + ParallelRangeSettings *settings); void BLI_task_parallel_range( const int start, const int stop, @@ -210,7 +210,7 @@ void BLI_task_parallel_mempool( /* TODO(sergey): Think of a better place for this. */ BLI_INLINE void BLI_parallel_range_settings_defaults( - ParallelRangeSettings* settings) + ParallelRangeSettings *settings) { memset(settings, 0, sizeof(*settings)); settings->use_threading = true; diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 55667d19f76..9c055a227a9 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -875,7 +875,7 @@ static void non_recursive_bvh_div_nodes_task_cb( * to use multithread building. * * To archive this is necessary to find how much leafs are accessible from a certain branch, BVHBuildHelper - * implicit_needed_branches and implicit_leafs_index are auxiliary functions to solve that "optimal-split". + * #implicit_needed_branches and #implicit_leafs_index are auxiliary functions to solve that "optimal-split". */ static void non_recursive_bvh_div_nodes( const BVHTree *tree, BVHNode *branches_array, BVHNode **leafs_array, int num_leafs) @@ -888,24 +888,23 @@ static void non_recursive_bvh_div_nodes( BVHBuildHelper data; int depth; - - /* set parent from root node to NULL */ - BVHNode *tmp = &branches_array[0]; - tmp->parent = NULL; - - /* Most of bvhtree code relies on 1-leaf trees having at least one branch - * We handle that special case here */ - if (num_leafs == 1) { - BVHNode *root = &branches_array[0]; - refit_kdop_hull(tree, root, 0, num_leafs); - root->main_axis = get_largest_axis(root->bv) / 2; - root->totnode = 1; - root->children[0] = leafs_array[0]; - root->children[0]->parent = root; - return; - } - branches_array--; /* Implicit trees use 1-based indexs */ + { + /* set parent from root node to NULL */ + BVHNode *root = &branches_array[1]; + root->parent = NULL; + + /* Most of bvhtree code relies on 1-leaf trees having at least one branch + * We handle that special case here */ + if (num_leafs == 1) { + refit_kdop_hull(tree, root, 0, num_leafs); + root->main_axis = get_largest_axis(root->bv) / 2; + root->totnode = 1; + root->children[0] = leafs_array[0]; + root->children[0]->parent = root; + return; + } + } build_implicit_tree_helper(tree, &data); @@ -1053,9 +1052,6 @@ void BLI_bvhtree_free(BVHTree *tree) void BLI_bvhtree_balance(BVHTree *tree) { - int i; - - BVHNode *branches_array = tree->nodearray + tree->totleaf; BVHNode **leafs_array = tree->nodes; /* This function should only be called once @@ -1063,13 +1059,14 @@ void BLI_bvhtree_balance(BVHTree *tree) BLI_assert(tree->totbranch == 0); /* Build the implicit tree */ - non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf); + non_recursive_bvh_div_nodes(tree, tree->nodearray + (tree->totleaf - 1), leafs_array, tree->totleaf); /* current code expects the branches to be linked to the nodes array * we perform that linkage here */ tree->totbranch = implicit_needed_branches(tree->tree_type, tree->totleaf); - for (i = 0; i < tree->totbranch; i++) - tree->nodes[tree->totleaf + i] = branches_array + i; + for (int i = 0; i < tree->totbranch; i++) { + tree->nodes[tree->totleaf + i] = &tree->nodearray[tree->totleaf + i]; + } #ifdef USE_SKIP_LINKS build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL); diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index a0c13e14e72..2f5b0f420b1 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -399,7 +399,7 @@ MINLINE int integer_digits_d(const double d) MINLINE int integer_digits_i(const int i) { - return (int)log10(i) + 1; + return (int)log10((double)i) + 1; } /* Internal helpers for SSE2 implementation. diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2e7d22cc4cd..9fd1c80a66a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5879,11 +5879,6 @@ static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollectio BLI_assert(link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - link->data = newlibadr_us(fd, lib, link->data); - BLI_assert(link->data); - } - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { lib_link_scene_collection(fd, lib, nsc); } @@ -6168,7 +6163,6 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi static void direct_link_scene_collection(FileData *fd, SceneCollection *sc) { link_list(fd, &sc->objects); - link_list(fd, &sc->filter_objects); link_list(fd, &sc->scene_collections); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { @@ -6702,6 +6696,7 @@ static void lib_link_screen(FileData *fd, Main *main) sc->scene = newlibadr(fd, sc->id.lib, sc->scene); sc->animtimer = NULL; /* saved in rare cases */ + sc->tool_tip = NULL; sc->scrubbing = false; for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { @@ -9999,10 +9994,6 @@ static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection expand_doit(fd, mainvar, link->data); } - for (LinkData *link = sc->filter_objects.first; link; link = link->next) { - expand_doit(fd, mainvar, link->data); - } - for (SceneCollection *nsc= sc->scene_collections.first; nsc; nsc = nsc->next) { expand_scene_collection(fd, mainvar, nsc); } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index b5530d90330..2f07ca43ff0 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -915,4 +915,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + { + if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) { + for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) { + probe->intensity = 1.0f; + } + } + } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ea305c72f01..3bd2f67ab86 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -710,8 +710,10 @@ static void write_iddata(void *wd, const ID *id) static void write_previews(WriteData *wd, const PreviewImage *prv_orig) { - /* Never write previews when doing memsave (i.e. undo/redo)! */ - if (prv_orig && !wd->current) { + /* Note we write previews also for undo steps. It takes up some memory, + * but not doing so would causes all previews to be re-rendered after + * undo which is too expensive. */ + if (prv_orig) { PreviewImage prv = *prv_orig; /* don't write out large previews if not requested */ @@ -2620,7 +2622,6 @@ static void write_scene_collection(WriteData *wd, SceneCollection *sc) writestruct(wd, DATA, SceneCollection, 1, sc); writelist(wd, DATA, LinkData, &sc->objects); - writelist(wd, DATA, LinkData, &sc->filter_objects); for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { write_scene_collection(wd, nsc); @@ -3919,6 +3920,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) memset(fg.pad, 0, sizeof(fg.pad)); memset(fg.filename, 0, sizeof(fg.filename)); memset(fg.build_hash, 0, sizeof(fg.build_hash)); + fg.pad1 = NULL; current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 99384be0299..18b2b4db2bf 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -2040,7 +2040,7 @@ static void adjust_offsets(BevelParams *bp) /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments, * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not - * obvious to users, who almost certainaly want clamping in this situation. + * obvious to users, who almost certainly want clamping in this situation. * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression * suite, where relative adjust maximum is about .6). */ if (!bp->limit_offset) { diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index 9c8b8fc25d6..8832e0fd577 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -55,9 +55,10 @@ static const char *bc_get_joint_name(T *node) } -ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) : +ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings) : TransformReader(conv), scene(sce), + view_layer(view_layer), unit_converter(conv), import_settings(import_settings), empty(NULL), @@ -411,7 +412,7 @@ Object *ArmatureImporter::get_empty_for_leaves() { if (empty) return empty; - empty = bc_add_object(scene, OB_EMPTY, NULL); + empty = bc_add_object(scene, view_layer, OB_EMPTY, NULL); empty->empty_drawtype = OB_EMPTY_SPHERE; return empty; @@ -586,7 +587,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) ob_arm = skin.set_armature(shared); } else { - ob_arm = skin.create_armature(scene); //once for every armature + ob_arm = skin.create_armature(scene, view_layer); //once for every armature } // enter armature edit mode diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index 17173f157e5..f260bb2307c 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -63,6 +63,7 @@ class ArmatureImporter : private TransformReader { private: Scene *scene; + ViewLayer *view_layer; UnitConverter *unit_converter; const ImportSettings *import_settings; @@ -137,7 +138,7 @@ private: TagsMap uid_tags_map; public: - ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings); + ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings); ~ArmatureImporter(); void add_root_joint(COLLADAFW::Node *node, Object *parent); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index d3e23f740c8..dfd662aa66c 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -108,8 +108,9 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set import_settings(import_settings), mImportStage(General), mContext(C), - armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), import_settings), - mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)), + view_layer(CTX_data_view_layer(mContext)), + armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C), view_layer, import_settings), + mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C), view_layer), anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) { } @@ -134,7 +135,7 @@ bool DocumentImporter::import() loader.registerExtraDataCallbackHandler(ehandler); // deselect all to select new objects - BKE_view_layer_base_deselect_all(CTX_data_view_layer(mContext)); + BKE_view_layer_base_deselect_all(view_layer); std::string mFilename = std::string(this->import_settings->filepath); const std::string encodedFilename = bc_url_encode(mFilename); @@ -380,7 +381,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera return NULL; } - Object *ob = bc_add_object(sce, OB_CAMERA, NULL); + Object *ob = bc_add_object(sce, view_layer, OB_CAMERA, NULL); Camera *cam = uid_camera_map[cam_uid]; Camera *old_cam = (Camera *)ob->data; ob->data = cam; @@ -396,7 +397,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce return NULL; } - Object *ob = bc_add_object(sce, OB_LAMP, NULL); + Object *ob = bc_add_object(sce, view_layer, OB_LAMP, NULL); Lamp *la = uid_lamp_map[lamp_uid]; Lamp *old_lamp = (Lamp *)ob->data; ob->data = la; @@ -512,7 +513,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if (parent_node == NULL && !is_library_node) { // A Joint on root level is a skeleton without root node. // Here we add the armature "on the fly": - par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str()); + par = bc_add_object(sce, view_layer, OB_ARMATURE, std::string("Armature").c_str()); objects_done->push_back(par); root_objects->push_back(par); object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par)); @@ -626,10 +627,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) { //Check if Object is armature, by checking if immediate child is a JOINT node. if (is_armature(node)) { - ob = bc_add_object(sce, OB_ARMATURE, name.c_str()); + ob = bc_add_object(sce, view_layer, OB_ARMATURE, name.c_str()); } else { - ob = bc_add_object(sce, OB_EMPTY, NULL); + ob = bc_add_object(sce, view_layer, OB_EMPTY, NULL); } objects_done->push_back(ob); if (parent_node == NULL) { diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index 62f76dbc022..fd61f3a68da 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -144,6 +144,7 @@ private: ImportStage mImportStage; bContext *mContext; + ViewLayer *view_layer; UnitConverter unit_converter; ArmatureImporter armature_importer; diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 87392352a48..5e7f92047d3 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -67,7 +67,7 @@ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettin bool EffectsExporter::hasEffects(Scene *sce) { - FOREACH_SCENE_OBJECT(scene, ob) + FOREACH_SCENE_OBJECT(sce, ob) { int a; for (a = 0; a < ob->totcol; a++) { diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 9c95d4de695..f8cd487c355 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -207,7 +207,11 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) } -MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) { +MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer): + unitconverter(unitconv), + scene(sce), + view_layer(view_layer), + armature_importer(arm) { } bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count) @@ -1141,7 +1145,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta const char *name = (id.length()) ? id.c_str() : NULL; // add object - Object *ob = bc_add_object(scene, OB_MESH, name); + Object *ob = bc_add_object(scene, view_layer, OB_MESH, name); bc_set_mark(ob); // used later for material assignement optimization diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h index e8ae934a393..f57f57e07a7 100644 --- a/source/blender/collada/MeshImporter.h +++ b/source/blender/collada/MeshImporter.h @@ -92,6 +92,8 @@ private: UnitConverter *unitconverter; Scene *scene; + ViewLayer *view_layer; + ArmatureImporter *armature_importer; std::map<std::string, std::string> mesh_geom_map; // needed for correct shape key naming @@ -159,7 +161,7 @@ private: public: - MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce); + MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer); virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid); diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index c29f1748efc..a2cb8237d08 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -159,9 +159,9 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co) } // called from write_controller -Object *SkinInfo::create_armature(Scene *scene) +Object *SkinInfo::create_armature(Scene *scene, ViewLayer *view_layer) { - ob_arm = bc_add_object(scene, OB_ARMATURE, NULL); + ob_arm = bc_add_object(scene, view_layer, OB_ARMATURE, NULL); return ob_arm; } diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h index e074f59cffc..a399bff9e3c 100644 --- a/source/blender/collada/SkinInfo.h +++ b/source/blender/collada/SkinInfo.h @@ -99,7 +99,7 @@ public: void set_controller(const COLLADAFW::SkinController* co); // called from write_controller - Object *create_armature(Scene *scene); + Object *create_armature(Scene *scene, ViewLayer *view_layer); Object* set_armature(Object *ob_arm); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 6a52027fb47..f351ebf7952 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -135,7 +135,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space) return true; } -Object *bc_add_object(Scene *scene, int type, const char *name) +Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name) { Object *ob = BKE_object_add_only_object(G.main, type, name); @@ -143,9 +143,6 @@ Object *bc_add_object(Scene *scene, int type, const char *name) ob->lay = scene->lay; DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - /* XXX Collada should use the context scene layer, not the scene one. (dfelinto/gaia). */ - ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene); - LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob); diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h index 75e9fb5dcea..5d6e836b9c3 100644 --- a/source/blender/collada/collada_utils.h +++ b/source/blender/collada/collada_utils.h @@ -67,7 +67,7 @@ typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureA extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index); extern int bc_test_parent_loop(Object *par, Object *ob); extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true); -extern Object *bc_add_object(Scene *scene, int type, const char *name); +extern Object *bc_add_object(Scene *scene, ViewLayer *view_layer, int type, const char *name); extern Mesh *bc_get_mesh_copy(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate); extern Object *bc_get_assigned_armature(Object *ob); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index c89c436cb6a..04a72f85a78 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -992,6 +992,18 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id) graph_->add_new_relation(operation_from, operation_to, "Animation -> Prop", true); + /* It is possible that animation is writing to a nested ID datablock, + * need to make sure animation is evaluated after target ID is copied. + */ + if (DEG_depsgraph_use_copy_on_write()) { + const IDDepsNode *id_node_from = operation_from->owner->owner; + const IDDepsNode *id_node_to = operation_to->owner->owner; + if (id_node_from != id_node_to) { + ComponentKey cow_key(id_node_to->id_orig, + DEG_NODE_TYPE_COPY_ON_WRITE); + add_relation(cow_key, adt_key, "Target CoW -> Animation", true); + } + } } } @@ -1011,7 +1023,6 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) /* create the driver's relations to targets */ build_driver(id, fcu); - /* Special case for array drivers: we can not multithread them because * of the way how they work internally: animation system will write the * whole array back to RNA even when changing individual array value. @@ -1142,6 +1153,25 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) else { RNAPathKey target_key(id, rna_path); add_relation(driver_key, target_key, "Driver -> Target"); + /* Similar to the case with f-curves, driver might drive a nested + * datablock, which means driver execution should wait for that + * datablock to be copied. + */ + if (DEG_depsgraph_use_copy_on_write()) { + PointerRNA id_ptr; + PointerRNA ptr; + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { + if (id_ptr.id.data != ptr.id.data) { + ComponentKey cow_key((ID *)ptr.id.data, + DEG_NODE_TYPE_COPY_ON_WRITE); + add_relation(cow_key, + driver_key, + "Target CoW -> Driver", + true); + } + } + } } } diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 42d512d473c..30c9d9f10be 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -58,6 +58,30 @@ extern "C" { /* ************************ DEG ITERATORS ********************* */ +static void verify_id_proeprties_freed(DEGObjectIterData *data) +{ + if (data->dupli_object_current == NULL) { + // We didn't enter duplication yet, so we can't have any dangling + // pointers. + return; + } + const Object *dupli_object = data->dupli_object_current->ob; + Object *temp_dupli_object = &data->temp_dupli_object; + if (temp_dupli_object->id.properties == NULL) { + // No ID proeprties in temp datablock -- no leak is possible. + return; + } + if (temp_dupli_object->id.properties == dupli_object->id.properties) { + // Temp copy of object did not modify ID properties. + return; + } + // 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; +} + static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; @@ -78,6 +102,8 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) continue; } + verify_id_proeprties_freed(data); + data->dupli_object_current = dob; /* Temporary object to evaluate. */ @@ -90,10 +116,13 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) if (dob->collection_properties != NULL) { temp_dupli_object->base_collection_properties = dob->collection_properties; - IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false); + IDP_MergeGroup(temp_dupli_object->base_collection_properties, + dupli_parent->base_collection_properties, + false); } else { - temp_dupli_object->base_collection_properties = dupli_parent->base_collection_properties; + temp_dupli_object->base_collection_properties = + dupli_parent->base_collection_properties; } copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); @@ -146,15 +175,16 @@ static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_no return; } - if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { + if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && + (object->transflag & OB_DUPLI)) + { data->dupli_parent = object; data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); data->dupli_object_next = (DupliObject *)data->dupli_list->first; - - const eObjectVisibilityCheck mode = (data->mode == DEG_ITER_OBJECT_MODE_RENDER) ? - OB_VISIBILITY_CHECK_FOR_RENDER : - OB_VISIBILITY_CHECK_FOR_VIEWPORT; - + const eObjectVisibilityCheck mode = + (data->mode == DEG_ITER_OBJECT_MODE_RENDER) + ? OB_VISIBILITY_CHECK_FOR_RENDER + : OB_VISIBILITY_CHECK_FOR_VIEWPORT; if (BKE_object_is_visible(object, mode) == false) { return; } @@ -211,6 +241,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) return; } else { + verify_id_proeprties_freed(data); free_object_duplilist(data->dupli_list); data->dupli_parent = NULL; data->dupli_list = NULL; @@ -234,7 +265,9 @@ void DEG_iterator_objects_end(BLI_Iterator *iter) { #ifndef NDEBUG DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */ + /* Force crash in case the iterator data is referenced and accessed down + * the line. (T51718) + */ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); #else (void) iter; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index a8eea136409..e5c714cfd74 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -263,6 +263,47 @@ void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) deg_editors_id_update(&update_ctx, id); } +void depsgraph_tag_component(Depsgraph *graph, + IDDepsNode *id_node, + eDepsNode_Type component_type, + eDepsOperation_Code operation_code) +{ + ComponentDepsNode *component_node = + id_node->find_component(component_type); + if (component_node == NULL) { + return; + } + if (operation_code == DEG_OPCODE_OPERATION) { + component_node->tag_update(graph); + } + else { + OperationDepsNode *operation_node = + component_node->find_operation(operation_code); + if (operation_node != NULL) { + operation_node->tag_update(graph); + } + } +} + +/* This is a tag compatibility with legacy code. + * + * Mainly, old code was tagging object with OB_RECALC_DATA tag to inform + * that object's data datablock changed. Now API expects that ID is given + * explicitly, but not all areas are aware of this yet. + */ +void deg_graph_id_tag_legacy_compat(Main *bmain, + ID *id, + eDepsgraph_Tag tag) +{ + if (tag == DEG_TAG_GEOMETRY && GS(id->name) == ID_OB) { + Object *object = (Object *)id; + ID *data_id = (ID *)object->data; + if (data_id != NULL) { + DEG_id_tag_update_ex(bmain, data_id, 0); + } + } +} + void deg_graph_id_tag_update_single_flag(Main *bmain, Depsgraph *graph, ID *id, @@ -304,21 +345,13 @@ void deg_graph_id_tag_update_single_flag(Main *bmain, id_node->tag_update(graph); } else { - ComponentDepsNode *component_node = - id_node->find_component(component_type); - if (component_node != NULL) { - if (operation_code == DEG_OPCODE_OPERATION) { - component_node->tag_update(graph); - } - else { - OperationDepsNode *operation_node = - component_node->find_operation(operation_code); - if (operation_node != NULL) { - operation_node->tag_update(graph); - } - } - } + depsgraph_tag_component(graph, id_node, component_type, operation_code); } + /* TODO(sergey): Get rid of this once all areas are using proper data ID + * for tagging. + */ + deg_graph_id_tag_legacy_compat(bmain, id, tag); + } void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) @@ -347,6 +380,20 @@ void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) id_tag_update_ntree_special(bmain, graph, id, flag); } +/* TODO(sergey): Consider storing scene and view layer at depsgraph allocation + * time. + */ +void deg_ensure_scene_view_layer(Depsgraph *graph, + Scene *scene, + ViewLayer *view_layer) +{ + if (!graph->need_update) { + return; + } + graph->scene = scene; + graph->view_layer = view_layer; +} + void deg_id_tag_update(Main *bmain, ID *id, int flag) { deg_graph_id_tag_update(bmain, NULL, id, flag); @@ -357,6 +404,11 @@ void deg_id_tag_update(Main *bmain, ID *id, int flag) view_layer, false); if (depsgraph != NULL) { + /* Make sure depsgraph is pointing to a correct scene and + * view layer. This is mainly required in cases when depsgraph + * was not built yet. + */ + deg_ensure_scene_view_layer(depsgraph, scene, view_layer); deg_graph_id_tag_update(bmain, depsgraph, id, flag); } } 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 ff447b53b1e..a6668208574 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 @@ -46,6 +46,7 @@ #include "BLI_string.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" @@ -467,6 +468,137 @@ void update_special_pointers(const Depsgraph *depsgraph, } } +void update_copy_on_write_layer_collections( + ListBase *layer_collections_cow, + const ListBase *layer_collections_orig); + +void update_copy_on_write_layer_collection( + LayerCollection *layer_collection_cow, + const LayerCollection *layer_collection_orig) +{ + // Make a local copy of original layer collection, so we can start + // modifying it. + LayerCollection local = *layer_collection_orig; + // Copy all pointer data from original CoW version of layer collection. + local.next = layer_collection_cow->next; + local.prev = layer_collection_cow->prev; + local.scene_collection = layer_collection_cow->scene_collection; + local.object_bases = layer_collection_cow->object_bases; + local.overrides = layer_collection_cow->overrides; + local.layer_collections = layer_collection_cow->layer_collections; + local.properties = layer_collection_cow->properties; + local.properties_evaluated = layer_collection_cow->properties_evaluated; + // Synchronize pointer-related data. + IDP_Reset(local.properties, layer_collection_orig->properties); + // Copy synchronized version back. + *layer_collection_cow = local; + // Recurs into nested layer collections. + update_copy_on_write_layer_collections( + &layer_collection_cow->layer_collections, + &layer_collection_orig->layer_collections); +} + +void update_copy_on_write_layer_collections( + ListBase *layer_collections_cow, + const ListBase *layer_collections_orig) +{ + const LayerCollection *layer_collection_orig = + (const LayerCollection *)layer_collections_orig->first; + LayerCollection *layer_collection_cow = + (LayerCollection *)layer_collections_cow->first; + while (layer_collection_orig != NULL) { + update_copy_on_write_layer_collection(layer_collection_cow, + layer_collection_orig); + layer_collection_orig = layer_collection_orig->next; + layer_collection_cow = layer_collection_cow->next; + } +} + +void update_copy_on_write_view_layer(const Depsgraph *depsgraph, + ViewLayer *view_layer_cow, + const ViewLayer *view_layer_orig) +{ + // Update pointers to active base. + if (view_layer_orig->basact == NULL) { + view_layer_cow->basact = NULL; + } + else { + const Object *obact_orig = view_layer_orig->basact->object; + Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id); + view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow); + } + // Update base flags. + // + // TODO(sergey): We should probably check visibled/selectabled. + // flag here? + const Base *base_orig = (Base *)view_layer_orig->object_bases.first; + Base *base_cow = (Base *)view_layer_cow->object_bases.first;; + while (base_orig != NULL) { + base_cow->flag = base_orig->flag; + base_orig = base_orig->next; + base_cow = base_cow->next; + } + // Synchronize settings. + view_layer_cow->active_collection = view_layer_orig->active_collection; + view_layer_cow->flag = view_layer_orig->flag; + view_layer_cow->layflag = view_layer_orig->layflag; + view_layer_cow->passflag = view_layer_orig->passflag; + view_layer_cow->pass_alpha_threshold = view_layer_orig->pass_alpha_threshold; + // Synchronize ID properties. + IDP_Reset(view_layer_cow->properties, view_layer_orig->properties); + IDP_Reset(view_layer_cow->id_properties, view_layer_orig->id_properties); + // Synchronize layer collections. + update_copy_on_write_layer_collections( + &view_layer_cow->layer_collections, + &view_layer_orig->layer_collections); +} + +void update_copy_on_write_view_layers(const Depsgraph *depsgraph, + Scene *scene_cow, + const Scene *scene_orig) +{ + const ViewLayer *view_layer_orig = (const ViewLayer *)scene_orig->view_layers.first; + ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first; + while (view_layer_orig != NULL) { + update_copy_on_write_view_layer(depsgraph, + view_layer_cow, + view_layer_orig); + view_layer_orig = view_layer_orig->next; + view_layer_cow = view_layer_cow->next; + } +} + +void update_copy_on_write_scene_collections( + ListBase *collections_cow, + const ListBase *collections_orig); + +void update_copy_on_write_scene_collection( + SceneCollection *collection_cow, + const SceneCollection *collection_orig) +{ + collection_cow->active_object_index = collection_orig->active_object_index; + update_copy_on_write_scene_collections( + &collection_cow->scene_collections, + &collection_orig->scene_collections); +} + +void update_copy_on_write_scene_collections( + ListBase *collections_cow, + const ListBase *collections_orig) +{ + const SceneCollection *nested_collection_orig = + (const SceneCollection *)collections_orig->first; + SceneCollection *nested_collection_cow = + (SceneCollection *)collections_cow->first; + while (nested_collection_orig != NULL) { + update_copy_on_write_scene_collection( + nested_collection_cow, + nested_collection_orig); + nested_collection_orig = nested_collection_orig->next; + nested_collection_cow = nested_collection_cow->next; + } +} + /* Update copy-on-write version of scene from original scene. */ void update_copy_on_write_scene(const Depsgraph *depsgraph, Scene *scene_cow, @@ -476,33 +608,10 @@ void update_copy_on_write_scene(const Depsgraph *depsgraph, // TODO(sergey): Are we missing something here? scene_cow->r.cfra = scene_orig->r.cfra; scene_cow->r.subframe = scene_orig->r.subframe; - // Update bases. - const ViewLayer *view_layer_orig = (ViewLayer *)scene_orig->view_layers.first; - ViewLayer *view_layer_cow = (ViewLayer *)scene_cow->view_layers.first; - while (view_layer_orig != NULL) { - // Update pointers to active base. - if (view_layer_orig->basact == NULL) { - view_layer_cow->basact = NULL; - } - else { - const Object *obact_orig = view_layer_orig->basact->object; - Object *obact_cow = (Object *)depsgraph->get_cow_id(&obact_orig->id); - view_layer_cow->basact = BKE_view_layer_base_find(view_layer_cow, obact_cow); - } - // Update base flags. - // - // TODO(sergey): We should probably check visibled/selectabled - // flag here? - const Base *base_orig = (Base *)view_layer_orig->object_bases.first; - Base *base_cow = (Base *)view_layer_cow->object_bases.first;; - while (base_orig != NULL) { - base_cow->flag = base_orig->flag; - base_orig = base_orig->next; - base_cow = base_cow->next; - } - view_layer_orig = view_layer_orig->next; - view_layer_cow = view_layer_cow->next; - } + // Update view layers and collections. + update_copy_on_write_view_layers(depsgraph, scene_cow, scene_orig); + update_copy_on_write_scene_collection(scene_cow->collection, + scene_orig->collection); // Update edit object pointer. if (scene_orig->obedit != NULL) { scene_cow->obedit = (Object *)depsgraph->get_cow_id(&scene_orig->obedit->id); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 426b74e7d31..4dcc8dc081c 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -139,6 +139,7 @@ data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/concentric_samples_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/hair_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC) diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index fcd9353bf1f..a9a919f7ac2 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -183,6 +183,7 @@ typedef struct CLAY_PrivateData { DRWShadingGroup *depth_shgrp_cull; DRWShadingGroup *depth_shgrp_cull_select; DRWShadingGroup *depth_shgrp_cull_active; + bool enable_ao; } CLAY_PrivateData; /* Transient data */ /* Functions */ @@ -607,7 +608,7 @@ static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material * return id; } -static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo) +static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_needs_ao) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); @@ -622,6 +623,12 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo) float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation"); int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); + if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) && + (ssao_distance > 0.0)) + { + *r_needs_ao = true; + } + memset(r_ubo, 0x0, sizeof(*r_ubo)); r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); @@ -667,7 +674,7 @@ static DRWShadingGroup *CLAY_object_shgrp_get( DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps; CLAY_UBO_Material mat_ubo_test; - ubo_mat_from_object(ob, &mat_ubo_test); + ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao); int id = mat_in_ubo(stl->storage, &mat_ubo_test); @@ -712,6 +719,9 @@ static void clay_cache_init(void *vedata) stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); } + /* Disable AO unless a material needs it. */ + stl->g_data->enable_ao = false; + /* Depth Pass */ { psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); @@ -851,18 +861,25 @@ static void clay_cache_finish(void *vedata) static void clay_draw_scene(void *vedata) { - + CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); /* Pass 1 : Depth pre-pass */ - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); + if (stl->g_data->enable_ao) { + DRW_draw_pass(psl->depth_pass); + DRW_draw_pass(psl->depth_pass_cull); + } + else { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRW_pass_state_set(psl->clay_pass, state); + DRW_pass_state_set(psl->clay_pass_flat, state); + } /* Pass 2 : Duplicate depth */ /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ - if (DRW_state_is_fbo()) { + if (DRW_state_is_fbo() && stl->g_data->enable_ao) { /* attach temp textures */ DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0); diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index f34601ef7b6..0a052b12e93 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -55,6 +55,7 @@ static void eevee_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->probe_ubo); DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); + DRW_UBO_FREE_SAFE(sldata->common_ubo); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); @@ -62,9 +63,6 @@ static void eevee_view_layer_data_free(void *storage) DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool); DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); - - /* Volumetrics */ - MEM_SAFE_FREE(sldata->volumetrics); } static void eevee_lightprobe_data_free(void *storage) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index c09e180b36d..5821111c59d 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -102,6 +102,7 @@ static void eevee_create_shader_downsample(void) void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; @@ -156,7 +157,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type, - (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, + max_ii((int)viewport_size[0] / 2, 1), max_ii((int)viewport_size[1] / 2, 1), &texmax, 1); @@ -169,8 +170,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) mip_size[0] = floorf(fmaxf(1.0f, mip_size[0] / 2.0f)); mip_size[1] = floorf(fmaxf(1.0f, mip_size[1] / 2.0f)); } - stl->g_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0]))))); - stl->g_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1]))))); + common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, floorf(log2f(floorf(viewport_size[0] / mip_size[0]))))); + common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1]))))); } @@ -209,12 +210,10 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } } -void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_effects_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; int downsample_write = DRW_STATE_WRITE_DEPTH; /* Intel gpu seems to have problem rendering to only depth format. @@ -229,7 +228,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v 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_shgroup_uniform_buffer(grp, "source", &e_data.color_src); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); DRW_shgroup_call_add(grp, quad, NULL); } @@ -401,7 +400,7 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_ DRW_stats_group_end(); } -void EEVEE_draw_effects(EEVEE_Data *vedata) +void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; @@ -478,7 +477,7 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) } /* Record pers matrix for the next frame. */ - DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_get(sldata->common_data.prev_persmat, DRW_MAT_PERS); /* 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 2e7be2c29a5..fe2beb4b557 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -66,10 +66,14 @@ static void eevee_engine_init(void *ved) (int)viewport_size[0], (int)viewport_size[1], &tex, 1); + if (sldata->common_ubo == NULL) { + sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); + } + /* EEVEE_effects_init needs to go first for TAA */ EEVEE_effects_init(sldata, vedata); - EEVEE_materials_init(stl, fbl); + EEVEE_materials_init(sldata, stl, fbl); EEVEE_lights_init(sldata); EEVEE_lightprobes_init(sldata, vedata); @@ -188,6 +192,9 @@ static void eevee_draw_background(void *vedata) EEVEE_lightprobes_refresh(sldata, vedata); DRW_stats_group_end(); + /* Update common buffer after probe rendering. */ + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + /* Refresh shadows */ DRW_stats_group_start("Shadows"); EEVEE_draw_shadows(sldata, psl); @@ -263,7 +270,7 @@ static void eevee_draw_background(void *vedata) /* Post Process */ DRW_stats_group_start("Post FX"); - EEVEE_draw_effects(vedata); + EEVEE_draw_effects(sldata, vedata); DRW_stats_group_end(); if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 9d90338131b..7403da737dd 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -83,7 +83,6 @@ static struct { struct GPUTexture *cube_face_minmaxz; int update_world; - bool world_ready_to_shade; } e_data = {NULL}; /* Engine data */ extern char datatoc_background_vert_glsl[]; @@ -107,6 +106,7 @@ extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern GlobalsUboStorage ts; @@ -205,6 +205,7 @@ static void lightprobe_shaders_init(void) char *shader_str = NULL; shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_glossy_frag_glsl); @@ -218,6 +219,7 @@ static void lightprobe_shaders_init(void) MEM_freeN(shader_str); shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_diffuse_frag_glsl); @@ -227,6 +229,7 @@ static void lightprobe_shaders_init(void) MEM_freeN(shader_str); shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_lightprobe_filter_visibility_frag_glsl); @@ -237,6 +240,7 @@ static void lightprobe_shaders_init(void) shader_str = BLI_string_joinN( datatoc_octahedron_lib_glsl, + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, @@ -252,6 +256,7 @@ static void lightprobe_shaders_init(void) shader_str = BLI_string_joinN( datatoc_octahedron_lib_glsl, + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_lightprobe_cube_display_frag_glsl); @@ -276,6 +281,7 @@ static void lightprobe_shaders_init(void) void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; bool update_all = false; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -288,15 +294,16 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); - sldata->probes->specular_toggle = true; - sldata->probes->ssr_toggle = true; - sldata->probes->sss_toggle = true; sldata->probes->grid_initialized = false; sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL); sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL); } + common_data->spec_toggle = true; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces"); if (sldata->probes->num_bounce != prop_bounce_num) { sldata->probes->num_bounce = prop_bounce_num; @@ -315,8 +322,8 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda } int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution"); - if (sldata->probes->irradiance_vis_size != visibility_res) { - sldata->probes->irradiance_vis_size = visibility_res; + if (common_data->prb_irradiance_vis_size != visibility_res) { + common_data->prb_irradiance_vis_size = visibility_res; update_all = true; } @@ -360,6 +367,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->do_cube_update = false; pinfo->num_cube = 1; /* at least one for the world */ pinfo->num_grid = 1; pinfo->num_planar = 0; @@ -428,14 +436,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom); - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "roughnessSquared", &sldata->probes->roughness, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1); - DRW_shgroup_uniform_float(grp, "texelSize", &sldata->probes->texel_size, 1); - DRW_shgroup_uniform_float(grp, "paddingSize", &sldata->probes->padding_size, 1); - DRW_shgroup_uniform_int(grp, "Layer", &sldata->probes->layer, 1); + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); + DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1); + DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); @@ -448,14 +457,15 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_diffuse_sh, psl->probe_diffuse_compute); #ifdef IRRADIANCE_SH_L2 - DRW_shgroup_uniform_int(grp, "probeSize", &sldata->probes->shres, 1); + DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1); #else - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "lodFactor", &sldata->probes->lodfactor, 1); - DRW_shgroup_uniform_float(grp, "lodMax", &sldata->probes->lod_rt_max, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1); + DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); #endif + DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); @@ -466,14 +476,14 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute); - DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1); - DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1); - DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1); - DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1); - DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1); - DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1); - DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1); - DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1); + DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1); + DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1); + DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1); + DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); + DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); + DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1); + DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1); + DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1); DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt); @@ -500,8 +510,8 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */ DRW_shgroup_attrib_float(grp, "probe_location", 3); DRW_shgroup_attrib_float(grp, "sphere_size", 1); - DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); geom = DRW_cache_quad_get(); grp = stl->g_data->planar_display_shgrp = DRW_shgroup_instance_create(e_data.probe_planar_display_sh, psl->probe_display, geom); @@ -516,7 +526,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom); DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &stl->effects->ssr_firefly_fac, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); } } @@ -549,7 +559,6 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) ped->need_update = true; ped->probe_id = 0; - if (probe->type == LIGHTPROBE_TYPE_GRID) { ped->updated_cells = 0; ped->updated_lvl = 0; @@ -565,6 +574,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) ped->probe_id = 0; } + pinfo->do_cube_update |= ped->need_update; + if (probe->type == LIGHTPROBE_TYPE_CUBE) { pinfo->probes_cube_ref[pinfo->num_cube] = ob; pinfo->num_cube++; @@ -832,6 +843,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; @@ -849,7 +861,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } int irr_size[3]; - irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); + irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, irr_size); if ((irr_size[0] != pinfo->cache_irradiance_size[0]) || (irr_size[1] != pinfo->cache_irradiance_size[1]) || @@ -875,8 +887,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* Tag probes to refresh */ e_data.update_world |= PROBE_UPDATE_CUBE; - e_data.world_ready_to_shade = false; - pinfo->num_render_cube = 0; + common_data->prb_num_render_cube = 0; pinfo->cache_num_cube = pinfo->num_cube; for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { @@ -908,7 +919,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], irradiance_format, DRW_TEX_FILTER, NULL); } - pinfo->num_render_grid = 0; + common_data->prb_num_render_grid = 0; pinfo->updated_bounce = 0; pinfo->grid_initialized = false; e_data.update_world |= PROBE_UPDATE_GRID; @@ -920,9 +931,9 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } } - if (pinfo->num_render_grid > pinfo->num_grid) { + if (common_data->prb_num_render_grid > pinfo->num_grid) { /* This can happen when deleting a probe. */ - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; } EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl); @@ -939,23 +950,26 @@ static void downsample_planar(void *vedata, int level) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; const float *size = DRW_viewport_size_get(); - copy_v2_v2(stl->g_data->texel_size, size); + copy_v2_v2(stl->g_data->planar_texel_size, size); for (int i = 0; i < level - 1; ++i) { - stl->g_data->texel_size[0] /= 2.0f; - stl->g_data->texel_size[1] /= 2.0f; - min_ff(floorf(stl->g_data->texel_size[0]), 1.0f); - min_ff(floorf(stl->g_data->texel_size[1]), 1.0f); + stl->g_data->planar_texel_size[0] /= 2.0f; + stl->g_data->planar_texel_size[1] /= 2.0f; + min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f); + min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f); } - invert_v2(stl->g_data->texel_size); + invert_v2(stl->g_data->planar_texel_size); DRW_draw_pass(psl->probe_planar_downsample_ps); } /* Glossy filter probe_rt to probe_pool at index probe_idx */ -static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx) +static void glossy_filter_probe( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int probe_idx, float intensity) { EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->intensity_fac = intensity; + /* Max lod used from the render target probe */ pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f; @@ -1018,7 +1032,7 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, CLAMP_MIN(mipsize, 1); } /* For shading, save max level of the octahedron map */ - pinfo->lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; + sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; /* reattach to have a valid framebuffer. */ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); @@ -1027,12 +1041,15 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Diffuse filter probe_rt to irradiance_pool at index probe_idx */ static void diffuse_filter_probe( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset, - float clipsta, float clipend, float vis_range, float vis_blur) + float clipsta, float clipend, float vis_range, float vis_blur, float intensity) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_LightProbesInfo *pinfo = sldata->probes; + pinfo->intensity_fac = intensity; + int pool_size[3]; - irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); + irradiance_pool_size_get(common_data->prb_irradiance_vis_size, pinfo->total_irradiance_samples, pool_size); /* find cell position on the virtual 3D texture */ /* NOTE : Keep in sync with load_irradiance_cell() */ @@ -1076,23 +1093,24 @@ static void diffuse_filter_probe( /* Compute visibility */ pinfo->samples_ct = 512.0f; /* TODO refine */ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; - pinfo->shres = pinfo->irradiance_vis_size; + pinfo->shres = common_data->prb_irradiance_vis_size; pinfo->visibility_range = vis_range; pinfo->visibility_blur = vis_blur; pinfo->near_clip = -clipsta; pinfo->far_clip = -clipend; - pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size; + pinfo->texel_size = 1.0f / (float)common_data->prb_irradiance_vis_size; - int cell_per_col = pool_size[1] / pinfo->irradiance_vis_size; - cell_per_row = pool_size[0] / pinfo->irradiance_vis_size; - x = pinfo->irradiance_vis_size * (offset % cell_per_row); - y = pinfo->irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); + int cell_per_col = pool_size[1] / common_data->prb_irradiance_vis_size; + cell_per_row = pool_size[0] / common_data->prb_irradiance_vis_size; + x = common_data->prb_irradiance_vis_size * (offset % cell_per_row); + y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); int layer = 1 + ((offset / cell_per_row) / cell_per_col); DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0); - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size); + DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, common_data->prb_irradiance_vis_size, + common_data->prb_irradiance_vis_size); DRW_draw_pass(psl->probe_visibility_compute); } @@ -1111,23 +1129,13 @@ static void render_scene_to_probe( EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; - float winmat[4][4], wininv[4][4], posmat[4][4], tmp_ao_dist, tmp_ao_settings; + float winmat[4][4], wininv[4][4], posmat[4][4]; unit_m4(posmat); /* Move to capture position */ negate_v3_v3(posmat[3], pos); - /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ - sldata->probes->specular_toggle = false; - sldata->probes->ssr_toggle = false; - sldata->probes->sss_toggle = false; - - /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */ - tmp_ao_dist = stl->effects->ao_dist; - tmp_ao_settings = stl->effects->ao_settings; - stl->effects->ao_settings = 0.0f; /* Disable AO */ - /* 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 dependant effects). */ @@ -1143,6 +1151,9 @@ static void render_scene_to_probe( stl->g_data->minzbuffer = e_data.depth_placeholder; txl->maxzbuffer = e_data.depth_placeholder; + /* Update common uniforms */ + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + /* Detach to rebind the right cubeface. */ DRW_framebuffer_bind(sldata->probe_fb); DRW_framebuffer_texture_detach(sldata->probe_rt); @@ -1204,14 +1215,9 @@ static void render_scene_to_probe( DRW_viewport_matrix_override_unset(DRW_MAT_WININV); /* Restore */ - pinfo->specular_toggle = true; - pinfo->ssr_toggle = true; - pinfo->sss_toggle = true; txl->planar_pool = tmp_planar_pool; stl->g_data->minzbuffer = tmp_minz; txl->maxzbuffer = tmp_maxz; - stl->effects->ao_dist = tmp_ao_dist; - stl->effects->ao_settings = tmp_ao_settings; } static void render_scene_to_planar( @@ -1250,11 +1256,6 @@ static void render_scene_to_planar( DRW_framebuffer_clear(false, true, false, NULL, 1.0); - /* Turn off ssr to avoid black specular */ - /* TODO : Enable SSR in planar reflections? (Would be very heavy) */ - sldata->probes->ssr_toggle = false; - sldata->probes->sss_toggle = false; - /* Avoid using the texture attached to framebuffer when rendering. */ /* XXX */ GPUTexture *tmp_planar_pool = txl->planar_pool; @@ -1286,8 +1287,6 @@ static void render_scene_to_planar( DRW_state_clip_planes_reset(); /* Restore */ - sldata->probes->ssr_toggle = true; - sldata->probes->sss_toggle = true; txl->planar_pool = tmp_planar_pool; txl->planar_depth = tmp_planar_depth; DRW_viewport_matrix_override_unset(DRW_MAT_PERS); @@ -1373,27 +1372,25 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; - EEVEE_LightProbesInfo *pinfo = sldata->probes; + render_world_to_probe(sldata, psl); if (e_data.update_world & PROBE_UPDATE_CUBE) { - glossy_filter_probe(sldata, vedata, psl, 0); + glossy_filter_probe(sldata, vedata, psl, 0, 1.0); + common_data->prb_num_render_cube = 1; } if (e_data.update_world & PROBE_UPDATE_GRID) { - diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0); + diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); DRW_framebuffer_texture_detach(sldata->probe_pool); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); DRW_draw_pass(psl->probe_grid_fill); DRW_framebuffer_texture_detach(sldata->irradiance_rt); DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + common_data->prb_num_render_grid = 1; } e_data.update_world = 0; - if (!e_data.world_ready_to_shade) { - e_data.world_ready_to_shade = true; - pinfo->num_render_cube = 1; - pinfo->num_render_grid = 1; - } DRW_viewport_request_redraw(); } @@ -1425,36 +1422,53 @@ static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEV static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_TextureList *txl = vedata->txl; Object *ob; EEVEE_LightProbesInfo *pinfo = sldata->probes; + + if (pinfo->num_planar == 0) { + return; + } + + /* Temporary Remove all planar reflections (avoid lag effect). */ + common_data->prb_num_planar = 0; + /* Turn off ssr to avoid black specular */ + /* TODO : Enable SSR in planar reflections? (Would be very heavy) */ + common_data->ssr_toggle = false; + common_data->sss_toggle = false; + + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); if (!ped->need_update) { continue; } - /* Temporary Remove all planar reflections (avoid lag effect). */ - int tmp_num_planar = pinfo->num_planar; - pinfo->num_planar = 0; render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset); - /* Restore */ - pinfo->num_planar = tmp_num_planar; ped->need_update = false; ped->probe_id = i; } + + /* Restore */ + common_data->prb_num_planar = pinfo->num_planar; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + /* If there is at least one planar probe */ if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { const int max_lod = 9; DRW_stats_group_start("Planar Probe Downsample"); DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata); /* For shading, save max level of the planar map */ - pinfo->lod_planar_max = (float)(max_lod); + common_data->prb_lod_planar_max = (float)(max_lod); DRW_stats_group_end(); } } static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -1466,11 +1480,11 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve } LightProbe *prb = (LightProbe *)ob->data; render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend); - glossy_filter_probe(sldata, vedata, psl, i); + glossy_filter_probe(sldata, vedata, psl, i, prb->intensity); ped->need_update = false; ped->probe_id = i; if (!ped->ready_to_shade) { - pinfo->num_render_cube++; + common_data->prb_num_render_cube++; ped->ready_to_shade = true; } #if 0 @@ -1487,6 +1501,7 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -1506,7 +1521,7 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ /* Reflection probes depend on diffuse lighting thus on irradiance grid, * so update them first. */ while (pinfo->updated_bounce < pinfo->num_bounce) { - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; /* TODO(sergey): This logic can be split into smaller functions. */ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); @@ -1550,16 +1565,16 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ lightprobe_cell_world_location_get(egrid, grid_loc, pos); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); /* Temporary Remove all probes. */ - int tmp_num_render_grid = pinfo->num_render_grid; - int tmp_num_render_cube = pinfo->num_render_cube; - int tmp_num_planar = pinfo->num_planar; + int tmp_num_render_grid = common_data->prb_num_render_grid; + int tmp_num_render_cube = common_data->prb_num_render_cube; + int tmp_num_planar = common_data->prb_num_planar; float tmp_level_bias = egrid->level_bias; - pinfo->num_render_cube = 0; - pinfo->num_planar = 0; + common_data->prb_num_render_cube = 0; + common_data->prb_num_planar = 0; /* Use light from previous bounce when capturing radiance. */ if (pinfo->updated_bounce == 0) { /* But not on first bounce. */ - pinfo->num_render_grid = 0; + common_data->prb_num_render_grid = 0; } else { /* Remove bias */ @@ -1568,14 +1583,15 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ } render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend); diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id, - prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur); + prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur, + prb->intensity); /* To see what is going on. */ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); /* Restore */ - pinfo->num_render_cube = tmp_num_render_cube; + common_data->prb_num_render_cube = tmp_num_render_cube; pinfo->num_planar = tmp_num_planar; if (pinfo->updated_bounce == 0) { - pinfo->num_render_grid = tmp_num_render_grid; + common_data->prb_num_render_grid = tmp_num_render_grid; } else { egrid->level_bias = tmp_level_bias; @@ -1603,7 +1619,7 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ } pinfo->updated_bounce++; - pinfo->num_render_grid = pinfo->num_grid; + common_data->prb_num_render_grid = pinfo->num_grid; if (pinfo->updated_bounce < pinfo->num_bounce) { /* Retag all grids to update for next bounce */ @@ -1631,18 +1647,39 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_LightProbesInfo *pinfo = sldata->probes; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ + common_data->spec_toggle = false; + common_data->ssr_toggle = false; + common_data->sss_toggle = false; + + /* Disable AO until we find a way to hide really bad discontinuities between cubefaces. */ + float tmp_ao_dist = common_data->ao_dist; + float tmp_ao_settings = common_data->ao_settings; + common_data->ao_settings = 0.0f; + common_data->ao_dist = 0.0f; + /* Render world in priority */ if (e_data.update_world) { lightprobes_refresh_world(sldata, vedata); } - else if (true) { /* TODO if at least one probe needs refresh */ + else if (pinfo->do_cube_update || (pinfo->updated_bounce < pinfo->num_bounce)) { lightprobes_refresh_all_no_world(sldata, vedata); } + /* Restore */ + common_data->spec_toggle = true; + common_data->ssr_toggle = true; + common_data->sss_toggle = true; + common_data->ao_dist = tmp_ao_dist; + common_data->ao_settings = tmp_ao_settings; + lightprobes_refresh_planar(sldata, vedata); /* Disable SSR if we cannot read previous frame */ - sldata->probes->ssr_toggle = vedata->stl->g_data->valid_double_buffer; + common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; } void EEVEE_lightprobes_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 63c0b540cdf..69b58bf9670 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -289,7 +289,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Step 1 find all lamps in the scene and setup them */ if (linfo->num_light >= MAX_LIGHT) { - printf("Too much lamps in the scene !!!\n"); + printf("Too many lamps in the scene !!!\n"); } else { Lamp *la = (Lamp *)ob->data; @@ -484,6 +484,8 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) EEVEE_LampsInfo *linfo = sldata->lamps; DRWTextureFormat shadow_pool_format = DRW_TEX_R_32; + sldata->common_data.la_num_light = linfo->num_light; + /* Setup enough layers. */ /* Free textures if number mismatch. */ if (linfo->num_layer != linfo->cache_num_layer) { diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index e2d47ab4e98..cde14f0efc3 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -70,7 +70,7 @@ static struct { unsigned int sss_count; - float viewvecs[2][4]; + float view_vecs[2][4]; float alpha_hash_offset; float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ @@ -88,6 +88,7 @@ extern char datatoc_btdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; @@ -361,65 +362,59 @@ static char *eevee_get_volume_defines(int options) **/ static void add_standard_uniforms( DRWShadingGroup *shgrp, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend, bool use_sss) + int *ssr_id, float *refract_depth, bool use_ssrefraction, bool use_alpha_blend) { if (ssr_id == NULL) { static int no_ssr = -1.0f; ssr_id = &no_ssr; } + DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_int(shgrp, "light_count", &sldata->lamps->num_light, 1); - DRW_shgroup_uniform_int(shgrp, "probe_count", &sldata->probes->num_render_cube, 1); - DRW_shgroup_uniform_int(shgrp, "grid_count", &sldata->probes->num_render_grid, 1); - DRW_shgroup_uniform_int(shgrp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1); - DRW_shgroup_uniform_bool(shgrp, "ssrToggle", &sldata->probes->ssr_toggle, 1); - DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); - DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); - DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1); - DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); - DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2); - DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); - DRW_shgroup_uniform_vec2(shgrp, "mipRatio[0]", (float *)vedata->stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(shgrp, "ssrParameters", &vedata->stl->effects->ssr_quality, 1); - - if (refract_depth != NULL) { - DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); + DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + + /* TODO if glossy or diffuse bsdf */ + if (true) { + DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); + DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); + DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); + + if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) { + DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons); + } + else { + /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ + DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); + } } - if (use_ssrefraction) { - DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); - DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1); - DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1); + /* TODO if diffuse bsdf */ + if (true) { + DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); } - if (vedata->stl->effects->use_ao) { - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons); + /* TODO if glossy bsdf */ + if (true) { + DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); } - else { - /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); + + if (use_ssrefraction) { + BLI_assert(refract_depth != NULL); + DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); + DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); } - if (vedata->stl->effects->use_volumetrics && use_alpha_blend) { + 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_buffer(shgrp, "inScattering", &vedata->txl->volume_scatter); DRW_shgroup_uniform_buffer(shgrp, "inTransmittance", &vedata->txl->volume_transmittance); - DRW_shgroup_uniform_vec2(shgrp, "volume_uv_ratio", (float *)sldata->volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(shgrp, "volume_param", (float *)sldata->volumetrics->depth_param, 1); - } - - if (use_sss) { - DRW_shgroup_uniform_bool(shgrp, "sssToggle", &sldata->probes->sss_toggle, 1); } } @@ -507,11 +502,12 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double DRW_framebuffer_texture_detach(e_data.util_tex); } -void EEVEE_materials_init(EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) +void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { if (!e_data.frag_shader_lib) { /* Shaders */ e_data.frag_shader_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_ambient_occlusion_lib_glsl, @@ -535,6 +531,7 @@ void EEVEE_materials_init(EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) datatoc_volumetric_lib_glsl); e_data.volume_shader_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, @@ -601,12 +598,12 @@ void EEVEE_materials_init(EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) } { - /* Update viewvecs */ + /* Update view_vecs */ const bool is_persp = DRW_viewport_is_persp_get(); float invproj[4][4], winmat[4][4]; /* view vectors for the corners of the view frustum. * Can be used to recreate the world space position easily */ - float viewvecs[3][4] = { + float view_vecs[3][4] = { {-1.0f, -1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f, 1.0f} @@ -618,28 +615,28 @@ void EEVEE_materials_init(EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) /* convert the view vectors to view space */ for (int i = 0; i < 3; i++) { - mul_m4_v4(invproj, viewvecs[i]); + mul_m4_v4(invproj, view_vecs[i]); /* normalized trick see: * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][3]); if (is_persp) - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); - viewvecs[i][3] = 1.0; + mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][2]); + view_vecs[i][3] = 1.0; } - copy_v4_v4(stl->g_data->viewvecs[0], viewvecs[0]); - copy_v4_v4(stl->g_data->viewvecs[1], viewvecs[1]); + copy_v4_v4(sldata->common_data.view_vecs[0], view_vecs[0]); + copy_v4_v4(sldata->common_data.view_vecs[1], view_vecs[1]); /* we need to store the differences */ - stl->g_data->viewvecs[1][0] -= viewvecs[0][0]; - stl->g_data->viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1]; + sldata->common_data.view_vecs[1][0] -= view_vecs[0][0]; + sldata->common_data.view_vecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; /* calculate a depth offset as well */ if (!is_persp) { float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; mul_m4_v4(invproj, vec_far); mul_v3_fl(vec_far, 1.0f / vec_far[3]); - stl->g_data->viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; + sldata->common_data.view_vecs[1][2] = vec_far[2] - view_vecs[0][2]; } } @@ -707,6 +704,7 @@ struct GPUMaterial *EEVEE_material_mesh_get( struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method) { + EEVEE_EffectsInfo *effects = vedata->stl->effects; const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_MESH; @@ -714,9 +712,9 @@ struct GPUMaterial *EEVEE_material_mesh_get( if (use_multiply) options |= VAR_MAT_MULT; if (use_refract) options |= VAR_MAT_REFRACT; if (use_sss) options |= VAR_MAT_SSS; - if (use_sss && vedata->stl->effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED; + if (use_sss && effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED; if (use_translucency) options |= VAR_MAT_TRANSLUC; - if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME; + if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME; options |= eevee_material_shadow_option(shadow_method); @@ -843,6 +841,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, bool is_hair, bool is_hair_fibers, 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; @@ -851,7 +850,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( if (is_hair_fibers) options |= VAR_MAT_HAIR_FIBERS; if (is_flat_normal) options |= VAR_MAT_FLAT; if (use_blend) options |= VAR_MAT_BLEND; - if (vedata->stl->effects->use_volumetrics && use_blend) options |= VAR_MAT_VOLUME; + if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME; options |= eevee_material_shadow_option(shadow_method); @@ -860,7 +859,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( } DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend, false); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, use_blend); return shgrp; } @@ -892,7 +891,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false, false); + add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); } return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); @@ -903,19 +902,6 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; - { - const DRWContextState *draw_ctx = DRW_context_state_get(); - ViewLayer *view_layer = draw_ctx->view_layer; - IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); - /* Global AO Switch*/ - stl->effects->use_ao = BKE_collection_engine_property_value_get_bool(props, "gtao_enable"); - stl->effects->use_bent_normals = BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals"); - /* SSR switch */ - stl->effects->use_ssr = BKE_collection_engine_property_value_get_bool(props, "ssr_enable"); - /* Volumetrics */ - stl->effects->use_volumetrics = BKE_collection_engine_property_value_get_bool(props, "volumetric_enable"); - } - /* Create Material Ghash */ { stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash"); @@ -1059,6 +1045,7 @@ static void material_opaque( bool do_cull, bool use_flat_nor, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth, struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth, struct DRWShadingGroup **shgrp_depth_clip) { + EEVEE_EffectsInfo *effects = vedata->stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; @@ -1072,9 +1059,9 @@ static void material_opaque( const bool use_gpumat = (ma->use_nodes && ma->nodetree); const bool use_refract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) && - ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0); + ((effects->enabled_effects & EFFECT_REFRACT) != 0); const bool use_sss = ((ma->blend_flag & MA_BL_SS_SUBSURFACE) != 0) && - ((stl->effects->enabled_effects & EFFECT_SSS) != 0); + ((effects->enabled_effects & EFFECT_SSS) != 0); const bool use_translucency = use_sss && ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0); EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma); @@ -1103,8 +1090,8 @@ static void material_opaque( if (*shgrp) { static int no_ssr = -1; static int first_ssr = 1; - int *ssr_id = (stl->effects->use_ssr && !use_refract) ? &first_ssr : &no_ssr; - add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false, use_sss); + int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr; + add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false); if (use_sss) { struct GPUTexture *sss_tex_profile = NULL; @@ -1119,7 +1106,7 @@ static void material_opaque( } DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); - EEVEE_subsurface_add_pass(vedata, e_data.sss_count + 1, sss_profile); + EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); e_data.sss_count++; } } @@ -1149,7 +1136,7 @@ static void material_opaque( } if (*shgrp_depth != NULL) { - add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false, false); + add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false); if (ma->blend_method == MA_BM_CLIP) { DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1); @@ -1165,7 +1152,8 @@ static void material_opaque( /* Fallback to default shader */ if (*shgrp == NULL) { - *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, false, use_flat_nor, stl->effects->use_ssr, linfo->shadow_method); + bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); + *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, false, use_flat_nor, 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); @@ -1217,7 +1205,7 @@ static void material_transparent( if (*shgrp) { static int ssr_id = -1; /* TODO transparent SSR */ bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0; - add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend, false); + add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend); } else { /* Shader failed : pink color */ @@ -1332,7 +1320,7 @@ static void material_particle_hair( shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false, false); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); BLI_ghash_insert(material_hash, ma, shgrp); } @@ -1348,7 +1336,9 @@ static void material_particle_hair( /* Fallback to default shader */ if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, false, stl->effects->use_ssr, sldata->lamps->shadow_method); + bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, false, use_ssr, + sldata->lamps->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); @@ -1415,7 +1405,7 @@ static void material_hair( shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false, false); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); BLI_ghash_insert(material_hash, ma, shgrp); } else { @@ -1430,7 +1420,9 @@ static void material_hair( /* Fallback to default shader */ if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, true, false, stl->effects->use_ssr, sldata->lamps->shadow_method); + bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, true, false, use_ssr, + sldata->lamps->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); @@ -1589,7 +1581,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld } /* Volumetrics */ - if (vedata->stl->effects->use_volumetrics && use_volume_material) { + if (((stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_volume_material) { EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob); } } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index f6f3bcd060e..9da438e825f 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -44,12 +44,14 @@ static struct { } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_gtao_frag_glsl[]; static void eevee_create_shader_occlusion(void) { char *frag_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_effect_gtao_frag_glsl); @@ -61,12 +63,12 @@ static void eevee_create_shader_occlusion(void) MEM_freeN(frag_str); } -int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -82,22 +84,19 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata eevee_create_shader_occlusion(); } - effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); - effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); - effects->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); + common_data->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); + common_data->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); + common_data->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); - effects->ao_settings = 1.0; /* USE_AO */ + common_data->ao_settings = 1.0; /* USE_AO */ if (BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals")) { - effects->ao_settings += 2.0; /* USE_BENT_NORMAL */ + common_data->ao_settings += 2.0; /* USE_BENT_NORMAL */ } if (BKE_collection_engine_property_value_get_bool(props, "gtao_denoise")) { - effects->ao_settings += 4.0; /* USE_DENOISE */ + common_data->ao_settings += 4.0; /* USE_DENOISE */ } - effects->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); - - effects->ao_texsize[0] = ((int)viewport_size[0]); - effects->ao_texsize[1] = ((int)viewport_size[1]); + common_data->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RGBA_8, 0}; @@ -119,12 +118,12 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata /* Cleanup */ DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); - effects->ao_settings = 0.0f; + common_data->ao_settings = 0.0f; return 0; } -void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; @@ -148,36 +147,30 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data **/ psl->ao_horizon_search = DRW_pass_create("GTAO 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_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &effects->ao_src_depth); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); psl->ao_horizon_search_layer = DRW_pass_create("GTAO 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_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(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_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_call_add(grp, quad, NULL); if (G.debug_value == 6) { psl->ao_horizon_debug = DRW_pass_create("GTAO 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_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 16544f185df..22440fb62c6 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -344,18 +344,6 @@ typedef struct EEVEE_ShadowCasterBuffer { unsigned int count; } EEVEE_ShadowCasterBuffer; -/* ************ VOLUME DATA ************ */ -typedef struct EEVEE_VolumetricsInfo { - float integration_step_count, shadow_step_count, sample_distribution, light_clamp; - float integration_start, integration_end; - float depth_param[3], history_alpha; - bool use_lights, use_volume_shadows; - int froxel_tex_size[3]; - float inv_tex_size[3]; - float volume_coord_scale[2]; - float jitter[3]; -} EEVEE_VolumetricsInfo; - /* ************ LIGHT DATA ************* */ typedef struct EEVEE_LampsInfo { int num_light, cache_num_light; @@ -441,12 +429,9 @@ typedef struct EEVEE_LightProbesInfo { int num_bounce; int cubemap_res; int target_size; - int irradiance_vis_size; int grid_initialized; struct World *prev_world; - /* Actual number of probes that have datas. */ - int num_render_cube; - int num_render_grid; + bool do_cube_update; /* For rendering probes */ float probemat[6][4][4]; int layer; @@ -461,11 +446,8 @@ typedef struct EEVEE_LightProbesInfo { float lod_rt_max, lod_cube_max, lod_planar_max; float visibility_range; float visibility_blur; + float intensity_fac; int shres; - int shnbr; - int specular_toggle; - int ssr_toggle; - int sss_toggle; /* List of probes in the scene. */ /* XXX This is fragile, can get out of sync quickly. */ struct Object *probes_cube_ref[MAX_PROBE]; @@ -488,30 +470,15 @@ enum { typedef struct EEVEE_EffectsInfo { int enabled_effects; bool swap_double_buffer; - /* SSSS */ int sss_sample_count; - float sss_jitter_threshold; bool sss_separate_albedo; - /* Volumetrics */ - bool use_volumetrics; int volume_current_sample; - /* SSR */ - bool use_ssr; bool reflection_trace_full; - bool ssr_use_normalization; int ssr_neighbor_ofs; int ssr_halfres_ofs[2]; - float ssr_brdf_bias; - float ssr_firefly_fac; - float ssr_border_fac; - float ssr_max_roughness; - float ssr_quality; - float ssr_thickness; - float ssr_pixelsize[2]; - /* Temporal Anti Aliasing */ int taa_current_sample; int taa_render_sample; @@ -523,29 +490,19 @@ typedef struct EEVEE_EffectsInfo { float overide_persinv[4][4]; float overide_winmat[4][4]; float overide_wininv[4][4]; - /* Ambient Occlusion */ - bool use_ao, use_bent_normals; - float ao_dist, pad1, ao_factor, pad2; - float ao_offset, ao_bounce_fac, ao_quality, ao_settings; - float ao_sample_nbr; - int ao_texsize[2], hori_tex_layers; int ao_depth_layer; struct GPUTexture *ao_src_depth; /* pointer copy */ - /* Motion Blur */ float current_ndc_to_world[4][4]; float past_world_to_ndc[4][4]; - float tmp_mat[4][4]; int motion_blur_samples; - /* Depth Of Field */ float dof_near_far[2]; float dof_params[3]; float dof_bokeh[4]; float dof_layer_select[2]; int dof_target_size[2]; - /* Bloom */ int bloom_iteration_ct; float source_texel_size[2]; @@ -558,7 +515,6 @@ typedef struct EEVEE_EffectsInfo { float unf_source_texel_size[2]; struct GPUTexture *unf_source_buffer; /* pointer copy */ struct GPUTexture *unf_base_buffer; /* pointer copy */ - /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */ struct GPUTexture *source_buffer; /* latest updated texture */ struct GPUFrameBuffer *target_buffer; /* next target to render to */ @@ -579,6 +535,58 @@ enum { EFFECT_SSS = (1 << 11), }; +/* ***************** COMMON DATA **************** */ + +/* Common uniform buffer containing all "constant" data over the whole drawing pipeline. */ +/* !! CAUTION !! + * - [i]vec3 need to be paded to [i]vec4 (even in ubo declaration). + * - Make sure that [i]vec4 start at a multiple of 16 bytes. + * - Arrays of vec2/vec3 are padded as arrays of vec4. + * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ +typedef struct EEVEE_CommonUniformBuffer { + float prev_persmat[4][4]; /* mat4 */ + float view_vecs[2][4]; /* vec4[2] */ + float mip_ratio[10][4]; /* vec2[10] */ + /* Ambient Occlusion */ + /* -- 16 byte aligned -- */ + float ao_dist, pad1, ao_factor, pad2; /* vec4 */ + float ao_offset, ao_bounce_fac, ao_quality, ao_settings; /* vec4 */ + /* Volumetric */ + /* -- 16 byte aligned -- */ + int vol_tex_size[3], pad3; /* ivec3 */ + float vol_depth_param[3], pad4; /* vec3 */ + float vol_inv_tex_size[3], pad5; /* vec3 */ + float vol_jitter[3], pad6; /* vec3 */ + float vol_coord_scale[2], pad7[2]; /* vec2 */ + /* -- 16 byte aligned -- */ + float vol_history_alpha; /* float */ + float vol_light_clamp; /* float */ + float vol_shadow_steps; /* float */ + int vol_use_lights; /* bool */ + /* Screen Space Reflections */ + /* -- 16 byte aligned -- */ + float ssr_quality, ssr_thickness, ssr_pixelsize[2]; /* vec4 */ + float ssr_border_fac; /* float */ + float ssr_max_roughness; /* float */ + float ssr_firefly_fac; /* float */ + float ssr_brdf_bias; /* float */ + int ssr_toggle; /* bool */ + /* SubSurface Scattering */ + float sss_jitter_threshold; /* float */ + int sss_toggle; /* bool */ + /* Specular */ + int spec_toggle; /* bool */ + /* Lamps */ + int la_num_light; /* int */ + /* Probes */ + int prb_num_planar; /* int */ + int prb_num_render_cube; /* int */ + int prb_num_render_grid; /* int */ + int prb_irradiance_vis_size; /* int */ + float prb_lod_cube_max; /* float */ + float prb_lod_planar_max; /* float */ +} EEVEE_CommonUniformBuffer; + /* ************** SCENE LAYER DATA ************** */ typedef struct EEVEE_ViewLayerData { /* Lamps */ @@ -616,10 +624,9 @@ typedef struct EEVEE_ViewLayerData { struct GPUTexture *irradiance_pool; struct GPUTexture *irradiance_rt; - struct ListBase probe_queue; /* List of probes to update */ - - /* Volumetrics */ - struct EEVEE_VolumetricsInfo *volumetrics; + /* Common Uniform Buffer */ + struct EEVEE_CommonUniformBuffer common_data; + struct GPUUniformBuffer *common_ubo; } EEVEE_ViewLayerData; /* ************ OBJECT DATA ************ */ @@ -717,15 +724,11 @@ typedef struct EEVEE_PrivateData { struct GPUTexture *ssr_pdf_output; struct GPUTexture *gtao_horizons_debug; float background_alpha; /* TODO find a better place for this. */ - float viewvecs[2][4]; /* For planar probes */ - float texel_size[2]; - /* To correct mip level texel mis-alignement */ - float mip_ratio[10][2]; /* TODO put in a UBO */ + float planar_texel_size[2]; /* For double buffering */ bool view_updated; bool valid_double_buffer; - float prev_persmat[4][4]; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -740,7 +743,7 @@ EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ -void EEVEE_materials_init(EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); +void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); void EEVEE_materials_cache_init(EEVEE_Data *vedata); void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob); void EEVEE_materials_cache_finish(EEVEE_Data *vedata); @@ -810,7 +813,8 @@ void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); +void EEVEE_subsurface_add_pass( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_free(void); @@ -843,7 +847,7 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_effects_do_gtao(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_draw_effects(EEVEE_Data *vedata); +void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_free(void); /* Shadow Matrix */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 86896a1e01a..2917bfd1236 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -37,7 +37,8 @@ enum { SSR_RESOLVE = (1 << 0), SSR_FULL_TRACE = (1 << 1), - SSR_MAX_SHADER = (1 << 2), + SSR_AO = (1 << 3), + SSR_MAX_SHADER = (1 << 4), }; static struct { @@ -50,6 +51,7 @@ static struct { } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; @@ -61,6 +63,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) { if (e_data.ssr_sh[options] == NULL) { char *ssr_shader_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_octahedron_lib_glsl, @@ -81,6 +84,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) if (options & SSR_FULL_TRACE) { BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); } + if (options & SSR_AO) { + BLI_dynstr_appendf(ds_defines, "#define SSR_AO\n"); + } char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); BLI_dynstr_free(ds_defines); @@ -93,8 +99,9 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) return e_data.ssr_sh[options]; } -int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; @@ -108,8 +115,8 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * RE_engine_id_BLENDER_EEVEE); /* Compute pixel size, (shared with contact shadows) */ - copy_v2_v2(effects->ssr_pixelsize, viewport_size); - invert_v2(effects->ssr_pixelsize); + copy_v2_v2(common_data->ssr_pixelsize, viewport_size); + invert_v2(common_data->ssr_pixelsize); if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) { const bool use_refraction = BKE_collection_engine_property_value_get_bool(props, "ssr_refraction"); @@ -124,16 +131,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * bool prev_trace_full = effects->reflection_trace_full; effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); - effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); - effects->ssr_quality = 1.0f - 0.95f * BKE_collection_engine_property_value_get_float(props, "ssr_quality"); - effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); - effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); - effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); - effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); - effects->ssr_brdf_bias = 0.1f + effects->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */ - - if (effects->ssr_firefly_fac < 1e-8f) { - effects->ssr_firefly_fac = FLT_MAX; + common_data->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); + common_data->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); + common_data->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); + common_data->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); + common_data->ssr_quality = 1.0f - 0.95f * BKE_collection_engine_property_value_get_float(props, "ssr_quality"); + common_data->ssr_brdf_bias = 0.1f + common_data->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */ + + if (common_data->ssr_firefly_fac < 1e-8f) { + common_data->ssr_firefly_fac = FLT_MAX; } if (prev_trace_full != effects->reflection_trace_full) { @@ -192,6 +198,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v if ((effects->enabled_effects & EFFECT_SSR) != 0) { int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; + options |= ((effects->enabled_effects & EFFECT_GTAO) != 0) ? SSR_AO : 0; struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options); struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options); @@ -214,16 +221,11 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_float(grp, "brdfBias", &effects->ssr_brdf_bias, 1); DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); if (!effects->reflection_trace_full) { DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1); } @@ -234,36 +236,20 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); - DRW_shgroup_uniform_float(grp, "brdfBias", &effects->ssr_brdf_bias, 1); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_buffer(grp, "hitBuffer", &vedata->txl->ssr_hit_output); DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output); + DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); + 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, "common_block", sldata->common_ubo); DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); - - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2); - if (effects->use_ao) { + if ((effects->enabled_effects & EFFECT_GTAO) != 0) { + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons); } - else { - /* Use ssr_specrough_input as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->ssr_specrough_input); - } DRW_shgroup_call_add(grp, quad, NULL); } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 4efdfb0fb84..17da4a18b78 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -27,7 +27,7 @@ #include "DRW_render.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "eevee_private.h" #include "GPU_texture.h" @@ -36,18 +36,26 @@ static struct { struct GPUShader *sss_sh[3]; } e_data = {NULL}; /* Engine data */ +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; static void eevee_create_shader_subsurface(void) { - e_data.sss_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define FIRST_PASS\n"); - e_data.sss_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n"); - e_data.sss_sh[2] = DRW_shader_create_fullscreen(datatoc_effect_subsurface_frag_glsl, "#define SECOND_PASS\n" - "#define USE_SEP_ALBEDO\n"); + char *frag_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_effect_subsurface_frag_glsl); + + e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n"); + e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); + e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" + "#define USE_SEP_ALBEDO\n"); + + MEM_freeN(frag_str); } -int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int 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; @@ -60,8 +68,8 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedat if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) { effects->sss_sample_count = 1 + BKE_collection_engine_property_value_get_int(props, "sss_samples") * 2; - effects->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo"); + common_data->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); /* Shaders */ if (!e_data.sss_sh[0]) { @@ -117,7 +125,8 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data } } -void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile) +void EEVEE_subsurface_add_pass( + EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_TextureList *txl = vedata->txl; @@ -127,23 +136,21 @@ void EEVEE_subsurface_add_pass(EEVEE_Data *vedata, unsigned int sss_id, struct G struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_data); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(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); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); - DRW_shgroup_uniform_float(grp, "jitterThreshold", &effects->sss_jitter_threshold, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index d1a45657a29..a960682e8c9 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -51,6 +51,7 @@ static struct { struct GPUShader *volumetric_clear_sh; struct GPUShader *volumetric_scatter_sh; + struct GPUShader *volumetric_scatter_with_lamps_sh; struct GPUShader *volumetric_integration_sh; struct GPUShader *volumetric_resolve_sh; @@ -63,6 +64,7 @@ static struct { extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lamps_lib_glsl[]; @@ -78,10 +80,12 @@ extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; static void eevee_create_shader_volumes(void) { e_data.volumetric_common_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_volumetric_lib_glsl); e_data.volumetric_common_lamps_lib = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_direct_lib_glsl, datatoc_octahedron_lib_glsl, @@ -104,6 +108,15 @@ static void eevee_create_shader_volumes(void) SHADER_DEFINES "#define VOLUMETRICS\n" "#define VOLUME_SHADOW\n"); + e_data.volumetric_scatter_with_lamps_sh = DRW_shader_create_with_lib( + datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_scatter_frag_glsl, + e_data.volumetric_common_lamps_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, @@ -121,6 +134,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -137,29 +151,23 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) eevee_create_shader_volumes(); } - if (sldata->volumetrics == NULL) { - sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo"); - } - - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - int tile_size = BKE_collection_engine_property_value_get_int(props, "volumetric_tile_size"); /* Find Froxel Texture resolution. */ - int froxel_tex_size[3]; + int tex_size[3]; - froxel_tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); - froxel_tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); - froxel_tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); + 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(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); - volumetrics->volume_coord_scale[0] = viewport_size[0] / (float)(tile_size * froxel_tex_size[0]); - volumetrics->volume_coord_scale[1] = viewport_size[1] / (float)(tile_size * froxel_tex_size[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 ((volumetrics->froxel_tex_size[0] != froxel_tex_size[0]) || - (volumetrics->froxel_tex_size[1] != froxel_tex_size[1]) || - (volumetrics->froxel_tex_size[2] != froxel_tex_size[2])) + 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); @@ -172,38 +180,46 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - volumetrics->froxel_tex_size[0] = froxel_tex_size[0]; - volumetrics->froxel_tex_size[1] = froxel_tex_size[1]; - volumetrics->froxel_tex_size[2] = froxel_tex_size[2]; + 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]; - volumetrics->inv_tex_size[0] = 1.0f / (float)(volumetrics->froxel_tex_size[0]); - volumetrics->inv_tex_size[1] = 1.0f / (float)(volumetrics->froxel_tex_size[1]); - volumetrics->inv_tex_size[2] = 1.0f / (float)(volumetrics->froxel_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. */ - volumetrics->history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; + 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(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_extinction = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_emission = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_phase = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RG_16, DRW_TEX_FILTER, NULL); + txl->volume_prop_scattering = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_extinction = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_emission = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_phase = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RG_16, 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(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_scatter = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, 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(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_scatter_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2], + DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); } /* Temporal Super sampling jitter */ @@ -221,7 +237,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if (do_taa) { - volumetrics->history_alpha = 0.0f; + common_data->vol_history_alpha = 0.0f; current_sample = effects->taa_current_sample - 1; effects->volume_current_sample = -1; } @@ -234,9 +250,9 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); - volumetrics->jitter[0] = (float)ht_point[0]; - volumetrics->jitter[1] = (float)ht_point[1]; - volumetrics->jitter[2] = (float)ht_point[2]; + common_data->vol_jitter[0] = (float)ht_point[0]; + common_data->vol_jitter[1] = (float)ht_point[1]; + common_data->vol_jitter[2] = (float)ht_point[2]; /* Framebuffer setup */ DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, @@ -245,63 +261,64 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) {&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol, 4); DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, {&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol_scat, 2); DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, {&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], + (int)tex_size[0], (int)tex_size[1], tex_vol_integ, 2); - volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); - volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); - volumetrics->sample_distribution = 4.0f * (1.00001f - BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution")); - volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows"); - volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); + float integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); + float integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); + common_data->vol_light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); - if (volumetrics->use_volume_shadows) { - volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + common_data->vol_shadow_steps = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + if (BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows")) { } else { - volumetrics->shadow_step_count = 0; + common_data->vol_shadow_steps = 0; } if (DRW_viewport_is_persp_get()) { - const float clip_start = stl->g_data->viewvecs[0][2]; + float sample_distribution = BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution"); + sample_distribution = 4.0f * (1.00001f - sample_distribution); + + const float clip_start = common_data->view_vecs[0][2]; /* Negate */ - float near = volumetrics->integration_start = min_ff(-volumetrics->integration_start, clip_start - 1e-4f); - float far = volumetrics->integration_end = min_ff(-volumetrics->integration_end, near - 1e-4f); + float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f); + float far = integration_end = min_ff(-integration_end, near - 1e-4f); - volumetrics->depth_param[0] = (far - near * exp2(1.0f / volumetrics->sample_distribution)) / (far - near); - volumetrics->depth_param[1] = (1.0f - volumetrics->depth_param[0]) / near; - volumetrics->depth_param[2] = volumetrics->sample_distribution; + 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 = stl->g_data->viewvecs[0][2]; - const float clip_end = stl->g_data->viewvecs[1][2]; - volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start); - volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end); - - volumetrics->depth_param[0] = volumetrics->integration_start; - volumetrics->depth_param[1] = volumetrics->integration_end; - volumetrics->depth_param[2] = 1.0f / (volumetrics->integration_end - volumetrics->integration_start); + const float clip_start = common_data->view_vecs[0][2]; + const float clip_end = 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 (volumetrics->light_clamp == 0.0) { - volumetrics->light_clamp = FLT_MAX; + if (common_data->vol_light_clamp == 0.0) { + common_data->vol_light_clamp = FLT_MAX; } - volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); + common_data->vol_use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); return EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER; } @@ -328,12 +345,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + 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; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - static int zero = 0; DRWShadingGroup *grp; /* Quick breakdown of the Volumetric rendering: @@ -370,65 +386,59 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (wo != NULL && wo->use_nodes && wo->nodetree) { struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + grp = DRW_shgroup_material_empty_tri_batch_create(mat, + psl->volumetric_world_ps, + common_data->vol_tex_size[2]); if (grp) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); } } else { /* 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, volumetrics->froxel_tex_size[2]); + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, + psl->volumetric_world_ps, + common_data->vol_tex_size[2]); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); } /* Volumetric Objects */ - psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | + DRW_STATE_ADDITIVE); + struct GPUShader *scatter_sh = (common_data->vol_use_lights) ? e_data.volumetric_scatter_with_lamps_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(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1); + grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps, + common_data->vol_tex_size[2]); DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1); - DRW_shgroup_uniform_float(grp, "volume_shadows_steps", &volumetrics->shadow_step_count, 1); - DRW_shgroup_uniform_float(grp, "volume_history_alpha", &volumetrics->history_alpha, 1); DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering); DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction); DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission); DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase); DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history); DRW_shgroup_uniform_buffer(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); 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, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + 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_buffer(grp, "volumeScattering", &txl->volume_scatter); DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); 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_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter); DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance); DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src); DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -438,7 +448,6 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved float *texcoloc = NULL; float *texcosize = NULL; struct ModifierData *md = NULL; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; Material *ma = give_current_material(ob, 1); if (ma == NULL) { @@ -447,7 +456,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); - DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]); + 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); @@ -455,14 +464,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); if (grp) { + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); } /* Smoke Simulation */ @@ -572,6 +577,7 @@ void EEVEE_volumes_free(void) 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_lamps_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/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 302b7596cc3..55f66f5500a 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -33,19 +33,8 @@ uniform sampler2DArray utilTex; #define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -uniform vec4 aoParameters[2]; uniform sampler2D horizonBuffer; -#define aoDistance aoParameters[0].x -#define aoSamples aoParameters[0].y /* UNUSED */ -#define aoFactor aoParameters[0].z -#define aoInvSamples aoParameters[0].w /* UNUSED */ - -#define aoOffset aoParameters[1].x /* UNUSED */ -#define aoBounceFac aoParameters[1].y -#define aoQuality aoParameters[1].z -#define aoSettings aoParameters[1].w - /* aoSettings flags */ #define USE_AO 1 #define USE_BENT_NORMAL 2 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 bdc59ec345a..68299fe7546 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -11,7 +11,6 @@ uniform mat4 ProjectionMatrix; uniform mat4 ViewProjectionMatrix; uniform mat4 ViewMatrixInverse; -uniform vec4 viewvecs[2]; #ifndef SHADOW_SHADER uniform mat4 ViewMatrix; #else @@ -31,8 +30,6 @@ flat in int shFace; /* Shadow layer we are rendering to. */ #define ViewMatrix FaceViewMatrix[shFace] #endif -uniform vec2 mipRatio[10]; - /* Buffers */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; @@ -304,7 +301,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -315,7 +312,7 @@ float get_depth_from_view_z(float z) return d * 0.5 + 0.5; } else { - return (z - viewvecs[0].z) / viewvecs[1].z; + return (z - viewVecs[0].z) / viewVecs[1].z; } } @@ -328,10 +325,10 @@ vec2 get_uvs_from_view(vec3 view) vec3 get_view_space_from_depth(vec2 uvcoords, float depth) { if (ProjectionMatrix[3][3] == 0.0) { - return (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz) * get_view_z_from_depth(depth); + return (viewVecs[0].xyz + vec3(uvcoords, 0.0) * viewVecs[1].xyz) * get_view_z_from_depth(depth); } else { - return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz; + return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz; } } @@ -746,8 +743,6 @@ Closure closure_add(Closure cl1, Closure cl2) return cl; } -uniform bool sssToggle; - #if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY) layout(location = 0) out vec4 fragColor; #ifdef USE_SSS diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl new file mode 100644 index 00000000000..37106fc32bd --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -0,0 +1,55 @@ + +layout(std140) uniform common_block { + mat4 pastViewProjectionMatrix; + vec4 viewVecs[2]; + vec2 mipRatio[10]; /* To correct mip level texel mis-alignement */ + /* Ambient Occlusion */ + vec4 aoParameters[2]; + /* Volumetric */ + ivec4 volTexSize; + vec4 volDepthParameters; /* Parameters to the volume Z equation */ + vec4 volInvTexSize; + vec4 volJitter; + vec4 volCoordScale; /* To convert volume uvs to screen uvs */ + float volHistoryAlpha; + float volLightClamp; + float volShadowSteps; + bool volUseLights; + /* Screen Space Reflections */ + vec4 ssrParameters; + float ssrBorderFac; + float ssrMaxRoughness; + float ssrFireflyFac; + float ssrBrdfBias; + bool ssrToggle; + /* SubSurface Scattering */ + float sssJitterThreshold; + bool sssToggle; + /* Specular */ + bool specToggle; + /* Lamps */ + int laNumLight; + /* Probes */ + int prbNumPlanar; + int prbNumRenderCube; + int prbNumRenderGrid; + int prbIrradianceVisSize; + float prbLodCubeMax; + float prbLodPlanarMax; +}; + +/* aoParameters */ +#define aoDistance aoParameters[0].x +#define aoSamples aoParameters[0].y /* UNUSED */ +#define aoFactor aoParameters[0].z +#define aoInvSamples aoParameters[0].w /* UNUSED */ + +#define aoOffset aoParameters[1].x /* UNUSED */ +#define aoBounceFac aoParameters[1].y +#define aoQuality aoParameters[1].z +#define aoSettings aoParameters[1].w + +/* ssrParameters */ +#define ssrQuality ssrParameters.x +#define ssrThickness ssrParameters.y +#define ssrPixelSize ssrParameters.zw
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index 9043a4ca768..aa88e365d93 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -10,9 +10,6 @@ uniform sampler2DArray utilTex; #define MAX_MIP 9.0 -uniform float brdfBias; -uniform float fireflyFactor; -uniform float maxRoughness; uniform ivec2 halfresOffset; ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar) @@ -35,9 +32,6 @@ vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform int planar_count; -uniform float noiseOffset; - layout(location = 0) out ivec2 hitData; layout(location = 1) out float pdfData; @@ -125,7 +119,7 @@ void main() float a2 = roughnessSquared * roughnessSquared; /* Early out */ - if (roughness > maxRoughness + 0.2) + if (roughness > ssrMaxRoughness + 0.2) return; vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0); @@ -135,7 +129,7 @@ void main() rand.xzw *= 0.0; } /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, brdfBias); + rand.x = mix(rand.x, 0.0, ssrBrdfBias); vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); vec3 wN = transform_direction(ViewMatrixInverse, N); @@ -144,7 +138,7 @@ void main() make_orthonormal_basis(N, T, B); /* Generate tangent space */ /* Planar Reflections */ - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { PlanarData pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0); @@ -173,9 +167,6 @@ uniform sampler2D specroughBuffer; uniform isampler2D hitBuffer; uniform sampler2D pdfBuffer; -uniform int probe_count; -uniform int planar_count; - uniform int neighborOffset; const ivec2 neighbors[32] = ivec2[32]( @@ -190,8 +181,6 @@ const ivec2 neighbors[32] = ivec2[32]( ivec2( 0, 0), ivec2( 2, 2), ivec2( 2, -2), ivec2(-1, 0) ); -uniform mat4 PastViewProjectionMatrix; - out vec4 fragColor; void fallback_cubemap( @@ -202,11 +191,15 @@ void fallback_cubemap( vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); vec3 bent_normal; +#ifdef SSR_AO float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal); final_ao = specular_occlusion(dot(N, V), final_ao, roughness); +#else + const float final_ao = 1.0; +#endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; i < MAX_PROBE && i < probe_count && spec_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, W); @@ -257,7 +250,7 @@ float brightness(vec3 c) vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) { /* TODO real reprojection with motion vectors, etc... */ - return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5; + return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5; } float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) @@ -296,7 +289,7 @@ vec3 get_hit_vector( vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) { if (is_planar) { - return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, lodPlanarMax)).rgb; + return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb; } else { return textureLod(prevColorBuffer, ref_uvs, mip).rgb; @@ -361,7 +354,7 @@ vec4 get_ssr_samples( /* Compute cone footprint in screen space. */ vec4 cone_footprint = hit_dist * cone_tan; - cone_footprint = brdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; /* Estimate a cone footprint to sample a corresponding mipmap level. */ vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); @@ -395,7 +388,7 @@ vec4 get_ssr_samples( luma.z = brightness(sample[2]); luma.w = brightness(sample[3]); luma = max(vec4(1e-8), luma); - luma = 1.0 - max(vec4(0.0), luma - fireflyFactor) / luma; + luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma; sample[0] *= luma.x; sample[1] *= luma.y; @@ -474,7 +467,7 @@ void main() /* Find Planar Reflections affecting this pixel */ PlanarData pd; float planar_index; - for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) { pd = planars_data[i]; float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0); @@ -495,12 +488,12 @@ void main() float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - vec2 source_uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; + vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; - if (roughness < maxRoughness + 0.2) { + if (roughness < ssrMaxRoughness + 0.2) { ssr_accum += get_ssr_samples(hit_pdf, hit_data, pd, planar_index, worldPosition, N, V, roughnessSquared, cone_tan, source_uvs, weight_acc); } @@ -509,7 +502,7 @@ void main() if (weight_acc > 0.0) { ssr_accum /= weight_acc; /* fade between 0.5 and 1.0 roughness */ - ssr_accum.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index a0c39c79048..184eac54c26 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -8,7 +8,6 @@ layout(std140) uniform sssProfile { int sss_samples; }; -uniform float jitterThreshold; uniform sampler2D depthBuffer; uniform sampler2D sssData; uniform sampler2D sssAlbedo; @@ -22,7 +21,6 @@ uniform sampler2DArray utilTex; out vec4 FragColor; uniform mat4 ProjectionMatrix; -uniform vec4 viewvecs[2]; float get_view_z_from_depth(float depth) { @@ -31,7 +29,7 @@ float get_view_z_from_depth(float depth) return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); } else { - return viewvecs[0].z + depth * viewvecs[1].z; + return viewVecs[0].z + depth * viewVecs[1].z; } } @@ -66,7 +64,7 @@ void main(void) vec3 accum = sss_data.rgb * kernel[0].rgb; for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) { - vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > jitterThreshold) ? dir : dir_rand); + vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand); vec3 color = texture(sssData, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl index 76d20486d3d..132cc16fcbd 100644 --- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl @@ -1,6 +1,5 @@ uniform sampler2DArray irradianceGrid; -uniform int irradianceVisibilitySize; #define IRRADIANCE_LIB @@ -81,8 +80,8 @@ IrradianceData load_irradiance_cell(int cell, vec3 N) float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range) { /* Keep in sync with diffuse_filter_probe() */ - ivec2 cell_co = ivec2(irradianceVisibilitySize); - ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize; + ivec2 cell_co = ivec2(prbIrradianceVisSize); + ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize; cell_co.x *= (cell % cell_per_row_col.x); cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y; float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y); @@ -90,8 +89,8 @@ float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy); vec2 co = vec2(cell_co) * texel_size; - vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize))); - uv *= vec2(irradianceVisibilitySize) * texel_size; + vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize))); + uv *= vec2(prbIrradianceVisSize) * texel_size; vec4 data = texture(irradianceGrid, vec3(co + uv, layer)); diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl index fc0b5b9548b..d10f4bc0d42 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl @@ -11,5 +11,5 @@ void main() ? normalize(cameraPos - worldPosition) : cameraForward; vec3 N = normalize(worldNormal); - FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, lodCubeMax).rgb, 1.0); + FragColor = vec4(textureLod_octahedron(probeCubes, vec4(reflect(-V, N), pid), 0.0, prbLodCubeMax).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl index eb4315c93a3..b19ee7a9ea3 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl @@ -3,6 +3,7 @@ uniform samplerCube probeHdr; uniform int probeSize; uniform float lodFactor; uniform float lodMax; +uniform float intensityFac; in vec3 worldPosition; @@ -192,6 +193,6 @@ void main() } } - FragColor = irradiance_encode(out_radiance / weight); + FragColor = irradiance_encode(intensityFac * out_radiance / weight); #endif }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 33714c5293c..3aec3ce4642 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -5,6 +5,7 @@ uniform float texelSize; uniform float lodFactor; uniform float lodMax; uniform float paddingSize; +uniform float intensityFac; in vec3 worldPosition; @@ -82,5 +83,5 @@ void main() { } } - FragColor = vec4(out_radiance / weight, 1.0); + FragColor = vec4(intensityFac * out_radiance / weight, 1.0); }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index e914228aded..429f6ea92e4 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,10 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform float lodPlanarMax; - uniform sampler2DArray probeCubes; -uniform float lodCubeMax; /* ----------- Structures --------- */ @@ -162,12 +159,12 @@ vec3 probe_evaluate_cube(float id, CubeData cd, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron(probeCubes, vec4(R, id), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, id), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * lodCubeMax, lodCubeMax).rgb; + return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( 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 a2917842d43..cc66b477da0 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -2,14 +2,6 @@ #ifndef LIT_SURFACE_UNIFORM #define LIT_SURFACE_UNIFORM -uniform int light_count; -uniform int probe_count; -uniform int grid_count; -uniform int planar_count; - -uniform bool specToggle; -uniform bool ssrToggle; - uniform float refractionDepth; #ifndef UTIL_TEX @@ -29,8 +21,6 @@ in vec3 worldNormal; in vec3 viewNormal; #endif -uniform float maxRoughness; - #endif /* LIT_SURFACE_UNIFORM */ /** AUTO CONFIG @@ -187,7 +177,7 @@ void CLOSURE_NAME( norm_view = normalize(cross(norm_view, N)); /* Normal facing view */ #endif - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ @@ -266,7 +256,7 @@ void CLOSURE_NAME( /* Planar Reflections */ /* ---------------------------- */ - for (int i = 0; i < MAX_PLANAR && i < planar_count && spec_accum.a < 0.999; ++i) { + for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) { PlanarData pd = planars_data[i]; /* Fade on geometric normal. */ @@ -312,11 +302,11 @@ void CLOSURE_NAME( /* Screen Space Refraction */ /* ---------------------------- */ #ifdef USE_REFRACTION - if (ssrToggle && roughness < maxRoughness + 0.2) { + if (ssrToggle && roughness < ssrMaxRoughness + 0.2) { /* Find approximated position of the 2nd refraction event. */ vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition; vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand); - trans.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness); + trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); accumulate_light(trans.rgb, trans.a, refr_accum); } #endif @@ -336,7 +326,7 @@ void CLOSURE_NAME( #endif /* Starts at 1 because 0 is world probe */ - for (int i = 1; ACCUM.a < 0.999 && i < probe_count && i < MAX_PROBE; ++i) { + for (int i = 1; ACCUM.a < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) { CubeData cd = probes_data[i]; float fade = probe_attenuation_cube(cd, worldPosition); @@ -448,7 +438,7 @@ void CLOSURE_NAME( /* Irradiance Grids */ /* ---------------------------- */ /* Start at 1 because 0 is world irradiance */ - for (int i = 1; i < MAX_GRID && i < grid_count && diff_accum.a < 0.999; ++i) { + for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) { GridData gd = grids_data[i]; vec3 localpos; @@ -463,7 +453,7 @@ void CLOSURE_NAME( /* ---------------------------- */ /* World Diffuse */ /* ---------------------------- */ - if (diff_accum.a < 0.999 && grid_count > 0) { + if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) { vec3 diff = probe_evaluate_world_diff(bent_normal); accumulate_light(diff, 1.0, diff_accum); } diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index c593081ce91..cb75731b7da 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -1,13 +1,5 @@ #define MAX_STEP 256 -uniform vec4 ssrParameters; - -#define ssrQuality ssrParameters.x -#define ssrThickness ssrParameters.y -#define ssrPixelSize ssrParameters.zw - -uniform float borderFadeFactor; - float sample_depth(vec2 uv, int index, float lod) { #ifdef PLANAR_PROBE_RAYTRACE @@ -233,7 +225,7 @@ vec3 raycast( float screen_border_mask(vec2 hit_co) { const float margin = 0.003; - float atten = borderFadeFactor + margin; /* Screen percentage */ + float atten = ssrBorderFac + margin; /* Screen percentage */ hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co)); float screenfade = hit_co.x * hit_co.y; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index 00e01e753f9..3a293647f84 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -4,9 +4,6 @@ #define NODETREE_EXEC -uniform ivec3 volumeTextureSize; -uniform vec3 volume_jitter; - #ifdef MESH_SHADER uniform mat4 volumeObjectMatrix; uniform vec3 volumeOrcoLoc; @@ -33,7 +30,7 @@ layout(location = 3) out vec4 volumePhase; void main() { ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); - vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volumeTextureSize); + 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); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index e12554bfabc..1a8167c2830 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -2,22 +2,16 @@ /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ -uniform float volume_light_clamp; - -uniform vec3 volume_param; /* Parameters to the volume Z equation */ - -uniform vec2 volume_uv_ratio; /* To convert volume uvs to screen uvs */ - /* Volume slice to view space depth. */ float volume_z_to_view_z(float z) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return (exp2(z / volume_param.z) - volume_param.x) / volume_param.y; + return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y; } else { /* Linear distribution */ - return mix(volume_param.x, volume_param.y, z); + return mix(volDepthParameters.x, volDepthParameters.y, z); } } @@ -25,11 +19,11 @@ float view_z_to_volume_z(float depth) { if (ProjectionMatrix[3][3] == 0.0) { /* Exponential distribution */ - return volume_param.z * log2(depth * volume_param.y + volume_param.x); + return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x); } else { /* Linear distribution */ - return (depth - volume_param.x) * volume_param.z; + return (depth - volDepthParameters.x) * volDepthParameters.z; } } @@ -38,7 +32,7 @@ vec3 volume_to_ndc(vec3 cos) { cos.z = volume_z_to_view_z(cos.z); cos.z = get_depth_from_view_z(cos.z); - cos.xy /= volume_uv_ratio; + cos.xy /= volCoordScale.xy; return cos; } @@ -46,7 +40,7 @@ vec3 ndc_to_volume(vec3 cos) { cos.z = get_view_z_from_depth(cos.z); cos.z = view_z_to_volume_z(cos.z); - cos.xy *= volume_uv_ratio; + cos.xy *= volCoordScale.xy; return cos; } @@ -90,15 +84,13 @@ vec3 light_volume(LightData ld, vec4 l_vector) power /= (l_vector.w * l_vector.w); - lum = min(lum * power, volume_light_clamp); + lum = min(lum * power, volLightClamp); return tint * lum; } #define VOLUMETRIC_SHADOW_MAX_STEP 32.0 -uniform float volume_shadows_steps; - vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction) { /* Waiting for proper volume shadowmaps and out of frustum shadow map. */ @@ -113,11 +105,11 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v { #if defined(VOLUME_SHADOW) /* Heterogeneous volume shadows */ - float dd = l_vector.w / volume_shadows_steps; + float dd = l_vector.w / volShadowSteps; vec3 L = l_vector.xyz * l_vector.w; vec3 shadow = vec3(1.0); - for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volume_shadows_steps - 0.1); s += 1.0) { - vec3 pos = ray_wpos + L * (s / volume_shadows_steps); + for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) { + vec3 pos = ray_wpos + L * (s / volShadowSteps); vec3 s_extinction = participating_media_extinction(pos, volume_extinction); shadow *= exp(-s_extinction * dd); } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl index ea402ff3d99..fcbb6661b14 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl @@ -13,28 +13,20 @@ uniform sampler3D volumePhase; uniform sampler3D historyScattering; uniform sampler3D historyTransmittance; -uniform vec3 volume_jitter; -uniform float volume_history_alpha; -uniform int light_count; -uniform mat4 PastViewProjectionMatrix; - flat in int slice; layout(location = 0) out vec4 outScattering; layout(location = 1) out vec4 outTransmittance; -#define VOLUME_LIGHTING - void main() { - vec3 volume_tex_size = vec3(textureSize(volumeScattering, 0)); ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice); /* Emission */ outScattering = texelFetch(volumeEmission, volume_cell, 0); outTransmittance = texelFetch(volumeExtinction, volume_cell, 0); vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb; - vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volume_jitter) / volume_tex_size); + vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz); vec3 worldPosition = get_world_space_from_depth(volume_ndc.xy, volume_ndc.z); vec3 wdir = cameraVec; @@ -45,7 +37,7 @@ void main() outScattering.rgb += irradiance_volumetric(worldPosition) * s_scattering * phase_function_isotropic(); #ifdef VOLUME_LIGHTING /* Lights */ - for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { + for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) { LightData ld = lights_data[i]; @@ -63,16 +55,16 @@ void main() /* Temporal supersampling */ /* Note : this uses the cell non-jittered position (texel center). */ - vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) / volume_tex_size); + vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) * volInvTexSize.xyz); vec3 wpos = get_world_space_from_depth(curr_ndc.xy, curr_ndc.z); - vec3 prev_ndc = project_point(PastViewProjectionMatrix, wpos); + vec3 prev_ndc = project_point(pastViewProjectionMatrix, wpos); vec3 prev_volume = ndc_to_volume(prev_ndc * 0.5 + 0.5); - if ((volume_history_alpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { + if ((volHistoryAlpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) { vec4 h_Scattering = texture(historyScattering, prev_volume); vec4 h_Transmittance = texture(historyTransmittance, prev_volume); - outScattering = mix(outScattering, h_Scattering, volume_history_alpha); - outTransmittance = mix(outTransmittance, h_Transmittance, volume_history_alpha); + outScattering = mix(outScattering, h_Scattering, volHistoryAlpha); + outTransmittance = mix(outTransmittance, h_Transmittance, volHistoryAlpha); } /* Catch NaNs */ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 8b95661681d..1f16f63ba14 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -358,6 +358,7 @@ void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); +void DRW_pass_state_set(DRWPass *pass, DRWState state); void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData); void DRW_pass_sort_shgroup_z(DRWPass *pass); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 442f30bfcbb..5faf397cc37 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -65,6 +65,7 @@ static struct DRWShapeCache { Gwn_Batch *drw_field_tube_limit; Gwn_Batch *drw_field_cone_limit; Gwn_Batch *drw_lamp; + Gwn_Batch *drw_lamp_shadows; Gwn_Batch *drw_lamp_sunrays; Gwn_Batch *drw_lamp_area; Gwn_Batch *drw_lamp_hemi; @@ -87,6 +88,7 @@ static struct DRWShapeCache { Gwn_Batch *drw_bone_point_wire; Gwn_Batch *drw_bone_arrows; Gwn_Batch *drw_camera; + Gwn_Batch *drw_camera_frame; Gwn_Batch *drw_camera_tria; Gwn_Batch *drw_camera_focus; Gwn_Batch *drw_particle_cross; @@ -1013,14 +1015,14 @@ Gwn_Batch *DRW_cache_lamp_get(void) Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2); - for (int a = 0; a < NSEGMENTS; a++) { - v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS)); - v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v); + for (int a = 0; a < NSEGMENTS * 2; a += 2) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v); - v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); - v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v); + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v); } SHC.drw_lamp = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); @@ -1029,6 +1031,38 @@ Gwn_Batch *DRW_cache_lamp_get(void) #undef NSEGMENTS } +Gwn_Batch *DRW_cache_lamp_shadows_get(void) +{ +#define NSEGMENTS 10 + if (!SHC.drw_lamp_shadows) { + float v[2]; + + /* Position Only 3D format */ + static Gwn_VertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, NSEGMENTS * 2); + + for (int a = 0; a < NSEGMENTS * 2; a += 2) { + v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a, v); + + v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2)); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v); + } + + SHC.drw_lamp_shadows = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + return SHC.drw_lamp_shadows; +#undef NSEGMENTS +} + Gwn_Batch *DRW_cache_lamp_sunrays_get(void) { if (!SHC.drw_lamp_sunrays) { @@ -1852,7 +1886,7 @@ Gwn_Batch *DRW_cache_bone_envelope_distance_outline_get(void) const float x = cosf(alpha); const float y = -sinf(alpha); - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){x, y, head_tail, 1.0f}); if (is_headtail_transition) { @@ -1886,7 +1920,7 @@ Gwn_Batch *DRW_cache_bone_envelope_wire_outline_get(void) /* Two lines between head and tail circles. */ /* Encoded lines, vertex shader gives them final correct value. */ - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 0.0f, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ 1.0f, 0.0f, 1.0f, 0.0f}); GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){-1.0f, 0.0f, 0.0f, 0.0f}); @@ -1922,7 +1956,7 @@ Gwn_Batch *DRW_cache_bone_envelope_head_wire_outline_get(void) const float x = cosf(alpha); const float y = -sinf(alpha); - /* { X, Y, head/tail, inner/outer border } */ + /* { X, Y, head/tail, inner/outer border } */ GWN_vertbuf_attr_set(vbo, pos_id, v_idx++, (const float[4]){ x, y, 0.0f, 0.0f}); } @@ -2002,97 +2036,139 @@ Gwn_Batch *DRW_cache_bone_arrows_get(void) /** \name Camera * \{ */ +/** + * We could make these more generic functions. + * although filling 1d lines is not common. + * + * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately. + */ + +static const float camera_coords_frame_bounds[5] = { + 0.0f, /* center point */ + 1.0f, /* + X + Y */ + 2.0f, /* + X - Y */ + 3.0f, /* - X - Y */ + 4.0f, /* - X + Y */ +}; + +static const float camera_coords_frame_tri[3] = { + 5.0f, /* tria + X */ + 6.0f, /* tria - X */ + 7.0f, /* tria + Y */ +}; + +/** Draw a loop of lines. */ +static void camera_fill_lines_loop_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i_prev]; + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + +/** Fan lines out from the first vertex. */ +static void camera_fill_lines_fan_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 1; i < coords_len; i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[0]; + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + +/** Simply fill the array. */ +static void camera_fill_array_fl_v1( + Gwn_VertBufRaw *pos_step, + const float *coords, const uint coords_len) +{ + for (uint i = 0; i < coords_len; i++) { + *((float *)GWN_vertbuf_raw_step(pos_step)) = coords[i]; + } +} + + Gwn_Batch *DRW_cache_camera_get(void) { if (!SHC.drw_camera) { - float v0 = 0.0f; /* Center point */ - float v1 = 1.0f; /* + X + Y */ - float v2 = 2.0f; /* + X - Y */ - float v3 = 3.0f; /* - X - Y */ - float v4 = 4.0f; /* - X + Y */ - float v5 = 5.0f; /* tria + X */ - float v6 = 6.0f; /* tria - X */ - float v7 = 7.0f; /* tria + Y */ - int v_idx = 0; - static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { - /* use x coordinate to identify the vertex - * the vertex shader take care to place it - * appropriatelly */ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); } /* Vertices */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 22); - - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); + const int vbo_len_capacity = 22; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); + /* camera cone (from center to frame) */ + camera_fill_lines_fan_fl_v1(&pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); + /* camera frame (skip center) */ + camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v0); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); + /* camera triangle (above the frame) */ + camera_fill_lines_loop_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri)); - /* camera frame */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v2); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); + SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + } + return SHC.drw_camera; +} - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v3); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); +Gwn_Batch *DRW_cache_camera_frame_get(void) +{ + if (!SHC.drw_camera_frame) { - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v4); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v1); + static Gwn_VertFormat format = { 0 }; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + } - /* tria */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); + /* Vertices */ + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + const int vbo_len_capacity = 8; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); + /* camera frame (skip center) */ + camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); - SHC.drw_camera = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); + SHC.drw_camera_frame = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); } - return SHC.drw_camera; + return SHC.drw_camera_frame; } Gwn_Batch *DRW_cache_camera_tria_get(void) { if (!SHC.drw_camera_tria) { - float v5 = 5.0f; /* tria + X */ - float v6 = 6.0f; /* tria - X */ - float v7 = 7.0f; /* tria + Y */ - int v_idx = 0; - static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { - /* use x coordinate to identify the vertex - * the vertex shader take care to place it - * appropriatelly */ attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); } /* Vertices */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 6); + const int vbo_len_capacity = 3; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + /* camera triangle (above the frame) */ + camera_fill_array_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri)); - /* tria */ - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v5); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v6); - GWN_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, &v7); + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); SHC.drw_camera_tria = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); } diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 3bef2940175..10539af5a94 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -74,6 +74,7 @@ struct Gwn_Batch *DRW_cache_field_cone_limit_get(void); /* Lamps */ struct Gwn_Batch *DRW_cache_lamp_get(void); +struct Gwn_Batch *DRW_cache_lamp_shadows_get(void); struct Gwn_Batch *DRW_cache_lamp_sunrays_get(void); struct Gwn_Batch *DRW_cache_lamp_area_get(void); struct Gwn_Batch *DRW_cache_lamp_hemi_get(void); @@ -82,6 +83,7 @@ struct Gwn_Batch *DRW_cache_lamp_spot_square_get(void); /* Camera */ struct Gwn_Batch *DRW_cache_camera_get(void); +struct Gwn_Batch *DRW_cache_camera_frame_get(void); struct Gwn_Batch *DRW_cache_camera_tria_get(void); /* Speaker */ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 41fb5c1ab8b..e5b959cdd3b 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -817,16 +817,10 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa else { switch (input->type) { case GPU_FLOAT: - DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC2: - DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC3: - DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1); - break; case GPU_VEC4: - DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1); + /* Should already be in the material ubo. */ break; case GPU_MAT3: DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec); @@ -1296,6 +1290,11 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) return pass; } +void DRW_pass_state_set(DRWPass *pass, DRWState state) +{ + pass->state = state; +} + void DRW_pass_free(DRWPass *pass) { for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { @@ -2309,6 +2308,7 @@ void DRW_framebuffer_init( DRWFboTexture textures[MAX_FBO_TEX], int textures_len) { BLI_assert(textures_len <= MAX_FBO_TEX); + BLI_assert(width > 0 && height > 0); bool create_fb = false; int color_attachment = -1; diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 7f4d595fd43..091edf10435 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -191,6 +191,7 @@ typedef struct OBJECT_PrivateData { /* Camera */ DRWShadingGroup *camera; + DRWShadingGroup *camera_frame; DRWShadingGroup *camera_tria; DRWShadingGroup *camera_focus; DRWShadingGroup *camera_clip; @@ -938,6 +939,9 @@ static void OBJECT_cache_init(void *vedata) geom = DRW_cache_camera_get(); stl->g_data->camera = shgroup_camera_instance(psl->non_meshes, geom); + geom = DRW_cache_camera_frame_get(); + stl->g_data->camera_frame = shgroup_camera_instance(psl->non_meshes, geom); + geom = DRW_cache_camera_tria_get(); stl->g_data->camera_tria = shgroup_camera_instance(psl->non_meshes, geom); @@ -995,6 +999,7 @@ static void OBJECT_cache_init(void *vedata) geom = DRW_cache_lamp_get(); stl->g_data->lamp_circle = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle); + geom = DRW_cache_lamp_shadows_get(); stl->g_data->lamp_circle_shadow = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircleShadow); geom = DRW_cache_lamp_sunrays_get(); @@ -1249,9 +1254,11 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; + RegionView3D *rv3d = draw_ctx->rv3d; Camera *cam = ob->data; const bool is_active = (ob == v3d->camera); + const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB)); float *color; DRW_object_wire_theme_get(ob, view_layer, &color); @@ -1264,7 +1271,7 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v BKE_camera_view_frame_ex(scene, cam, cam->drawsize, false, scale, asp, shift, &drawsize, vec); - // /* Frame coords */ + /* Frame coords */ copy_v2_v2(cam->drwcorners[0], vec[0]); copy_v2_v2(cam->drwcorners[1], vec[1]); copy_v2_v2(cam->drwcorners[2], vec[2]); @@ -1279,13 +1286,23 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v cam->drwtria[1][0] = shift[0]; cam->drwtria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); - DRW_shgroup_call_dynamic_add(stl->g_data->camera, color, cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); - - /* Active cam */ - if (is_active) { + if (look_through) { + /* Only draw the frame. */ + DRW_shgroup_call_dynamic_add( + stl->g_data->camera_frame, color, cam->drwcorners, + &cam->drwdepth, cam->drwtria, ob->obmat); + } + else { DRW_shgroup_call_dynamic_add( - stl->g_data->camera_tria, color, - cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); + stl->g_data->camera, color, cam->drwcorners, + &cam->drwdepth, cam->drwtria, ob->obmat); + + /* Active cam */ + if (is_active) { + DRW_shgroup_call_dynamic_add( + stl->g_data->camera_tria, color, + cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat); + } } /* draw the rest in normalize object space */ diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 2a84ca7f297..65c55b6cd22 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -31,6 +31,500 @@ set(SRC ) +# Order matches "UI_icons.h", final name will be formatted: "icons{size}_{name}.dat" +set(ICON_NAMES + question + error + cancel + tria_right + tria_down + tria_left + tria_up + arrow_leftright + plus + disclosure_tri_down + disclosure_tri_right + radiobut_off + radiobut_on + menu_panel + blender + grip + dot + collapsemenu + x + go_left + plug + ui + node + node_sel + fullscreen + splitscreen + rightarrow_thin + bordermove + viewzoom + zoomin + zoomout + panel_close + copy_id + eyedropper + link_area + auto + checkbox_dehlt + checkbox_hlt + unlocked + locked + unpinned + pinned + screen_back + rightarrow + downarrow_hlt + dotsup + dotsdown + link + inlink + plugin + help + ghost_enabled + color + linked + unlinked + hand + zoom_all + zoom_selected + zoom_previous + zoom_in + zoom_out + render_region + border_rect + border_lasso + freeze + stylus_pressure + ghost_disabled + new + file_tick + quit + url + recover_last + fullscreen_enter + fullscreen_exit + lamp + material + texture + anim + world + scene + edit + game + radio + script + particles + physics + speaker + texture_shaded + view3d + ipo + oops + buts + filesel + image_col + info + sequence + text + imasel + sound + action + nla + scriptwin + time + nodetree + logic + console + preferences + clip + asset_manager + object_datamode + editmode_hlt + facesel_hlt + vpaint_hlt + tpaint_hlt + wpaint_hlt + sculptmode_hlt + pose_hlt + particlemode + lightpaint + greasepencil_stroke_paint + scene_data + renderlayers + world_data + object_data + mesh_data + curve_data + meta_data + lattice_data + lamp_data + material_data + texture_data + anim_data + camera_data + particle_data + library_data_direct + group + armature_data + pose_data + bone_data + constraint + shapekey_data + constraint_bone + camera_stereo + package + uglypackage + brush_data + image_data + file + fcurve + font_data + render_result + surface_data + empty_data + settings + render_animation + render_still + library_data_broken + boids + strands + library_data_indirect + greasepencil + line_data + library_data_override + group_bone + group_vertex + group_vcol + group_uvs + rna + rna_add + outliner_ob_empty + outliner_ob_mesh + outliner_ob_curve + outliner_ob_lattice + outliner_ob_meta + outliner_ob_lamp + outliner_ob_camera + outliner_ob_armature + outliner_ob_font + outliner_ob_surface + outliner_ob_speaker + outliner_ob_force_field + outliner_ob_group_instance + outliner_ob_greasepencil + restrict_color_off + restrict_color_on + restrict_view_off + restrict_view_on + restrict_select_off + restrict_select_on + restrict_render_off + restrict_render_on + outliner_data_empty + outliner_data_mesh + outliner_data_curve + outliner_data_lattice + outliner_data_meta + outliner_data_lamp + outliner_data_camera + outliner_data_armature + outliner_data_font + outliner_data_surface + outliner_data_speaker + outliner_data_pose + outliner_data_greasepencil + mesh_plane + mesh_cube + mesh_circle + mesh_uvsphere + mesh_icosphere + mesh_grid + mesh_monkey + mesh_cylinder + mesh_torus + mesh_cone + mesh_capsule + lamp_point + lamp_sun + lamp_spot + lamp_hemi + lamp_area + meta_empty + meta_plane + meta_cube + meta_ball + meta_ellipsoid + meta_capsule + surface_ncurve + surface_ncircle + surface_nsurface + surface_ncylinder + surface_nsphere + surface_ntorus + curve_bezcurve + curve_bezcircle + curve_ncurve + curve_ncircle + curve_path + color_red + color_green + color_blue + tria_right_bar + tria_down_bar + tria_left_bar + tria_up_bar + force_force + force_wind + force_vortex + force_magnetic + force_harmonic + force_charge + force_lennardjones + force_texture + force_curve + force_boid + force_turbulence + force_drag + force_smokeflow + node_insert_on + node_insert_off + modifier + mod_wave + mod_build + mod_decim + mod_mirror + mod_soft + mod_subsurf + hook + mod_physics + mod_particles + mod_boolean + mod_edgesplit + mod_array + mod_uvproject + mod_displace + mod_curve + mod_lattice + constraint_data + mod_armature + mod_shrinkwrap + mod_cast + mod_meshdeform + mod_bevel + mod_smooth + mod_simpledeform + mod_mask + mod_cloth + mod_explode + mod_fluidsim + mod_multires + mod_smoke + mod_solidify + mod_screw + mod_vertex_weight + mod_dynamicpaint + mod_remesh + mod_ocean + mod_warp + mod_skin + mod_triangulate + mod_wireframe + mod_data_transfer + mod_normaledit + rec + play + ff + rew + pause + prev_keyframe + next_keyframe + play_audio + play_reverse + preview_range + action_tweak + pmarker_act + pmarker_sel + pmarker + marker_hlt + marker + space2 + space3 + keyingset + key_dehlt + key_hlt + mute_ipo_off + mute_ipo_on + visible_ipo_off + visible_ipo_on + driver + solo_off + solo_on + frame_prev + frame_next + nla_pushdown + ipo_constant + ipo_linear + ipo_bezier + ipo_sine + ipo_quad + ipo_cubic + ipo_quart + ipo_quint + ipo_expo + ipo_circ + ipo_bounce + ipo_elastic + ipo_back + ipo_ease_in + ipo_ease_out + ipo_ease_in_out + normalize_fcurves + vertexsel + edgesel + facesel + loopsel + rotate + cursor + rotatecollection + rotatecenter + rotactive + align + smoothcurve + spherecurve + rootcurve + sharpcurve + lincurve + nocurve + rndcurve + prop_off + prop_on + prop_con + particle_point + particle_tip + particle_path + man_trans + man_rot + man_scale + manipul + snap_off + snap_on + snap_normal + snap_grid + snap_vertex + snap_edge + snap_face + snap_volume + snap_increment + sticky_uvs_loc + sticky_uvs_disable + sticky_uvs_vert + clipuv_dehlt + clipuv_hlt + snap_peel_object + grid + object_origin + pastedown + copydown + pasteflipup + pasteflipdown + snap_surface + automerge_on + automerge_off + retopo + uv_vertexsel + uv_edgesel + uv_facesel + uv_islandsel + uv_sync_select + bbox + wire + solid + smooth + potato + ortho + lockview_off + lockview_on + axis_side + axis_front + axis_top + ndof_dom + ndof_turn + ndof_fly + ndof_trans + layer_used + layer_active + sortalpha + sortbyext + sorttime + sortsize + longdisplay + shortdisplay + ghost + imgdisplay + save_as + save_copy + bookmarks + fontpreview + filter + newfolder + open_recent + file_parent + file_refresh + file_folder + file_blend + file_image + file_movie + file_script + file_sound + file_font + file_text + recover_auto + save_prefs + link_blend + append_blend + import + export + external_data + load_factory + loop_back + loop_forwards + back + forward + file_hidden + file_backup + disk_drive + matplane + matsphere + matcube + monkey + hair + aliased + antialiased + mat_sphere_sky + wordwrap_off + wordwrap_on + syntax_off + syntax_on + linenumbers_off + linenumbers_on + scriptplugins + seq_sequencer + seq_preview + seq_luma_waveform + seq_chroma_scope + seq_histogram + seq_splitview + image_rgb + image_rgb_alpha + image_alpha + image_zdepth + imagefile +) + data_to_c_simple(../../../../release/datafiles/bfont.pfb SRC) data_to_c_simple(../../../../release/datafiles/bfont.ttf SRC) data_to_c_simple(../../../../release/datafiles/bmonofont.ttf SRC) @@ -53,12 +547,12 @@ if(WITH_BLENDER) #../../../../release/datafiles/blender_icons16.png #90 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 "icon16_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC) #svg_to_png(../../../../release/datafiles/blender_icons.svg #../../../../release/datafiles/blender_icons32.png #180 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 "icon32_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC) #svg_to_png(../../../../release/datafiles/prvicons.svg #../../../../release/datafiles/prvicons.png @@ -130,4 +624,6 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/startup.blend SRC) endif() +unset(ICON_NAMES) + blender_add_lib(bf_editor_datafiles "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a82148788c8..22a3224e563 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -105,7 +105,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ED_gpencil_reset_layers_parent(gpd); } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; @@ -153,7 +154,8 @@ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ts->gp_sculpt.alpha = 1.0f; } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index e66e5e7462d..8201401296a 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -236,6 +236,8 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspm eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); +float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); + float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); bool ED_view3d_win_to_ray( @@ -308,8 +310,6 @@ void ED_view3d_clipping_set(struct RegionView3D *rv3d); void ED_view3d_clipping_enable(void); void ED_view3d_clipping_disable(void); -float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); - float ED_view3d_radius_to_dist_persp(const float angle, const float radius); float ED_view3d_radius_to_dist_ortho(const float lens, const float radius); float ED_view3d_radius_to_dist( @@ -446,6 +446,9 @@ uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d) uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen); bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); +void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp); +bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar); + /* camera lock functions */ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); @@ -462,7 +465,7 @@ bool ED_view3d_camera_lock_autokey( struct View3D *v3d, struct RegionView3D *rv3d, struct bContext *C, const bool do_rotate, const bool do_translate); -void ED_view3D_lock_clear(struct View3D *v3d); +void ED_view3d_lock_clear(struct View3D *v3d); #define VIEW3D_MARGIN 1.4f #define VIEW3D_DIST_FALLBACK 1.0f diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 0b846ad642f..b6714e80e80 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -190,8 +190,8 @@ DEF_ICON(SCULPTMODE_HLT) DEF_ICON(POSE_HLT) DEF_ICON(PARTICLEMODE) DEF_ICON(LIGHTPAINT) +DEF_ICON(GREASEPENCIL_STROKE_PAINT) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK063) DEF_ICON(BLANK064) DEF_ICON(BLANK065) DEF_ICON(BLANK066) @@ -313,6 +313,7 @@ DEF_ICON(OUTLINER_OB_SURFACE) DEF_ICON(OUTLINER_OB_SPEAKER) DEF_ICON(OUTLINER_OB_FORCE_FIELD) DEF_ICON(OUTLINER_OB_GROUP_INSTANCE) +DEF_ICON(OUTLINER_OB_GREASEPENCIL) DEF_ICON(OUTLINER_OB_GROOM) #ifndef DEF_ICON_BLANK_SKIP DEF_ICON(BLANK123) @@ -344,8 +345,8 @@ DEF_ICON(OUTLINER_DATA_FONT) DEF_ICON(OUTLINER_DATA_SURFACE) DEF_ICON(OUTLINER_DATA_SPEAKER) DEF_ICON(OUTLINER_DATA_POSE) +DEF_ICON(OUTLINER_DATA_GREASEPENCIL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK130) DEF_ICON(BLANK131) DEF_ICON(BLANK132) DEF_ICON(BLANK133) @@ -713,8 +714,8 @@ DEF_ICON(CLIPUV_DEHLT) DEF_ICON(CLIPUV_HLT) DEF_ICON(SNAP_PEEL_OBJECT) DEF_ICON(GRID) +DEF_ICON(OBJECT_ORIGIN) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK221) DEF_ICON(BLANK222) DEF_ICON(BLANK224) DEF_ICON(BLANK225) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 5d7a45a7e48..6e09318314d 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1105,6 +1105,8 @@ void UI_context_active_but_prop_get_templateID( struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); +uiBut *UI_region_active_but_get(struct ARegion *ar); + /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, @@ -1151,7 +1153,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* ui_interface_region_tooltip.c */ struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but); struct ARegion *UI_tooltip_create_from_manipulator(struct bContext *C, struct wmManipulator *mpr); -void UI_tooltip_free(struct bContext *C, struct ARegion *ar); +void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar); /* How long before a tool-tip shows. */ #define UI_TOOLTIP_DELAY 0.5 diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 9c1cee915e4..3af64c8c5a6 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -296,8 +296,6 @@ typedef struct uiHandleButtonData { ColorBand *coba; /* tooltip */ - ARegion *tooltip; - wmTimer *tooltiptimer; unsigned int tooltip_force : 1; /* auto open */ @@ -7701,12 +7699,12 @@ static bool button_modal_state(uiHandleButtonState state) */ void UI_but_tooltip_refresh(bContext *C, uiBut *but) { - uiHandleButtonData *data; - - data = but->active; - if (data && data->tooltip) { - UI_tooltip_free(C, data->tooltip); - data->tooltip = UI_tooltip_create_from_button(C, data->region, but); + uiHandleButtonData *data = but->active; + if (data) { + bScreen *sc = WM_window_get_active_screen(data->window); + if (sc->tool_tip && sc->tool_tip->region) { + WM_tooltip_refresh(C, data->window); + } } } @@ -7717,39 +7715,38 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) data = but->active; if (data) { - - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } - if (data->tooltip) { - UI_tooltip_free(C, data->tooltip); - data->tooltip = NULL; - } - if (data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; } + + if (data->window) { + WM_tooltip_clear(C, data->window); + } + } +} + +static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event) +{ + uiBut *but = UI_region_active_but_get(ar); + *r_exit_on_event = false; + if (but) { + return UI_tooltip_create_from_button(C, ar, but); } + return NULL; } static void button_tooltip_timer_reset(bContext *C, uiBut *but) { wmWindowManager *wm = CTX_wm_manager(C); - uiHandleButtonData *data; - - data = but->active; + uiHandleButtonData *data = but->active; - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } + WM_tooltip_timer_clear(C, data->window); if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, UI_TOOLTIP_DELAY); + WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init); } } } @@ -8109,12 +8106,10 @@ void ui_but_active_free(const bContext *C, uiBut *but) } /* returns the active button with an optional checking function */ -static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *)) +static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *)) { uiBut *but_found = NULL; - ARegion *ar = CTX_wm_region(C); - while (ar) { uiBlock *block; uiBut *but, *activebut = NULL; @@ -8157,12 +8152,17 @@ static bool ui_context_rna_button_active_test(uiBut *but) } static uiBut *ui_context_rna_button_active(const bContext *C) { - return ui_context_button_active(C, ui_context_rna_button_active_test); + return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); } uiBut *UI_context_active_but_get(const struct bContext *C) { - return ui_context_button_active(C, NULL); + return ui_context_button_active(CTX_wm_region(C), NULL); +} + +uiBut *UI_region_active_but_get(ARegion *ar) +{ + return ui_context_button_active(ar, NULL); } /** @@ -8445,16 +8445,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } case TIMER: { - /* handle tooltip timer */ - if (event->customdata == data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - - if (!data->tooltip) - data->tooltip = UI_tooltip_create_from_button(C, data->region, but); - } /* handle menu auto open timer */ - else if (event->customdata == data->autoopentimer) { + if (event->customdata == data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index eeda0a25195..16525dfbc9e 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1485,7 +1485,7 @@ void ED_keymap_ui(wmKeyConfig *keyconf) * through until a suitable eyedropper for the active button is found */ WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS , KM_ALT, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 9a818efebee..07fbefa42e1 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -953,9 +953,9 @@ ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr) return ui_tooltip_create_with_data(C, data, init_position, aspect); } -void UI_tooltip_free(bContext *C, ARegion *ar) +void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) { - ui_region_temp_remove(C, CTX_wm_screen(C), ar); + ui_region_temp_remove(C, sc, ar); } /** \} */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index b271b0b5bc6..dc68c8b58de 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1509,6 +1509,9 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), v2d->smooth_timer); v2d->smooth_timer = NULL; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } else { /* ease in/out */ diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index fc227a2aa75..1b7fd319da0 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -40,6 +40,8 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "ED_screen.h" #include "ED_object.h" @@ -447,6 +449,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) min_chain_length, keep_bind_info) ) { + DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE); return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c index ce6992e7ad9..7e57b48c77c 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c @@ -133,7 +133,6 @@ static void button2d_draw_intern( if (select == false) { if (button->shape_batch[0] != NULL) { - glEnable(GL_POLYGON_SMOOTH); glEnable(GL_LINE_SMOOTH); glLineWidth(1.0f); for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) { @@ -146,7 +145,6 @@ static void button2d_draw_intern( GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color)); GWN_batch_draw(button->shape_batch[i]); } - glDisable(GL_POLYGON_SMOOTH); glDisable(GL_LINE_SMOOTH); gpuPopMatrix(); } @@ -206,9 +204,12 @@ static int manipulator_button2d_test_select( return -1; } -static int manipulator_button2d_cursor_get(wmManipulator *UNUSED(mpr)) +static int manipulator_button2d_cursor_get(wmManipulator *mpr) { - return BC_HANDCURSOR; + if (RNA_boolean_get(mpr->ptr, "show_drag")) { + return BC_NSEW_SCROLLCURSOR; + } + return CURSOR_STD; } static void manipulator_button2d_free(wmManipulator *mpr) @@ -248,6 +249,9 @@ static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt) /* Passed to 'GPU_batch_from_poly_2d_encoded' */ RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING); + + /* Currently only used for cursor display. */ + RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", ""); } void ED_manipulatortypes_button_2d(void) diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index d7e59a05772..bd2ad21d51c 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -75,7 +75,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, DerivedMesh *dm; Scene *scene = CTX_data_scene(C); EvaluationContext eval_ctx; - LinkNode *dms = NULL; + LinkNodePair dms_pair = {NULL, NULL}; int nverts, ntris, *tris; float *verts; @@ -90,7 +90,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, ob = (Object *) oblink->link; dm = mesh_create_derived_no_virtual(&eval_ctx, scene, ob, NULL, CD_MASK_MESH); DM_ensure_tessface(dm); - BLI_linklist_prepend(&dms, dm); + BLI_linklist_append(&dms_pair, dm); nverts += dm->getNumVerts(dm); nfaces = dm->getNumTessFaces(dm); @@ -106,6 +106,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, *r_lay |= ob->lay; } + LinkNode *dms = dms_pair.list; /* create data */ verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts"); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index af131e270ef..89b131fa340 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2123,7 +2123,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer #define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } - Base *basen = NULL; + Base *base, *basen = NULL; Material ***matarar; Object *obn; ID *id; @@ -2136,7 +2136,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_collection_object_add_from(scene, ob, obn); + base = BKE_view_layer_base_find(view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLED)) { + BKE_collection_object_add_from(scene, ob, obn); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); + BKE_collection_object_add(&scene->id, layer_collection->scene_collection, obn); + } basen = BKE_view_layer_base_find(view_layer, obn); /* 1) duplis should end up in same group as the original @@ -2486,13 +2493,13 @@ static int add_named_exec(bContext *C, wmOperator *op) clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); - BKE_scene_object_base_flag_sync_from_object(basen); if (basen == NULL) { BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } + BKE_scene_object_base_flag_sync_from_object(basen); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2510,9 +2517,11 @@ static int add_named_exec(bContext *C, wmOperator *op) BKE_main_id_clear_newpoins(bmain); + /* TODO(sergey): Only update relations for the current scene. */ DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index b351bc7f114..13cc53c04a7 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1679,9 +1679,6 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen } } - /* we reset filter objects because they should be regenerated after this */ - BLI_freelistN(&sc->filter_objects); - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups); } @@ -1741,9 +1738,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in libblock_relink_scene_collection(msc); set_sca_new_poins(); - - /* TODO redo filter */ - TODO_LAYER_SYNC_FILTER } /* not an especially efficient function, only added so the single user diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 6fdbe5e88a2..270ba2a7947 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -427,7 +427,8 @@ static int material_slot_move_exec(bContext *C, wmOperator *op) MEM_freeN(slot_remap); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 694770d088d..2e4e9127ed6 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -288,7 +288,7 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos } /** - * Only for edge lines between areas, and the blended join arrows. + * Only for edge lines between areas. */ void ED_screen_draw_edges(wmWindow *win) { @@ -326,6 +326,12 @@ void ED_screen_draw_edges(wmWindow *win) screen->do_draw = false; } +/** + * The blended join arrows. + * + * \param sa1: Area from which the resultant originates. + * \param sa2: Target area that will be replaced. + */ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2) { unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index b73174917f3..030c24b0061 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1479,8 +1479,6 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) */ typedef struct sAreaSplitData { - int x, y; /* last used mouse position */ - int origval; /* for move areas */ int bigger, smaller; /* constraints for moving new edge */ int delta; /* delta move edge */ @@ -1727,9 +1725,6 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) sd = (sAreaSplitData *)op->customdata; - sd->x = event->x; - sd->y = event->y; - if (event->type == EVT_ACTIONZONE_AREA) { /* do the split */ @@ -1797,28 +1792,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) /* execute the events */ switch (event->type) { case MOUSEMOVE: - { - const int dir = RNA_property_enum_get(op->ptr, prop_dir); - - sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; - if (sd->previewmode == 0) - area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, sd->do_snap); - else { - if (sd->sarea) { - ED_area_tag_redraw(sd->sarea); - } - /* area context not set */ - sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); - - if (sd->sarea) { - ED_area_tag_redraw(sd->sarea); - update_factor = true; - } - - CTX_wm_screen(C)->do_draw = true; - } + update_factor = true; break; - } + case LEFTMOUSE: if (sd->previewmode) { area_split_apply(C, op); @@ -1845,8 +1821,6 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v'); area_split_preview_update_cursor(C, op); update_factor = true; - - ED_area_tag_redraw(sd->sarea); } } } @@ -1866,31 +1840,53 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) if (update_factor) { const int dir = RNA_property_enum_get(op->ptr, prop_dir); - float fac; - if (dir == 'v') { - sd->origsize = sd->sarea->winx; - sd->origmin = sd->sarea->totrct.xmin; + sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; + + if (sd->previewmode == 0) { + if (sd->do_snap) { + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller); + sd->delta = snap_loc - sd->origval; + } + area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false); } else { - sd->origsize = sd->sarea->winy; - sd->origmin = sd->sarea->totrct.ymin; - } + if (sd->sarea) { + ED_area_tag_redraw(sd->sarea); + } + /* area context not set */ + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); + + if (sd->sarea) { + ScrArea *sa = sd->sarea; + if (dir == 'v') { + sd->origsize = sa->winx; + sd->origmin = sa->totrct.xmin; + } + else { + sd->origsize = sa->winy; + sd->origmin = sa->totrct.ymin; + } - if (sd->do_snap) { - ScrArea *sa = sd->sarea; - sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1; + if (sd->do_snap) { + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1; - int snap_loc = area_snap_calc_location( - CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin); + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin); - sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0; - fac = snap_loc - sd->origmin; - } - else { - fac = (dir == 'v') ? event->x - sd->origmin : event->y - sd->origmin; + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0; + sd->delta = snap_loc - sd->origval; + } + + ED_area_tag_redraw(sd->sarea); + } + + CTX_wm_screen(C)->do_draw = true; } - RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize); + + float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize; + RNA_float_set(op->ptr, "factor", fac); } return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 9dd51b289f4..3982c9a3c30 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -109,6 +109,8 @@ typedef struct PaintStroke { * e.g. in sculpt mode, stroke doesn't start until cursor * passes over the mesh */ bool stroke_started; + /* Set when enough motion was found for rake rotation */ + bool rake_started; /* event that started stroke, for modal() return */ int event_type; /* check if stroke variables have been initialized */ @@ -376,7 +378,12 @@ static bool paint_brush_update(bContext *C, else if (!(brush->flag & BRUSH_CURVE)) { if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) { /* Not enough motion to define an angle. */ - is_dry_run = true; + if (!stroke->rake_started) { + is_dry_run = true; + } + } + else { + stroke->rake_started = true; } } } diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 1c55a0d76cf..110c4d1789d 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1127,7 +1127,8 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op) actkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1577,7 +1578,8 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent mouse_action_keys(&ac, event->mval, selectmode, column, channel); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 0e5c5ddc0c7..ce6ce802a5b 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2792,7 +2792,8 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); WM_reportf(RPT_INFO, "Deleted %u drivers", deleted); - } else { + } + else { WM_report(RPT_INFO, "No drivers deleted"); } diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 1683fbdbdb9..392db4ef4b5 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1003,7 +1003,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) graphkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1517,7 +1518,8 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEve } /* set notifier that keyframe selection (and also channel selection in some cases) has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 2cc5c7f8d68..6c0ab33dd2c 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1858,7 +1858,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; - bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); /* error handling */ if (!rr) { diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 1179401f346..e09e4417d5d 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -444,7 +444,8 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op) nlaedit_select_leftright(C, &ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 0fdd52d3205..1bee2716e65 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -633,7 +633,8 @@ static void node_common_set_butfunc(bNodeType *ntype) /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, - PointerRNA *imaptr, PointerRNA *iuserptr) + PointerRNA *imaptr, PointerRNA *iuserptr, + bool compositor) { uiLayout *col; int source; @@ -668,7 +669,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); } - if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && + if (compositor && + RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); @@ -792,7 +794,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. */ - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -811,7 +813,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + 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); @@ -1261,7 +1263,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * imaptr = RNA_pointer_get(ptr, "image"); - node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true); node_buts_image_views(layout, C, ptr, &imaptr); } diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 1ffe62fbc00..8999555521a 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -58,9 +58,6 @@ static int collection_delete_exec(struct bContext *C, struct wmOperator *op); static LayerCollection *outliner_collection_active(bContext *C) { - TODO_LAYER_OPERATORS; - /* consider that we may have overrides or objects active - * leading to no active collections */ return CTX_data_layer_collection(C); } @@ -79,15 +76,6 @@ SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te) return NULL; } -#if 0 -static CollectionOverride *outliner_override_active(bContext *UNUSED(C)) -{ - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - return NULL; -} -#endif - /* -------------------------------------------------------------------- */ /* Poll functions. */ @@ -250,7 +238,6 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot) /* api callbacks */ ot->exec = collection_link_exec; ot->invoke = collection_link_invoke; - ot->poll = view_layer_editor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -327,14 +314,12 @@ void OUTLINER_OT_collection_unlink(wmOperatorType *ot) static int collection_new_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceOops *soops = CTX_wm_space_outliner(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); BKE_collection_link(view_layer, scene_collection); - outliner_cleanup_tree(soops); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; @@ -572,46 +557,6 @@ void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/**********************************************************************************/ - -/** - * Returns true is selected element is a collection - */ -static int collection_override_new_poll(bContext *(C)) -{ -#ifdef TODO_LAYER_OVERRIDE - /* disable for now, since it's not implemented */ - (void) C; - return 0; -#else - return outliner_collection_active(C) ? 1 : 0; -#endif -} - -static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) -{ - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet"); - return OPERATOR_CANCELLED; -} - -/* in the middle of renames remove s */ -void OUTLINER_OT_collection_override_new(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "New Override"; - ot->idname = "OUTLINER_OT_collection_override_new"; - ot->description = "Add a new override to the active collection"; - - /* api callbacks */ - ot->invoke = collection_override_new_invoke; - ot->poll = collection_override_new_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - struct CollectionDeleteData { Scene *scene; SpaceOops *soops; @@ -666,8 +611,6 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op)) data.collections_to_delete = BLI_gset_ptr_new(__func__); - TODO_LAYER_OVERRIDE; /* handle overrides */ - /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data); @@ -814,40 +757,3 @@ void OUTLINER_OT_collection_toggle(wmOperatorType *ot) #undef ACTION_TOGGLE #undef ACTION_ENABLE #undef ACTION_DISABLE - -/* -------------------------------------------------------------------- */ - -static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) -{ - TODO_LAYER_OPERATORS; - BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet"); - return OPERATOR_CANCELLED; -} - -void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Objects"; - ot->idname = "OUTLINER_OT_collection_objects_select"; - ot->description = "Select collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Deselect Objects"; - ot->idname = "OUTLINER_OT_collection_objects_deselect"; - ot->description = "Deselect collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index feeade036d1..45459bdb030 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1427,11 +1427,7 @@ static void outliner_draw_tree_element( } else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ - int icon_x; - if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE)) - icon_x = startx; - else - icon_x = startx + 5 * ufac; + int icon_x = startx; // icons a bit higher if (TSELEM_OPEN(tselem, soops)) @@ -1819,7 +1815,7 @@ static void outliner_draw_tree( // gray hierarchy lines starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; - startx = 6; + startx = UI_UNIT_X / 2 - 1.0f; outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); // items themselves diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index fb4c8cd7506..30ede0a5e55 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -48,6 +48,7 @@ struct ID; struct Object; struct bPoseChannel; struct EditBone; +struct wmEvent; struct wmKeyConfig; @@ -72,7 +73,9 @@ typedef enum TreeTraversalAction { typedef void (*TreeElementReinsertFunc)(struct Main *bmain, struct SpaceOops *soops, struct TreeElement *insert_element, - struct TreeElement *insert_handle, TreeElementInsertType action); + struct TreeElement *insert_handle, + TreeElementInsertType action, + const struct wmEvent *event); /** * Executed on (almost) each mouse move while dragging. It's supposed to give info * if reinserting insert_element before/after/into insert_handle would be allowed. @@ -104,6 +107,7 @@ typedef struct TreeElement { TreeElementInsertType insert_type; /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */ struct TreeElement *insert_handle; + void *tooltip_draw_handle; } *drag_data; } TreeElement; @@ -340,10 +344,7 @@ void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 9022552c429..52f27b9708e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -33,9 +33,13 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_main.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "UI_interface.h" @@ -48,6 +52,11 @@ #include "outliner_intern.h" +typedef struct OutlinerDragDropTooltip { + TreeElement *te; + void *handle; +} OutlinerDragDropTooltip; + enum { OUTLINER_ITEM_DRAG_CANCEL, OUTLINER_ITEM_DRAG_CONFIRM, @@ -69,9 +78,15 @@ static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *a return outliner_find_item_at_y(soops, &soops->tree, my); } -static void outliner_item_drag_end(TreeElement *dragged_te) +static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data) { - MEM_SAFE_FREE(dragged_te->drag_data); + MEM_SAFE_FREE(data->te->drag_data); + + if (data->handle) { + WM_draw_cb_exit(win, data->handle); + } + + MEM_SAFE_FREE(data); } static void outliner_item_drag_get_insert_data( @@ -164,8 +179,35 @@ static void outliner_item_drag_handle( te_dragged->drag_data->insert_handle = te_insert_handle; } -static bool outliner_item_drag_drop_apply(Main *bmain, SpaceOops *soops, TreeElement *dragged_te) +/** + * Returns true if it is a collection and empty. + */ +static bool is_empty_collection(TreeElement *te) { + if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { + return false; + } + + SceneCollection *scene_collection; + if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) { + scene_collection = (SceneCollection *)te->directdata; + } + else { + BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION); + scene_collection = ((LayerCollection *)te->directdata)->scene_collection; + } + + return BLI_listbase_is_empty(&scene_collection->objects) && + BLI_listbase_is_empty(&scene_collection->scene_collections); +} + +static bool outliner_item_drag_drop_apply( + Main *bmain, + SpaceOops *soops, + OutlinerDragDropTooltip *data, + const wmEvent *event) +{ + TreeElement *dragged_te = data->te; TreeElement *insert_handle = dragged_te->drag_data->insert_handle; TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; @@ -178,7 +220,16 @@ static bool outliner_item_drag_drop_apply(Main *bmain, SpaceOops *soops, TreeEle /* call of assert above should not have changed insert_handle and insert_type at this point */ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && dragged_te->drag_data->insert_type == insert_type); - dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type); + + /* If the collection was just created and you moved objects/collections inside it, + * it is strange to have it closed and we not see the newly dragged elements. */ + const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); + + dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event); + + if (should_open_collection && !is_empty_collection(insert_handle)) { + TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; + } return true; } @@ -190,7 +241,8 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv Main *bmain = CTX_data_main(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te_dragged = op->customdata; + OutlinerDragDropTooltip *data = op->customdata; + TreeElement *te_dragged = data->te; int retval = OPERATOR_RUNNING_MODAL; bool redraw = false; bool skip_rebuild = true; @@ -198,7 +250,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, soops, te_dragged)) { + if (outliner_item_drag_drop_apply(bmain, soops, data, event)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -210,7 +262,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv BLI_assert(0); } WM_event_add_mousemove(C); /* update highlight */ - outliner_item_drag_end(te_dragged); + outliner_item_drag_end(CTX_wm_window(C), data); redraw = true; break; case MOUSEMOVE: @@ -229,6 +281,93 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv return retval; } +/** + * Check if the given TreeElement is a collection + * + * This test is mainly used to see if next/prev TreeElement is a collection. + * It will fail when there is no next/prev TreeElement, or when the + * element is an Override or something else in the future. + */ +static bool tree_element_is_collection_get(const TreeElement *te) { + if (te == NULL) { + return false; + } + + TreeStoreElem *tselem = TREESTORE(te); + return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); +} + +static const char *outliner_drag_drop_tooltip_get( + const TreeElement *te_float) +{ + const char *name = NULL; + + const TreeElement *te_insert = te_float->drag_data->insert_handle; + if (tree_element_is_collection_get(te_float)) { + if (te_insert == NULL) { + name = TIP_("Move collection"); + } + else { + switch (te_float->drag_data->insert_type) { + case TE_INSERT_BEFORE: + if (tree_element_is_collection_get(te_insert->prev)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move before collection"); + } + break; + case TE_INSERT_AFTER: + if (tree_element_is_collection_get(te_insert->next)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move after collection"); + } + break; + case TE_INSERT_INTO: + name = TIP_("Move inside collection"); + break; + } + } + } + else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { + name = TIP_("Move to collection (Ctrl to add)"); + } + + return name; +} + +static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) +{ + OutlinerDragDropTooltip *data = vdata; + const char *tooltip; + + int cursorx, cursory; + int x, y; + + tooltip = outliner_drag_drop_tooltip_get(data->te); + if (tooltip == NULL) { + return; + } + + cursorx = win->eventstate->x; + cursory = win->eventstate->y; + + x = cursorx + U.widget_unit; + y = cursory - U.widget_unit; + + /* Drawing. */ + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; + + glEnable(GL_BLEND); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg); + glDisable(GL_BLEND); +} + static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -239,7 +378,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } - op->customdata = te_dragged; + OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__); + data->te = te_dragged; + + op->customdata = data; te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__); /* by default we don't change the item position */ te_dragged->drag_data->insert_handle = te_dragged; @@ -251,6 +393,8 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE WM_event_add_modal_handler(C, op); + data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data); + return OPERATOR_RUNNING_MODAL; } @@ -330,9 +474,6 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); - WM_operatortype_append(OUTLINER_OT_collection_override_new); - WM_operatortype_append(OUTLINER_OT_collection_objects_select); - WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); WM_operatortype_append(OUTLINER_OT_collection_nested_new); WM_operatortype_append(OUTLINER_OT_collection_delete_selected); diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index bf0dea06724..205f70e58dc 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -446,7 +446,8 @@ static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void static void outliner_object_reorder( Main *bmain, SpaceOops *soops, TreeElement *insert_element, - TreeElement *insert_handle, TreeElementInsertType action) + TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *event) { SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); SceneCollection *sc_ob_parent = NULL; @@ -459,12 +460,21 @@ static void outliner_object_reorder( .objects_selected_array = {NULL, NULL}, }; + const bool is_append = event->ctrl; + /* Make sure we include the originally inserted element as well. */ TREESTORE(insert_element)->flag |= TSE_SELECTED; outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { TreeElement *ten_selected = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(ten_selected)->id; + + if (is_append) { + BKE_collection_object_add(id, sc, ob); + continue; + } + /* Find parent scene-collection of object. */ if (ten_selected->parent) { for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { @@ -477,7 +487,7 @@ static void outliner_object_reorder( else { sc_ob_parent = BKE_collection_master(id); } - Object *ob = (Object *)TREESTORE(ten_selected)->id; + BKE_collection_object_move(id, sc, sc_ob_parent, ob); } @@ -1443,7 +1453,8 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) static void outliner_layer_collections_reorder( Main *bmain, SpaceOops *UNUSED(soops), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { LayerCollection *lc_insert = insert_element->directdata; LayerCollection *lc_handle = insert_handle->directdata; @@ -1510,7 +1521,8 @@ static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElemen static void outliner_scene_collections_reorder( Main *bmain, SpaceOops *UNUSED(soops), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { SceneCollection *sc_insert = insert_element->directdata; SceneCollection *sc_handle = insert_handle->directdata; diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 11ef781b229..d148ef3c6fe 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC view3d_select.c view3d_snap.c view3d_toolbar.c + view3d_utils.c view3d_view.c view3d_intern.h diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3bc2481a608..51dc56bafaf 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1034,7 +1034,7 @@ static void drawcube_size(float size, unsigned pos) { size, size, size} }; - const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; + const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6}; #if 0 glEnableClientState(GL_VERTEX_ARRAY); @@ -8065,7 +8065,7 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) if (solid) { /* Adpated from "Optimizing Triangle Strips for Fast Rendering" by F. Evans, S. Skiena and A. Varshney * (http://www.cs.umd.edu/gvil/papers/av_ts.pdf). */ - static const GLubyte tris_strip_indices[14] = {0,1,3,2,6,1,5,0,4,3,7,6,4,5}; + static const GLubyte tris_strip_indices[14] = {0, 1, 3, 2, 6, 1, 5, 0, 4, 3, 7, 6, 4, 5}; immBegin(GWN_PRIM_TRI_STRIP, 14); for (int i = 0; i < 14; ++i) { immVertex3fv(pos, vec[tris_strip_indices[i]]); @@ -8073,7 +8073,8 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) immEnd(); } else { - static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7}; + static const GLubyte line_indices[24] = + {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7}; immBegin(GWN_PRIM_LINES, 24); for (int i = 0; i < 24; ++i) { immVertex3fv(pos, vec[line_indices[i]]); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 64b607aa9f7..fb5b9386dde 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1128,10 +1128,12 @@ static void view3d_main_region_message_subscribe( extern StructRNA RNA_ViewLayerEngineSettingsEevee; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); } +#ifdef WITH_CLAY_ENGINE else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) { extern StructRNA RNA_ViewLayerEngineSettingsClay; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); } +#endif } /* concept is to retrieve cursor type context-less */ diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 9b07593e576..c39057431c2 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -138,13 +138,10 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl) * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { View3DCameraControl *vctrl; - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__); @@ -181,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( /* store the original camera loc and rot */ vctrl->obtfm = BKE_object_tfm_backup(ob_back); - BKE_object_where_is_calc(&eval_ctx, scene, v3d->camera); + BKE_object_where_is_calc(eval_ctx, scene, v3d->camera); negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); rv3d->dist = 0.0; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index cf43d65b44a..f734bb085d0 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -133,11 +133,18 @@ void ED_view3d_update_viewmat( view3d_winmatrix_set(depsgraph, ar, v3d, rect); /* setup view matrix */ - if (viewmat) + if (viewmat) { copy_m4_m4(rv3d->viewmat, viewmat); - else - view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - + } + else { + float rect_scale[2]; + if (rect) { + rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx; + rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy; + } + /* note: calls BKE_object_where_is_calc for camera... */ + view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d, rect ? rect_scale : NULL); + } /* update utility matrices */ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d286e608de4..1e368e2d171 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -26,6 +26,8 @@ /** \file blender/editors/space_view3d/view3d_edit.c * \ingroup spview3d + * + * 3D view manipulation/operators. */ #include <string.h> @@ -42,9 +44,7 @@ #include "MEM_guardedalloc.h" -#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" -#include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -57,13 +57,11 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_action.h" #include "DEG_depsgraph.h" -#include "BIF_gl.h" #include "WM_api.h" #include "WM_types.h" @@ -73,14 +71,12 @@ #include "ED_armature.h" #include "ED_particle.h" -#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" #include "ED_gpencil.h" #include "ED_view3d.h" -#include "DEG_depsgraph_query.h" #include "UI_resources.h" @@ -88,440 +84,9 @@ #include "view3d_intern.h" /* own include */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar); - -bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); -} - -/* ********************** view3d_edit: view manipulations ********************* */ - -/** - * \return true when the view-port is locked to its camera. - */ -bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return ((v3d->camera) && - (!ID_IS_LINKED(v3d->camera)) && - (v3d->flag2 & V3D_LOCK_CAMERA) && - (rv3d->persp == RV3D_CAMOB)); -} - -/** - * Apply the camera object transformation to the view-port. - * (needed so we can use regular view-port manipulation operators, that sync back to the camera). - */ -void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - if (calc_dist) { - /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - } - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } -} - -void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) -{ - ED_view3d_camera_lock_init_ex(v3d, rv3d, true); -} - -/** - * Apply the view-port transformation back to the camera object. - * - * \return true if the camera is moved. - */ -bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - ObjectTfmProtectedChannels obtfm; - Object *root_parent; - - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - Object *ob_update; - float tmat[4][4]; - float imat[4][4]; - float view_mat[4][4]; - float diff_mat[4][4]; - float parent_mat[4][4]; - - while (root_parent->parent) { - root_parent = root_parent->parent; - } - - ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - - normalize_m4_m4(tmat, v3d->camera->obmat); - - invert_m4_m4(imat, tmat); - mul_m4_m4m4(diff_mat, view_mat, imat); - - mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); - - BKE_object_tfm_protected_backup(root_parent, &obtfm); - BKE_object_apply_mat4(root_parent, parent_mat, true, false); - BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); - - ob_update = v3d->camera; - while (ob_update) { - DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); - ob_update = ob_update->parent; - } - } - else { - /* always maintain the same scale */ - const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); - BKE_object_tfm_protected_backup(v3d->camera, &obtfm); - ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); - BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); - - DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); - } - - return true; - } - else { - return false; - } -} - -bool ED_view3d_camera_autokey( - Scene *scene, ID *id_key, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - if (autokeyframe_cfra_can_key(scene, id_key)) { - const float cfra = (float)CFRA; - ListBase dsources = {NULL, NULL}; - - /* add data-source override for the camera object */ - ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); - - /* insert keyframes - * 1) on the first frame - * 2) on each subsequent frame - * TODO: need to check in future that frame changed before doing this - */ - if (do_rotate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - if (do_translate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - - /* free temp data */ - BLI_freelistN(&dsources); - - return true; - } - else { - return false; - } -} - -/** - * Call after modifying a locked view. - * - * \note Not every view edit currently auto-keys (numpad for eg), - * this is complicated because of smoothview. - */ -bool ED_view3d_camera_lock_autokey( - View3D *v3d, RegionView3D *rv3d, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - /* similar to ED_view3d_cameracontrol_update */ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - Scene *scene = CTX_data_scene(C); - ID *id_key; - Object *root_parent; - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - while (root_parent->parent) { - root_parent = root_parent->parent; - } - id_key = &root_parent->id; - } - else { - id_key = &v3d->camera->id; - } - - return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); - } - else { - return false; - } -} - -/** - * For viewport operators that exit camera persp. - * - * \note This differs from simply setting ``rv3d->persp = persp`` because it - * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, - * otherwise switching out of camera view may jump to a different part of the scene. - */ -static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) -{ - BLI_assert(rv3d->persp == RV3D_CAMOB); - BLI_assert(persp != RV3D_CAMOB); - - if (v3d->camera) { - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } - - if (!ED_view3d_camera_lock_check(v3d, rv3d)) { - rv3d->persp = persp; - } -} - -/* ********************* box view support ***************** */ - -static void view3d_boxview_clip(ScrArea *sa) -{ - ARegion *ar; - BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); - float clip[6][4]; - float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; - int val; - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { - if (ar->winx > ar->winy) x1 = rv3d->dist; - else x1 = ar->winx * rv3d->dist / ar->winy; - - if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; - else y1 = rv3d->dist; - copy_v2_v2(ofs, rv3d->ofs); - } - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { - ofs[2] = rv3d->ofs[2]; - - if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; - else z1 = rv3d->dist; - } - } - } - } - - for (val = 0; val < 8; val++) { - if (ELEM(val, 0, 3, 4, 7)) - bb->vec[val][0] = -x1 - ofs[0]; - else - bb->vec[val][0] = x1 - ofs[0]; - - if (ELEM(val, 0, 1, 4, 5)) - bb->vec[val][1] = -y1 - ofs[1]; - else - bb->vec[val][1] = y1 - ofs[1]; - - if (val > 3) - bb->vec[val][2] = -z1 - ofs[2]; - else - bb->vec[val][2] = z1 - ofs[2]; - } - - /* normals for plane equations */ - normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); - normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); - normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); - normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); - normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); - normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); - - /* then plane equations */ - for (val = 0; val < 6; val++) { - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); - } - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - rv3d->rflag |= RV3D_CLIPPING; - memcpy(rv3d->clip, clip, sizeof(clip)); - if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); - rv3d->clipbb = MEM_dupallocN(bb); - } - } - } - MEM_freeN(bb); -} - -/** - * Find which axis values are shared between both views and copy to \a rv3d_dst - * taking axis flipping into account. - */ -static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) -{ - /* absolute axis values above this are considered to be set (will be ~1.0f) */ - const float axis_eps = 0.5f; - float viewinv[4]; - - /* use the view rotation to identify which axis to sync on */ - float view_axis_all[4][3] = { - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}}; - - float *view_src_x = &view_axis_all[0][0]; - float *view_src_y = &view_axis_all[1][0]; - - float *view_dst_x = &view_axis_all[2][0]; - float *view_dst_y = &view_axis_all[3][0]; - int i; - - - /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_src_x); - mul_qt_v3(viewinv, view_src_y); - - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_dst_x); - mul_qt_v3(viewinv, view_dst_y); - - /* check source and dest have a matching axis */ - for (i = 0; i < 3; i++) { - if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && - ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) - { - rv3d_dst->ofs[i] = rv3d_src->ofs[i]; - } - } -} - -/* sync center/zoom view of region to others, for view transforms */ -static void view3d_boxview_sync(ScrArea *sa, ARegion *ar) -{ - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - short clip = 0; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock & RV3D_LOCKED) { - rv3dtest->dist = rv3d->dist; - view3d_boxview_sync_axis(rv3dtest, rv3d); - clip |= rv3dtest->viewlock & RV3D_BOXCLIP; - - ED_region_tag_redraw(artest); - } - } - } - - if (clip) { - view3d_boxview_clip(sa); - } -} - -/* for home, center etc */ -void view3d_boxview_copy(ScrArea *sa, ARegion *ar) -{ - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - bool clip = false; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock) { - rv3dtest->dist = rv3d->dist; - copy_v3_v3(rv3dtest->ofs, rv3d->ofs); - ED_region_tag_redraw(artest); - - clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); - } - } - } - - if (clip) { - view3d_boxview_clip(sa); - } -} - -/* 'clip' is used to know if our clip setting has changed */ -void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) -{ - ARegion *ar_sync = NULL; - RegionView3D *rv3d = ar->regiondata; - short viewlock; - /* this function copies flags from the first of the 3 other quadview - * regions to the 2 other, so it assumes this is the region whose - * properties are always being edited, weak */ - viewlock = rv3d->viewlock; - - if ((viewlock & RV3D_LOCKED) == 0) { - do_clip = (viewlock & RV3D_BOXCLIP) != 0; - viewlock = 0; - } - else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { - do_clip = true; - viewlock &= ~RV3D_BOXCLIP; - } - - for (; ar; ar = ar->prev) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - rv3d->viewlock = viewlock; - - if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { - rv3d->rflag &= ~RV3D_BOXCLIP; - } - - /* use ar_sync so we sync with one of the aligned views below - * else the view jumps on changing view settings like 'clip' - * since it copies from the perspective view */ - ar_sync = ar; - } - } - - if (rv3d->viewlock & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); - } - - /* ensure locked regions have an axis, locked user views don't make much sense */ - if (viewlock & RV3D_LOCKED) { - int index_qsplit = 0; - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - if (rv3d->viewlock) { - if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); - rv3d->persp = RV3D_ORTHO; - ED_view3d_lock(rv3d); - } - } - index_qsplit++; - } - } - } - - ED_area_tag_redraw(sa); -} - -/* ************************** init for view ops **********************************/ +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Custom-Data + * \{ */ typedef struct ViewOpsData { /* context pointers (assigned by viewops_data_alloc) */ @@ -581,13 +146,6 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) vec[2] = -z; /* yah yah! */ } - -/* -------------------------------------------------------------------- */ -/* ViewOpsData */ - -/** \name Generic View Operator Custom-Data. - * \{ */ - /** * Allocate and fill in context pointers for #ViewOpsData */ @@ -732,7 +290,7 @@ static enum eViewOpsOrbit viewops_orbit_mode(void) /** * Calculate the values for #ViewOpsData * - * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of + * \param use_ensure_persp: When enabled run #ED_view3d_persp_ensure this may switch out of * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common * so we don't want it to trigger auto-perspective). @@ -765,7 +323,7 @@ static void viewops_data_create_ex( } if (use_ensure_persp) { - if (view3d_ensure_persp(vod->v3d, vod->ar)) { + if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders * are properly updated. @@ -898,10 +456,12 @@ static void viewops_data_free(bContext *C, wmOperator *op) #endif ED_region_tag_redraw(ar); } -/** \} */ +/** \} */ -/* ************************** viewrotate **********************************/ +/* -------------------------------------------------------------------- */ +/** \name View Rotate Operator + * \{ */ enum { VIEW_PASS = 0, @@ -910,12 +470,14 @@ enum { }; /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */ -#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2 -#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3 -#define VIEWROT_MODAL_SWITCH_ZOOM 4 -#define VIEWROT_MODAL_SWITCH_MOVE 5 -#define VIEWROT_MODAL_SWITCH_ROTATE 6 +enum { + VIEW_MODAL_CONFIRM = 1, /* used for all view operations */ + VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2, + VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3, + VIEWROT_MODAL_SWITCH_ZOOM = 4, + VIEWROT_MODAL_SWITCH_MOVE = 5, + VIEWROT_MODAL_SWITCH_ROTATE = 6, +}; /* called in transform_ops.c, on each regeneration of keymaps */ void viewrotate_modal_keymap(wmKeyConfig *keyconf) @@ -1231,37 +793,6 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) return ret; } -/** - * Action to take when rotating the view, - * handle auto-persp and logic for switching out of views. - * - * shared with NDOF. - */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; - - BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - - if (ED_view3d_camera_lock_check(v3d, rv3d)) - return false; - - if (rv3d->persp != RV3D_PERSP) { - if (rv3d->persp == RV3D_CAMOB) { - /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ - char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; - view3d_persp_switch_from_camera(v3d, rv3d, persp); - } - else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->persp = RV3D_PERSP; - } - return true; - } - - return false; -} - static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; @@ -1365,11 +896,13 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; } -#ifdef WITH_INPUT_NDOF +/** \} */ +/* -------------------------------------------------------------------- */ /** \name NDOF Utility Functions * \{ */ +#ifdef WITH_INPUT_NDOF #define NDOF_HAS_TRANSLATE ((!ED_view3d_offset_lock_check(v3d, rv3d)) && !is_zero_v3(ndof->tvec)) #define NDOF_HAS_ROTATE (((rv3d->viewlock & RV3D_LOCKED) == 0) && !is_zero_v3(ndof->rvec)) @@ -1419,8 +952,9 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) * * \param has_zoom zoom, otherwise dolly, often `!rv3d->is_persp` since it doesnt make sense to dolly in ortho. */ -static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - const bool has_translate, const bool has_zoom) +static void view3d_ndof_pan_zoom( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + const bool has_translate, const bool has_zoom) { RegionView3D *rv3d = ar->regiondata; float view_inv[4]; @@ -1481,9 +1015,10 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s } -static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - /* optional, can be NULL*/ - ViewOpsData *vod) +static void view3d_ndof_orbit( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + /* optional, can be NULL*/ + ViewOpsData *vod) { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; @@ -1492,7 +1027,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); rv3d->view = RV3D_VIEW_USER; @@ -1668,11 +1203,14 @@ void view3d_ndof_fly( /** \} */ +/* -------------------------------------------------------------------- */ +/** \name NDOF Operators + * + * - "orbit" navigation (trackball/turntable) + * - zooming + * - panning in rotationally-locked views + * \{ */ -/* -- "orbit" navigation (trackball/turntable) - * -- zooming - * -- panning in rotationally-locked views - */ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -1936,8 +1474,11 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) #endif /* WITH_INPUT_NDOF */ -/* ************************ viewmove ******************************** */ +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Move (Pan) Operator + * \{ */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -1999,8 +1540,9 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) add_v3_v3(vod->rv3d->ofs, dvec); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } } vod->oldx = x; @@ -2117,7 +1659,11 @@ void VIEW3D_OT_move(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; } -/* ************************ viewzoom ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ /* viewdolly_modal_keymap has an exact copy of this, apply fixes to both */ /* called in transform_ops.c, on each regeneration of keymaps */ @@ -2359,8 +1905,9 @@ static void viewzoom_apply_3d( /* these limits were in old code too */ CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2497,8 +2044,9 @@ static int viewzoom_exec(bContext *C, wmOperator *op) } } - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2512,41 +2060,6 @@ static int viewzoom_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* this is an exact copy of viewzoom_modal_keymap */ -/* called in transform_ops.c, on each regeneration of keymaps */ -void viewdolly_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL} - }; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) return; - - keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); - - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); -} - /* viewdolly_invoke() copied this function, changes here may apply there */ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -2634,8 +2147,50 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Dolly Operator + * + * Like zoom but translates the view offset along the view direction + * which avoids #RegionView3D.dist approaching zero. + * \{ */ + +/* this is an exact copy of viewzoom_modal_keymap */ +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewdolly_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) return; + + keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); +} -/* ************************ viewdolly ******************************** */ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); @@ -2679,8 +2234,9 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv if (zfac != 1.0f) view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2780,8 +2336,9 @@ static int viewdolly_exec(bContext *C, wmOperator *op) view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f); } - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2819,7 +2376,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (vod->rv3d->persp != RV3D_PERSP) { if (vod->rv3d->persp == RV3D_CAMOB) { /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ - view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); + ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); } else { vod->rv3d->persp = RV3D_PERSP; @@ -2901,6 +2458,13 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * + * Move & Zoom the view to fit all of it's contents. + * \{ */ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, const float min[3], const float max[3], bool ok_dist, const int smooth_viewtx) @@ -2970,9 +2534,10 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, } /* same as view3d_from_minmax but for all regions (except cameras) */ -static void view3d_from_minmax_multi(bContext *C, View3D *v3d, - const float min[3], const float max[3], - const bool ok_dist, const int smooth_viewtx) +static void view3d_from_minmax_multi( + bContext *C, View3D *v3d, + const float min[3], const float max[3], + const bool ok_dist, const int smooth_viewtx) { ScrArea *sa = CTX_wm_area(C); ARegion *ar; @@ -3072,6 +2637,14 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) RNA_def_boolean(ot->srna, "center", 0, "Center", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Selected Operator + * + * Move & Zoom the view to fit selected contents. + * \{ */ + /* like a localview without local!, was centerview() in 2.4x */ static int viewselected_exec(bContext *C, wmOperator *op) { @@ -3202,12 +2775,18 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Clear Operator + * \{ */ + static int view_lock_clear_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3234,6 +2813,12 @@ void VIEW3D_OT_view_lock_clear(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock to Active Operator + * \{ */ + static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); @@ -3241,7 +2826,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); v3d->ob_centre = obact; /* can be NULL */ @@ -3285,6 +2870,12 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Cursor Operator + * \{ */ + static int viewcenter_cursor_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); @@ -3325,6 +2916,12 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Pick Operator + * \{ */ + static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); @@ -3375,6 +2972,12 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Camera Center Operator + * \{ */ + static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { const Depsgraph *depsgraph = CTX_data_depsgraph(C); @@ -3421,6 +3024,12 @@ void VIEW3D_OT_view_center_camera(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Center Operator + * \{ */ + static int view3d_center_lock_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -3447,7 +3056,11 @@ void VIEW3D_OT_view_center_lock(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Set render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Render Border Operator + * \{ */ static int render_border_exec(bContext *C, wmOperator *op) { @@ -3549,7 +3162,11 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/* ********************* Clear render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Render Border Operator + * \{ */ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3596,7 +3213,11 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************* Border Zoom operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Zoom Operator + * \{ */ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) { @@ -3724,8 +3345,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) C, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist}); - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(CTX_wm_area(C), ar); + } return OPERATOR_FINISHED; } @@ -3764,7 +3386,14 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) WM_operator_properties_gesture_border_zoom(ot); } -/* sets the view to 1:1 camera/render-pixel */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Camera Zoom 1:1 Operator + * + * Sets the view to 1:1 camera/render-pixel. + * \{ */ + static void view3d_set_1_to_1_viewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { RegionView3D *rv3d = ar->regiondata; @@ -3810,7 +3439,11 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Changing view operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis/Type Operator + * \{ */ static const EnumPropertyItem prop_view_items[] = { {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"}, @@ -3826,10 +3459,11 @@ static const EnumPropertyItem prop_view_items[] = { /* would like to make this a generic function - outside of transform */ -static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, - const float quat_[4], - short view, int perspo, bool align_active, - const int smooth_viewtx) +static void axis_set_view( + bContext *C, View3D *v3d, ARegion *ar, + const float quat_[4], + short view, int perspo, bool align_active, + const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */ float quat[4]; @@ -4049,6 +3683,12 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Orbit Operator + * \{ */ + static const EnumPropertyItem prop_view_orbit_items[] = { {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"}, {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"}, @@ -4092,7 +3732,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op) float quat_new[4]; if (view_opposite == RV3D_VIEW_USER) { - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); } if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { @@ -4169,11 +3809,13 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); - } +/** \} */ -/* ************************ viewroll ******************************** */ +/* -------------------------------------------------------------------- */ +/** \name View Roll Operator + * \{ */ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle) { @@ -4211,8 +3853,9 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs); } - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -4415,6 +4058,14 @@ static const EnumPropertyItem prop_view_pan_items[] = { {0, NULL, 0, NULL, NULL} }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * + * Move (pan) in incremental steps. + * \{ */ + static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int x = 0, y = 0; @@ -4455,6 +4106,12 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Toggle Perspective/Orthographic Operator + * \{ */ + static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d_dummy; @@ -4491,6 +4148,14 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Navigate Operator + * + * Wraps walk/fly modes. + * \{ */ + static int view3d_navigate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { eViewNavigation_Method mode = U.navigation_mode; @@ -4520,8 +4185,11 @@ void VIEW3D_OT_navigate(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } +/** \} */ -/* ******************** add background image operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name Background Image Add Operator + * \{ */ static CameraBGImage *background_image_add(bContext *C) { @@ -4580,8 +4248,12 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Background Image Remove Operator + * \{ */ -/* ***** remove image operator ******* */ static int background_image_remove_exec(bContext *C, wmOperator *op) { Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; @@ -4626,7 +4298,13 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot) RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX); } -/* ********************* set clipping operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Planes Operator + * + * Draw border or toggle off. + * \{ */ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4]) { @@ -4707,7 +4385,11 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) WM_operator_properties_border(ot); } -/* ***************** 3d cursor cursor op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Cursor Operator + * \{ */ /* cursor position in vec, result in vec, mval in region coords */ /* note: cannot use event->mval here (called by object_add() */ @@ -4819,7 +4501,11 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) } -/* ***************** manipulator op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Enable Transform Manipulator Operator + * \{ */ static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { @@ -4861,7 +4547,11 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************* Toggle rendered shading *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Render Shading Operator + * \{ */ static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -4890,315 +4580,4 @@ void VIEW3D_OT_toggle_render(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } -/* ************************* below the line! *********************** */ - - -static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) -{ - ViewDepths depth_temp = {0}; - rcti rect; - float depth_close; - - if (margin == 0) { - /* Get Z Depths, needed for perspective, nice for ortho */ - rect.xmin = mval[0]; - rect.ymin = mval[1]; - rect.xmax = mval[0] + 1; - rect.ymax = mval[1] + 1; - } - else { - BLI_rcti_init_pt_radius(&rect, mval, margin); - } - - view3d_update_depths_rect(ar, &depth_temp, &rect); - depth_close = view3d_depth_near(&depth_temp); - MEM_SAFE_FREE(depth_temp.depths); - return depth_close; -} - -/** - * Get the world-space 3d location from a screen-space 2d point. - * - * \param mval: Input screen-space pixel location. - * \param mouse_worldloc: Output world-space location. - * \param fallback_depth_pt: Use this points depth when no depth can be found. - */ -bool ED_view3d_autodist( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, - const int mval[2], float mouse_worldloc[3], - const bool alphaoverride, const float fallback_depth_pt[3]) -{ - float depth_close; - int margin_arr[] = {0, 2, 4}; - int i; - bool depth_ok = false; - - /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); - - /* Attempt with low margin's first */ - i = 0; - do { - depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); - depth_ok = (depth_close != FLT_MAX); - } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); - - if (depth_ok) { - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - - if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { - return true; - } - } - - if (fallback_depth_pt) { - ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); - return true; - } - else { - return false; - } -} - -void ED_view3d_autodist_init( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, - ARegion *ar, View3D *v3d, int mode) -{ - /* Get Z Depths, needed for perspective, nice for ortho */ - switch (mode) { - case 0: - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); - break; - case 1: - { - Scene *scene = DEG_get_evaluated_scene(graph); - ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); - break; - } - } -} - -/* no 4x4 sampling, run #ED_view3d_autodist_init first */ -bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], - int margin, float *force_depth) -{ - float depth; - - /* Get Z Depths, needed for perspective, nice for ortho */ - if (force_depth) - depth = *force_depth; - else - depth = view_autodist_depth_margin(ar, mval, margin); - - if (depth == FLT_MAX) - return false; - - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); -} - -bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) -{ - *depth = view_autodist_depth_margin(ar, mval, margin); - - return (*depth != FLT_MAX); -} - -static bool depth_segment_cb(int x, int y, void *userData) -{ - struct { ARegion *ar; int margin; float depth; } *data = userData; - int mval[2]; - float depth; - - mval[0] = x; - mval[1] = y; - - depth = view_autodist_depth_margin(data->ar, mval, data->margin); - - if (depth != FLT_MAX) { - data->depth = depth; - return 0; - } - else { - return 1; - } -} - -bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int mval_end[2], - int margin, float *depth) -{ - struct { ARegion *ar; int margin; float depth; } data = {NULL}; - int p1[2]; - int p2[2]; - - data.ar = ar; - data.margin = margin; - data.depth = FLT_MAX; - - copy_v2_v2_int(p1, mval_sta); - copy_v2_v2_int(p2, mval_end); - - BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); - - *depth = data.depth; - - return (*depth != FLT_MAX); -} - -/* problem - ofs[3] can be on same location as camera itself. - * Blender needs proper dist value for zoom. - * use fallback_dist to override small values - */ -float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) -{ - float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float dist; - - mul_m4_v4(mat, pos); - add_v3_v3(pos, ofs); - mul_m4_v4(mat, dir); - normalize_v3(dir); - - dist = dot_v3v3(pos, dir); - - if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { - dist = fallback_dist; - } - - return dist; -} - -/** - * Set the dist without moving the view (compensate with #RegionView3D.ofs) - * - * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. - */ -void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) -{ - float viewinv[4]; - float tvec[3]; - - BLI_assert(dist >= 0.0f); - - copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); - /* rv3d->viewinv isn't always valid */ -#if 0 - mul_mat3_m4_v3(rv3d->viewinv, tvec); -#else - invert_qt_qt_normalized(viewinv, rv3d->viewquat); - mul_qt_v3(viewinv, tvec); -#endif - sub_v3_v3(rv3d->ofs, tvec); - - rv3d->dist = dist; -} - -/** - * Set the view transformation from a 4x4 matrix. - * - * \param mat The view 4x4 transformation matrix to assign. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) -{ - float nmat[3][3]; - - /* dist depends on offset */ - BLI_assert(dist == NULL || ofs != NULL); - - copy_m3_m4(nmat, mat); - normalize_m3(nmat); - - /* Offset */ - if (ofs) - negate_v3_v3(ofs, mat[3]); - - /* Quat */ - if (quat) { - mat3_normalized_to_quat(quat, nmat); - invert_qt_normalized(quat); - } - - if (ofs && dist) { - madd_v3_v3fl(ofs, nmat[2], *dist); - } -} - -/** - * Calculate the view transformation matrix from RegionView3D input. - * The resulting matrix is equivalent to RegionView3D.viewinv - * \param mat The view 4x4 transformation matrix to calculate. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) -{ - float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; - float dvec[3] = {0.0f, 0.0f, dist}; - - quat_to_mat4(mat, iviewquat); - mul_mat3_m4_v3(mat, dvec); - sub_v3_v3v3(mat[3], dvec, ofs); -} - -/** - * Set the RegionView3D members from an objects transformation and optionally lens. - * \param ob The object to set the view to. - * \param ofs The view offset to be set, normally from RegionView3D.ofs. - * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. - * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. - */ -void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) -{ - ED_view3d_from_m4(ob->obmat, ofs, quat, dist); - - if (lens) { - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, ob); - *lens = params.lens; - } -} - -/** - * Set the object transformation from RegionView3D members. - * \param ob The object which has the transformation assigned. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) -{ - float mat[4][4]; - - ED_view3d_to_m4(mat, ofs, quat, dist); - BKE_object_apply_mat4(ob, mat, true, true); -} - -/** - * Use to store the last view, before entering camera view. - */ -void ED_view3d_lastview_store(RegionView3D *rv3d) -{ - copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); - rv3d->lview = rv3d->view; - if (rv3d->persp != RV3D_CAMOB) { - rv3d->lpersp = rv3d->persp; - } -} - -void ED_view3D_lock_clear(View3D *v3d) -{ - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - v3d->ob_centre_cursor = false; - v3d->flag2 &= ~V3D_LOCK_CAMERA; -} +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 8a48b1dc3aa..d2aa19509d7 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -58,6 +58,8 @@ #include "GPU_immediate.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -344,6 +346,10 @@ enum { static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); + rctf viewborder; float upvec[3]; /* tmp */ @@ -419,7 +425,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent } fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, fly->scene, fly->v3d, fly->rv3d, + &eval_ctx, fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* calculate center */ diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index df2e5315c39..5e34bc188f0 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -111,6 +111,7 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_render(struct wmOperatorType *ot); void view3d_boxview_copy(ScrArea *sa, ARegion *ar); +void view3d_boxview_sync(ScrArea *sa, ARegion *ar); void view3d_orbit_apply_dyn_ofs( float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], @@ -276,8 +277,12 @@ void ED_view3d_smooth_view_force_finish( struct bContext *C, struct View3D *v3d, struct ARegion *ar); -void view3d_winmatrix_set(const struct Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect); -void view3d_viewmatrix_set(const struct EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d); +void view3d_winmatrix_set( + const struct Depsgraph *depsgraph, + ARegion *ar, const View3D *v3d, const rcti *rect); +void view3d_viewmatrix_set( + const struct EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]); void fly_modal_keymap(struct wmKeyConfig *keyconf); void walk_modal_keymap(struct wmKeyConfig *keyconf); @@ -292,7 +297,7 @@ void view3d_buttons_register(struct ARegionType *art); /* view3d_camera_control.c */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root); void ED_view3d_cameracontrol_update( struct View3DCameraControl *vctrl, diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c index 0f7df8fe6aa..9f655fff8a1 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -163,6 +163,16 @@ struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = { struct NavigateWidgetGroup { wmManipulator *mpr_array[MPR_TOTAL]; + /* Store the view state to check for changes. */ + struct { + struct { + short winx, winy; + } ar; + struct { + char is_persp; + char viewlock; + } rv3d; + } state; int region_size[2]; bool is_persp; }; @@ -200,8 +210,6 @@ static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorG RNA_property_string_set_bytes( mpr->ptr, prop, (const char *)info->shape, info->shape_size); - /* don't fade icons so much */ - mpr->color[3] = 0.5f; } wmOperatorType *ot = WM_operatortype_find(info->opname, true); @@ -214,6 +222,15 @@ static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorG RNA_enum_set(ptr, "type", RV3D_VIEW_CAMERA); } + /* Click only buttons (not modal). */ + { + int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + RNA_boolean_set(mpr->ptr, "show_drag", false); + } + } + { wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; mpr->scale_basis = MANIPULATOR_SIZE / 2; @@ -248,16 +265,19 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGr copy_v3_v3(navgroup->mpr_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]); } - if ((navgroup->region_size[0] == ar->winx) && - (navgroup->region_size[1] == ar->winy) && - (navgroup->is_persp == rv3d->is_persp)) + if ((navgroup->state.ar.winx == ar->winx) && + (navgroup->state.ar.winy == ar->winy) && + (navgroup->state.rv3d.is_persp == rv3d->is_persp) && + (navgroup->state.rv3d.viewlock == rv3d->viewlock)) { return; } - navgroup->region_size[0] = ar->winx; - navgroup->region_size[1] = ar->winy; - navgroup->is_persp = rv3d->is_persp; + + navgroup->state.ar.winx = ar->winx; + navgroup->state.ar.winy = ar->winy; + navgroup->state.rv3d.is_persp = rv3d->is_persp; + navgroup->state.rv3d.viewlock = rv3d->viewlock; const float icon_size = MANIPULATOR_SIZE; @@ -266,36 +286,50 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGr const float co[2] = {ar->winx - icon_offset, ar->winy - icon_offset}; wmManipulator *mpr; - mpr = navgroup->mpr_array[MPR_ROTATE]; - mpr->matrix_basis[3][0] = co[0]; - mpr->matrix_basis[3][1] = co[1]; - mpr = navgroup->mpr_array[MPR_MOVE]; - mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; - mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) { + mpr = navgroup->mpr_array[i]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } - mpr = navgroup->mpr_array[MPR_ZOOM]; - mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; - mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - if (rv3d->is_persp) { - mpr = navgroup->mpr_array[MPR_PERSP]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - mpr = navgroup->mpr_array[MPR_ORTHO]; + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_ORTHO : MPR_PERSP]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_CAMERA]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); } else { - mpr = navgroup->mpr_array[MPR_ORTHO]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - mpr = navgroup->mpr_array[MPR_PERSP]; + /* RV3D_LOCKED: only show supported buttons. */ + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - } - mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; - mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; - mpr = navgroup->mpr_array[MPR_CAMERA]; - mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; - mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } } void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index bda692a0e5c..e8d540bcc9d 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -1011,7 +1011,7 @@ void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) wgt->name = "Ruler Widgets"; wgt->idname = view3d_wgt_ruler_id; - wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE; + wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL; wgt->mmap_params.spaceid = SPACE_VIEW3D; wgt->mmap_params.regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index af44629a18e..ba3e78b25b9 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -277,6 +277,11 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[ /* More Generic Window/Ray/Vector projection functions * *************************************************** */ +float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) +{ + return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; +} + /** * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta */ diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c new file mode 100644 index 00000000000..7bb3f443ac6 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -0,0 +1,1436 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_utils.c + * \ingroup spview3d + * + * 3D View checks and manipulation (no operators). + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap_draw_2d.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_screen.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_matrix.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Data Access Utilities + * + * \{ */ + +float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) +{ + if (v3d && v3d->localvd) return v3d->cursor; + else return scene->cursor; +} + +Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) +{ + /* establish the camera object, so we can default to view mapping if anything is wrong with it */ + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { + return v3d->camera->data; + } + else { + return NULL; + } +} + +void ED_view3d_dist_range_get( + const View3D *v3d, + float r_dist_range[2]) +{ + r_dist_range[0] = v3d->grid * 0.001f; + r_dist_range[1] = v3d->far * 10.0f; +} + +/** + * \note copies logic of #ED_view3d_viewplane_get(), keep in sync. + */ +bool ED_view3d_clip_range_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, + float *r_clipsta, float *r_clipend, + const bool use_ortho_factor) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + + if (use_ortho_factor && params.is_ortho) { + const float fac = 2.0f / (params.clipend - params.clipsta); + params.clipsta *= fac; + params.clipend *= fac; + } + + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + + return params.is_ortho; +} + +bool ED_view3d_viewplane_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, + rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); + + if (r_viewplane) *r_viewplane = params.viewplane; + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + if (r_pixsize) *r_pixsize = params.viewdx; + + return params.is_ortho; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name View State/Context Utilities + * + * \{ */ + +/** + * Use this call when executing an operator, + * event system doesn't set for each event the OpenGL drawing context. + */ +void view3d_operator_needs_opengl(const bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + + view3d_region_operator_needs_opengl(win, ar); +} + +void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) +{ + /* for debugging purpose, context should always be OK */ + if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { + printf("view3d_region_operator_needs_opengl error, wrong region\n"); + } + else { + RegionView3D *rv3d = ar->regiondata; + + wmSubWindowSet(win, ar->swinid); + gpuLoadProjectionMatrix(rv3d->winmat); + gpuLoadMatrix(rv3d->viewmat); + } +} + +/** + * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] + */ +void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) +{ + float viewdist; + + if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { + return; + } + + viewdist = rv3d->dist; + + /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ + if (dist != 0.0f) { + if (rv3d->persp == RV3D_CAMOB) { + if (rv3d->is_persp == false) { + viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); + } + } + } + + bglPolygonOffset(viewdist, dist); +} + +bool ED_view3d_context_activate(bContext *C) +{ + bScreen *sc = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar; + + /* sa can be NULL when called from python */ + if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { + sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); + } + + if (sa == NULL) { + return false; + } + + ar = BKE_area_find_region_active_win(sa); + if (ar == NULL) { + return false; + } + + /* bad context switch .. */ + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Utilities + * + * \{ */ + +void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) +{ + int val; + + for (val = 0; val < 4; val++) { + normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); + if (UNLIKELY(is_flip)) { + negate_v3(clip[val]); + } + + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); + } +} + +void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) +{ + /* init in case unproject fails */ + memset(bb->vec, 0, sizeof(bb->vec)); + + /* four clipping planes and bounding volume */ + /* first do the bounding volume */ + for (int val = 0; val < 4; val++) { + float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; + float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; + + ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); + ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); + } + + /* optionally transform to object space */ + if (ob) { + float imat[4][4]; + invert_m4_m4(imat, ob->obmat); + + for (int val = 0; val < 8; val++) { + mul_m4_v3(imat, bb->vec[val]); + } + } + + /* verify if we have negative scale. doing the transform before cross + * product flips the sign of the vector compared to doing cross product + * before transform then, so we correct for that. */ + int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; + + ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Bound-Box Utilities + * + * \{ */ + +static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) +{ + int a, flag = -1, fl; + + for (a = 0; a < 8; a++) { + float vec[4], min, max; + copy_v3_v3(vec, bb->vec[a]); + vec[3] = 1.0; + mul_m4_v4(persmatob, vec); + max = vec[3]; + min = -vec[3]; + + fl = 0; + if (vec[0] < min) fl += 1; + if (vec[0] > max) fl += 2; + if (vec[1] < min) fl += 4; + if (vec[1] > max) fl += 8; + if (vec[2] < min) fl += 16; + if (vec[2] > max) fl += 32; + + flag &= fl; + if (flag == 0) return true; + } + + return false; +} + +bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) +{ + /* return 1: draw */ + + float persmatob[4][4]; + + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); + + return view3d_boundbox_clip_m4(bb, persmatob); +} + +bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) +{ + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + return view3d_boundbox_clip_m4(bb, rv3d->persmatob); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Perspective & Mode Switching + * + * Misc view utility functions. + * \{ */ + +bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); +} + +/** + * Use to store the last view, before entering camera view. + */ +void ED_view3d_lastview_store(RegionView3D *rv3d) +{ + copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); + rv3d->lview = rv3d->view; + if (rv3d->persp != RV3D_CAMOB) { + rv3d->lpersp = rv3d->persp; + } +} + +void ED_view3d_lock_clear(View3D *v3d) +{ + v3d->ob_centre = NULL; + v3d->ob_centre_bone[0] = '\0'; + v3d->ob_centre_cursor = false; + v3d->flag2 &= ~V3D_LOCK_CAMERA; +} + +/** + * For viewport operators that exit camera perspective. + * + * \note This differs from simply setting ``rv3d->persp = persp`` because it + * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, + * otherwise switching out of camera view may jump to a different part of the scene. + */ +void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) +{ + BLI_assert(rv3d->persp == RV3D_CAMOB); + BLI_assert(persp != RV3D_CAMOB); + + if (v3d->camera) { + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } + + if (!ED_view3d_camera_lock_check(v3d, rv3d)) { + rv3d->persp = persp; + } +} +/** + * Action to take when rotating the view, + * handle auto-persp and logic for switching out of views. + * + * shared with NDOF. + */ +bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; + + BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); + + if (ED_view3d_camera_lock_check(v3d, rv3d)) + return false; + + if (rv3d->persp != RV3D_PERSP) { + if (rv3d->persp == RV3D_CAMOB) { + /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ + char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; + ED_view3d_persp_switch_from_camera(v3d, rv3d, persp); + } + else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->persp = RV3D_PERSP; + } + return true; + } + + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Lock API + * + * Lock the camera to the view-port, allowing view manipulation to transform the camera. + * \{ */ + +/** + * \return true when the view-port is locked to its camera. + */ +bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return ((v3d->camera) && + (!ID_IS_LINKED(v3d->camera)) && + (v3d->flag2 & V3D_LOCK_CAMERA) && + (rv3d->persp == RV3D_CAMOB)); +} + +/** + * Apply the camera object transformation to the view-port. + * (needed so we can use regular view-port manipulation operators, that sync back to the camera). + */ +void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + if (calc_dist) { + /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + } + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } +} + +void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) +{ + ED_view3d_camera_lock_init_ex(v3d, rv3d, true); +} + +/** + * Apply the view-port transformation back to the camera object. + * + * \return true if the camera is moved. + */ +bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + ObjectTfmProtectedChannels obtfm; + Object *root_parent; + + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + Object *ob_update; + float tmat[4][4]; + float imat[4][4]; + float view_mat[4][4]; + float diff_mat[4][4]; + float parent_mat[4][4]; + + while (root_parent->parent) { + root_parent = root_parent->parent; + } + + ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); + + normalize_m4_m4(tmat, v3d->camera->obmat); + + invert_m4_m4(imat, tmat); + mul_m4_m4m4(diff_mat, view_mat, imat); + + mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); + + BKE_object_tfm_protected_backup(root_parent, &obtfm); + BKE_object_apply_mat4(root_parent, parent_mat, true, false); + BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); + + ob_update = v3d->camera; + while (ob_update) { + DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); + ob_update = ob_update->parent; + } + } + else { + /* always maintain the same scale */ + const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); + BKE_object_tfm_protected_backup(v3d->camera, &obtfm); + ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); + + DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); + } + + return true; + } + else { + return false; + } +} + +bool ED_view3d_camera_autokey( + Scene *scene, ID *id_key, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + if (autokeyframe_cfra_can_key(scene, id_key)) { + const float cfra = (float)CFRA; + ListBase dsources = {NULL, NULL}; + + /* add data-source override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); + + /* insert keyframes + * 1) on the first frame + * 2) on each subsequent frame + * TODO: need to check in future that frame changed before doing this + */ + if (do_rotate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + if (do_translate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + + /* free temp data */ + BLI_freelistN(&dsources); + + return true; + } + else { + return false; + } +} + +/** + * Call after modifying a locked view. + * + * \note Not every view edit currently auto-keys (numpad for eg), + * this is complicated because of smoothview. + */ +bool ED_view3d_camera_lock_autokey( + View3D *v3d, RegionView3D *rv3d, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + /* similar to ED_view3d_cameracontrol_update */ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + Scene *scene = CTX_data_scene(C); + ID *id_key; + Object *root_parent; + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + while (root_parent->parent) { + root_parent = root_parent->parent; + } + id_key = &root_parent->id; + } + else { + id_key = &v3d->camera->id; + } + + return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); + } + else { + return false; + } +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ +/** \name Box View Support + * + * Use with quad-split so each view is clipped by the bounds of each view axis. + * \{ */ + +static void view3d_boxview_clip(ScrArea *sa) +{ + ARegion *ar; + BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); + float clip[6][4]; + float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; + int val; + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { + if (ar->winx > ar->winy) x1 = rv3d->dist; + else x1 = ar->winx * rv3d->dist / ar->winy; + + if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; + else y1 = rv3d->dist; + copy_v2_v2(ofs, rv3d->ofs); + } + else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { + ofs[2] = rv3d->ofs[2]; + + if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; + else z1 = rv3d->dist; + } + } + } + } + + for (val = 0; val < 8; val++) { + if (ELEM(val, 0, 3, 4, 7)) + bb->vec[val][0] = -x1 - ofs[0]; + else + bb->vec[val][0] = x1 - ofs[0]; + + if (ELEM(val, 0, 1, 4, 5)) + bb->vec[val][1] = -y1 - ofs[1]; + else + bb->vec[val][1] = y1 - ofs[1]; + + if (val > 3) + bb->vec[val][2] = -z1 - ofs[2]; + else + bb->vec[val][2] = z1 - ofs[2]; + } + + /* normals for plane equations */ + normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); + normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); + normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); + normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); + normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); + normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); + + /* then plane equations */ + for (val = 0; val < 6; val++) { + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); + } + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + rv3d->rflag |= RV3D_CLIPPING; + memcpy(rv3d->clip, clip, sizeof(clip)); + if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); + rv3d->clipbb = MEM_dupallocN(bb); + } + } + } + MEM_freeN(bb); +} + +/** + * Find which axis values are shared between both views and copy to \a rv3d_dst + * taking axis flipping into account. + */ +static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) +{ + /* absolute axis values above this are considered to be set (will be ~1.0f) */ + const float axis_eps = 0.5f; + float viewinv[4]; + + /* use the view rotation to identify which axis to sync on */ + float view_axis_all[4][3] = { + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}}; + + float *view_src_x = &view_axis_all[0][0]; + float *view_src_y = &view_axis_all[1][0]; + + float *view_dst_x = &view_axis_all[2][0]; + float *view_dst_y = &view_axis_all[3][0]; + int i; + + + /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_src_x); + mul_qt_v3(viewinv, view_src_y); + + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_dst_x); + mul_qt_v3(viewinv, view_dst_y); + + /* check source and dest have a matching axis */ + for (i = 0; i < 3; i++) { + if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && + ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) + { + rv3d_dst->ofs[i] = rv3d_src->ofs[i]; + } + } +} + +/* sync center/zoom view of region to others, for view transforms */ +void view3d_boxview_sync(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + short clip = 0; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock & RV3D_LOCKED) { + rv3dtest->dist = rv3d->dist; + view3d_boxview_sync_axis(rv3dtest, rv3d); + clip |= rv3dtest->viewlock & RV3D_BOXCLIP; + + ED_region_tag_redraw(artest); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* for home, center etc */ +void view3d_boxview_copy(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + bool clip = false; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock) { + rv3dtest->dist = rv3d->dist; + copy_v3_v3(rv3dtest->ofs, rv3d->ofs); + ED_region_tag_redraw(artest); + + clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* 'clip' is used to know if our clip setting has changed */ +void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) +{ + ARegion *ar_sync = NULL; + RegionView3D *rv3d = ar->regiondata; + short viewlock; + /* this function copies flags from the first of the 3 other quadview + * regions to the 2 other, so it assumes this is the region whose + * properties are always being edited, weak */ + viewlock = rv3d->viewlock; + + if ((viewlock & RV3D_LOCKED) == 0) { + do_clip = (viewlock & RV3D_BOXCLIP) != 0; + viewlock = 0; + } + else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { + do_clip = true; + viewlock &= ~RV3D_BOXCLIP; + } + + for (; ar; ar = ar->prev) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + rv3d->viewlock = viewlock; + + if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { + rv3d->rflag &= ~RV3D_BOXCLIP; + } + + /* use ar_sync so we sync with one of the aligned views below + * else the view jumps on changing view settings like 'clip' + * since it copies from the perspective view */ + ar_sync = ar; + } + } + + if (rv3d->viewlock & RV3D_BOXVIEW) { + view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); + } + + /* ensure locked regions have an axis, locked user views don't make much sense */ + if (viewlock & RV3D_LOCKED) { + int index_qsplit = 0; + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + if (rv3d->viewlock) { + if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); + rv3d->persp = RV3D_ORTHO; + ED_view3d_lock(rv3d); + } + } + index_qsplit++; + } + } + } + + ED_area_tag_redraw(sa); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Auto-Depth Utilities + * \{ */ + +static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) +{ + ViewDepths depth_temp = {0}; + rcti rect; + float depth_close; + + if (margin == 0) { + /* Get Z Depths, needed for perspective, nice for ortho */ + rect.xmin = mval[0]; + rect.ymin = mval[1]; + rect.xmax = mval[0] + 1; + rect.ymax = mval[1] + 1; + } + else { + BLI_rcti_init_pt_radius(&rect, mval, margin); + } + + view3d_update_depths_rect(ar, &depth_temp, &rect); + depth_close = view3d_depth_near(&depth_temp); + MEM_SAFE_FREE(depth_temp.depths); + return depth_close; +} + +/** + * Get the world-space 3d location from a screen-space 2d point. + * + * \param mval: Input screen-space pixel location. + * \param mouse_worldloc: Output world-space location. + * \param fallback_depth_pt: Use this points depth when no depth can be found. + */ +bool ED_view3d_autodist( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, + const int mval[2], float mouse_worldloc[3], + const bool alphaoverride, const float fallback_depth_pt[3]) +{ + float depth_close; + int margin_arr[] = {0, 2, 4}; + int i; + bool depth_ok = false; + + /* Get Z Depths, needed for perspective, nice for ortho */ + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); + + /* Attempt with low margin's first */ + i = 0; + do { + depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); + depth_ok = (depth_close != FLT_MAX); + } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); + + if (depth_ok) { + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + + if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { + return true; + } + } + + if (fallback_depth_pt) { + ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); + return true; + } + else { + return false; + } +} + +void ED_view3d_autodist_init( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, + ARegion *ar, View3D *v3d, int mode) +{ + /* Get Z Depths, needed for perspective, nice for ortho */ + switch (mode) { + case 0: + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); + break; + case 1: + { + Scene *scene = DEG_get_evaluated_scene(graph); + ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); + break; + } + } +} + +/* no 4x4 sampling, run #ED_view3d_autodist_init first */ +bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], + int margin, float *force_depth) +{ + float depth; + + /* Get Z Depths, needed for perspective, nice for ortho */ + if (force_depth) + depth = *force_depth; + else + depth = view_autodist_depth_margin(ar, mval, margin); + + if (depth == FLT_MAX) + return false; + + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); +} + +bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) +{ + *depth = view_autodist_depth_margin(ar, mval, margin); + + return (*depth != FLT_MAX); +} + +static bool depth_segment_cb(int x, int y, void *userData) +{ + struct { ARegion *ar; int margin; float depth; } *data = userData; + int mval[2]; + float depth; + + mval[0] = x; + mval[1] = y; + + depth = view_autodist_depth_margin(data->ar, mval, data->margin); + + if (depth != FLT_MAX) { + data->depth = depth; + return 0; + } + else { + return 1; + } +} + +bool ED_view3d_autodist_depth_seg( + ARegion *ar, const int mval_sta[2], const int mval_end[2], + int margin, float *depth) +{ + struct { ARegion *ar; int margin; float depth; } data = {NULL}; + int p1[2]; + int p2[2]; + + data.ar = ar; + data.margin = margin; + data.depth = FLT_MAX; + + copy_v2_v2_int(p1, mval_sta); + copy_v2_v2_int(p2, mval_end); + + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); + + *depth = data.depth; + + return (*depth != FLT_MAX); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Radius/Distance Utilities + * + * Use to calculate a distance to a point based on it's radius. + * \{ */ + +float ED_view3d_radius_to_dist_persp(const float angle, const float radius) +{ + return radius * (1.0f / tanf(angle / 2.0f)); +} + +float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) +{ + return radius / (DEFAULT_SENSOR_WIDTH / lens); +} + +/** + * Return a new RegionView3D.dist value to fit the \a radius. + * + * \note Depth isn't taken into account, this will fit a flat plane exactly, + * but points towards the view (with a perspective projection), + * may be within the radius but outside the view. eg: + * + * <pre> + * + + * pt --> + /^ radius + * / | + * / | + * view + + + * \ | + * \ | + * \| + * + + * </pre> + * + * \param ar Can be NULL if \a use_aspect is false. + * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) + * \param use_aspect Increase the distance to account for non 1:1 view aspect. + * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). + */ +float ED_view3d_radius_to_dist( + const View3D *v3d, const ARegion *ar, + const char persp, const bool use_aspect, + const float radius) +{ + float dist; + + BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); + BLI_assert((persp != RV3D_CAMOB) || v3d->camera); + + if (persp == RV3D_ORTHO) { + dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); + } + else { + float lens, sensor_size, zoom; + float angle; + + if (persp == RV3D_CAMOB) { + CameraParams params; + BKE_camera_params_init(¶ms); + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, v3d->camera); + + lens = params.lens; + sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); + + /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ + zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; + } + else { + lens = v3d->lens; + sensor_size = DEFAULT_SENSOR_WIDTH; + zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; + } + + angle = focallength_to_fov(lens, sensor_size); + + /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ + angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; + + dist = ED_view3d_radius_to_dist_persp(angle, radius); + } + + if (use_aspect) { + const RegionView3D *rv3d = ar->regiondata; + + float winx, winy; + + if (persp == RV3D_CAMOB) { + /* camera frame x/y in pixels */ + winx = ar->winx / rv3d->viewcamtexcofac[0]; + winy = ar->winy / rv3d->viewcamtexcofac[1]; + } + else { + winx = ar->winx; + winy = ar->winy; + } + + if (winx && winy) { + float aspect = winx / winy; + if (aspect < 1.0f) { + aspect = 1.0f / aspect; + } + dist *= aspect; + } + } + + return dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Distance Utilities + * \{ */ + +/* problem - ofs[3] can be on same location as camera itself. + * Blender needs proper dist value for zoom. + * use fallback_dist to override small values + */ +float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) +{ + float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float dist; + + mul_m4_v4(mat, pos); + add_v3_v3(pos, ofs); + mul_m4_v4(mat, dir); + normalize_v3(dir); + + dist = dot_v3v3(pos, dir); + + if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { + dist = fallback_dist; + } + + return dist; +} + +/** + * Set the dist without moving the view (compensate with #RegionView3D.ofs) + * + * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. + */ +void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) +{ + float viewinv[4]; + float tvec[3]; + + BLI_assert(dist >= 0.0f); + + copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); + /* rv3d->viewinv isn't always valid */ +#if 0 + mul_mat3_m4_v3(rv3d->viewinv, tvec); +#else + invert_qt_qt_normalized(viewinv, rv3d->viewquat); + mul_qt_v3(viewinv, tvec); +#endif + sub_v3_v3(rv3d->ofs, tvec); + + rv3d->dist = dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis Utilities + * \{ */ +static float view3d_quat_axis[6][4] = { + {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ + {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ + {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ + {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ + {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ + {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ +}; + + +bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) +{ + if (RV3D_VIEW_IS_AXIS(view)) { + copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); + return true; + } + else { + return false; + } +} + +char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) +{ + /* quat values are all unit length */ + + char view; + + for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { + if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) { + return view; + } + } + + return RV3D_VIEW_USER; +} + +char ED_view3d_lock_view_from_index(int index) +{ + switch (index) { + case 0: return RV3D_VIEW_FRONT; + case 1: return RV3D_VIEW_TOP; + case 2: return RV3D_VIEW_RIGHT; + default: return RV3D_VIEW_USER; + } + +} + +char ED_view3d_axis_view_opposite(char view) +{ + switch (view) { + case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; + case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; + case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; + case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; + case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; + case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; + } + + return RV3D_VIEW_USER; +} + + +bool ED_view3d_lock(RegionView3D *rv3d) +{ + return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Transform Utilities + * \{ */ + +/** + * Set the view transformation from a 4x4 matrix. + * + * \param mat The view 4x4 transformation matrix to assign. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) +{ + float nmat[3][3]; + + /* dist depends on offset */ + BLI_assert(dist == NULL || ofs != NULL); + + copy_m3_m4(nmat, mat); + normalize_m3(nmat); + + /* Offset */ + if (ofs) + negate_v3_v3(ofs, mat[3]); + + /* Quat */ + if (quat) { + mat3_normalized_to_quat(quat, nmat); + invert_qt_normalized(quat); + } + + if (ofs && dist) { + madd_v3_v3fl(ofs, nmat[2], *dist); + } +} + +/** + * Calculate the view transformation matrix from RegionView3D input. + * The resulting matrix is equivalent to RegionView3D.viewinv + * \param mat The view 4x4 transformation matrix to calculate. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) +{ + float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; + float dvec[3] = {0.0f, 0.0f, dist}; + + quat_to_mat4(mat, iviewquat); + mul_mat3_m4_v3(mat, dvec); + sub_v3_v3v3(mat[3], dvec, ofs); +} + +/** + * Set the RegionView3D members from an objects transformation and optionally lens. + * \param ob The object to set the view to. + * \param ofs The view offset to be set, normally from RegionView3D.ofs. + * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. + * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. + */ +void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) +{ + ED_view3d_from_m4(ob->obmat, ofs, quat, dist); + + if (lens) { + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, ob); + *lens = params.lens; + } +} + +/** + * Set the object transformation from RegionView3D members. + * \param ob The object which has the transformation assigned. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) +{ + float mat[4][4]; + ED_view3d_to_m4(mat, ofs, quat, dist); + BKE_object_apply_mat4(ob, mat, true, true); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Depth Buffer Utilities + * \{ */ + +float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) +{ + ViewDepths *vd = vc->rv3d->depths; + + int x = mval[0]; + int y = mval[1]; + + if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { + return vd->depths[y * vd->w + x]; + } + else { + BLI_assert(1.0 <= vd->depth_range[1]); + return 1.0f; + } +} + +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const int mval[2], + float r_normal[3]) +{ + /* Note: we could support passing in a radius. + * For now just read 9 pixels. */ + + /* pixels surrounding */ + bool depths_valid[9] = {false}; + float coords[9][3] = {{0}}; + + ARegion *ar = vc->ar; + const ViewDepths *depths = vc->rv3d->depths; + + for (int x = 0, i = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; + + const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { + depths_valid[i] = true; + } + } + i++; + } + } + + const int edges[2][6][2] = { + /* x edges */ + {{0, 1}, {1, 2}, + {3, 4}, {4, 5}, + {6, 7}, {7, 8}}, + /* y edges */ + {{0, 3}, {3, 6}, + {1, 4}, {4, 7}, + {2, 5}, {5, 8}}, + }; + + float cross[2][3] = {{0.0f}}; + + for (int i = 0; i < 6; i++) { + for (int axis = 0; axis < 2; axis++) { + if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { + float delta[3]; + sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); + add_v3_v3(cross[axis], delta); + } + } + } + + cross_v3_v3v3(r_normal, cross[0], cross[1]); + + if (normalize_v3(r_normal) != 0.0f) { + return true; + } + else { + return false; + } +} + +bool ED_view3d_depth_unproject( + const ARegion *ar, + const int mval[2], const double depth, + float r_location_world[3]) +{ + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); +} + +void ED_view3d_depth_tag_update(RegionView3D *rv3d) +{ + if (rv3d->depths) + rv3d->depths->damaged = true; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 72443a5a227..0597f2806b3 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -28,7 +28,6 @@ * \ingroup spview3d */ - #include "DNA_camera_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -39,7 +38,6 @@ #include "BLI_rect.h" #include "BLI_utildefines.h" -#include "BKE_anim.h" #include "BKE_action.h" #include "BKE_camera.h" #include "BKE_context.h" @@ -48,12 +46,9 @@ #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_screen.h" #include "DEG_depsgraph.h" -#include "BIF_glutil.h" - #include "UI_resources.h" #include "GPU_glew.h" @@ -64,7 +59,6 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_armature.h" #include "DRW_engine.h" @@ -79,53 +73,14 @@ # include "BL_System.h" #endif - #include "view3d_intern.h" /* own include */ -/* use this call when executing an operator, - * event system doesn't set for each event the - * opengl drawing context */ -void view3d_operator_needs_opengl(const bContext *C) -{ - wmWindow *win = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); - - view3d_region_operator_needs_opengl(win, ar); -} - -void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) -{ - /* for debugging purpose, context should always be OK */ - if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { - printf("view3d_region_operator_needs_opengl error, wrong region\n"); - } - else { - RegionView3D *rv3d = ar->regiondata; - - wmSubWindowSet(win, ar->swinid); - gpuLoadProjectionMatrix(rv3d->winmat); - gpuLoadMatrix(rv3d->viewmat); - } -} - -float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) -{ - if (v3d && v3d->localvd) return v3d->cursor; - else return scene->cursor; -} - -Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) -{ - /* establish the camera object, so we can default to view mapping if anything is wrong with it */ - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { - return v3d->camera->data; - } - else { - return NULL; - } -} +/* -------------------------------------------------------------------- */ +/** \name Smooth View Operator & Utilities + * + * Use for view transitions to have smooth (animated) transitions. + * \{ */ -/* ****************** smooth view operator ****************** */ /* This operator is one of the 'timer refresh' ones like animation playback */ struct SmoothView3DState { @@ -402,6 +357,8 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) { @@ -463,22 +420,25 @@ void ED_view3d_smooth_view_force_finish( void VIEW3D_OT_smoothview(wmOperatorType *ot) { - /* identifiers */ ot->name = "Smooth View"; ot->description = ""; ot->idname = "VIEW3D_OT_smoothview"; - + /* api callbacks */ ot->invoke = view3d_smoothview_invoke; - + /* flags */ ot->flag = OPTYPE_INTERNAL; ot->poll = ED_operator_view3d_active; } -/* ****************** change view operators ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera to View Operator + * \{ */ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -542,6 +502,12 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Fit Frame to Selected Operator + * \{ */ + /* unlike VIEW3D_OT_view_selected this is for framing a render and not * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) @@ -601,6 +567,12 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object as Camera Operator + * \{ */ + static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx) { Main *bmain = CTX_data_main(C); @@ -651,7 +623,7 @@ static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob } static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) -{ +{ View3D *v3d; ARegion *ar; RegionView3D *rv3d; @@ -704,7 +676,6 @@ int ED_operator_rv3d_user_region_poll(bContext *C) void VIEW3D_OT_object_as_camera(wmOperatorType *ot) { - /* identifiers */ ot->name = "Set Active Object as Camera"; ot->description = "Set the active object as the active camera for this view or scene"; @@ -718,280 +689,12 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************************** */ - -void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) -{ - int val; - - for (val = 0; val < 4; val++) { - normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); - if (UNLIKELY(is_flip)) { - negate_v3(clip[val]); - } - - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); - } -} - -void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) -{ - /* init in case unproject fails */ - memset(bb->vec, 0, sizeof(bb->vec)); - - /* four clipping planes and bounding volume */ - /* first do the bounding volume */ - for (int val = 0; val < 4; val++) { - float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; - float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; - - ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); - ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); - } - - /* optionally transform to object space */ - if (ob) { - float imat[4][4]; - invert_m4_m4(imat, ob->obmat); - - for (int val = 0; val < 8; val++) { - mul_m4_v3(imat, bb->vec[val]); - } - } - - /* verify if we have negative scale. doing the transform before cross - * product flips the sign of the vector compared to doing cross product - * before transform then, so we correct for that. */ - int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; - - ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); -} - -static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) -{ - int a, flag = -1, fl; - - for (a = 0; a < 8; a++) { - float vec[4], min, max; - copy_v3_v3(vec, bb->vec[a]); - vec[3] = 1.0; - mul_m4_v4(persmatob, vec); - max = vec[3]; - min = -vec[3]; - - fl = 0; - if (vec[0] < min) fl += 1; - if (vec[0] > max) fl += 2; - if (vec[1] < min) fl += 4; - if (vec[1] > max) fl += 8; - if (vec[2] < min) fl += 16; - if (vec[2] > max) fl += 32; - - flag &= fl; - if (flag == 0) return true; - } - - return false; -} - -bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) -{ - /* return 1: draw */ - - float persmatob[4][4]; - - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); - - return view3d_boundbox_clip_m4(bb, persmatob); -} - -bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) -{ - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - return view3d_boundbox_clip_m4(bb, rv3d->persmatob); -} +/** \} */ /* -------------------------------------------------------------------- */ - -/** \name Depth Utilities +/** \name Window and View Matrix Calculation * \{ */ -float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) -{ - ViewDepths *vd = vc->rv3d->depths; - - int x = mval[0]; - int y = mval[1]; - - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { - return vd->depths[y * vd->w + x]; - } - else { - BLI_assert(1.0 <= vd->depth_range[1]); - return 1.0f; - } -} - -bool ED_view3d_depth_read_cached_normal( - const ViewContext *vc, const int mval[2], - float r_normal[3]) -{ - /* Note: we could support passing in a radius. - * For now just read 9 pixels. */ - - /* pixels surrounding */ - bool depths_valid[9] = {false}; - float coords[9][3] = {{0}}; - - ARegion *ar = vc->ar; - const ViewDepths *depths = vc->rv3d->depths; - - for (int x = 0, i = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - - const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { - depths_valid[i] = true; - } - } - i++; - } - } - - const int edges[2][6][2] = { - /* x edges */ - {{0, 1}, {1, 2}, - {3, 4}, {4, 5}, - {6, 7}, {7, 8}}, - /* y edges */ - {{0, 3}, {3, 6}, - {1, 4}, {4, 7}, - {2, 5}, {5, 8}}, - }; - - float cross[2][3] = {{0.0f}}; - - for (int i = 0; i < 6; i++) { - for (int axis = 0; axis < 2; axis++) { - if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { - float delta[3]; - sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); - add_v3_v3(cross[axis], delta); - } - } - } - - cross_v3_v3v3(r_normal, cross[0], cross[1]); - - if (normalize_v3(r_normal) != 0.0f) { - return true; - } - else { - return false; - } -} - -bool ED_view3d_depth_unproject( - const ARegion *ar, - const int mval[2], const double depth, - float r_location_world[3]) -{ - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); -} - -/** \} */ - -void ED_view3d_depth_tag_update(RegionView3D *rv3d) -{ - if (rv3d->depths) - rv3d->depths->damaged = true; -} - -void ED_view3d_dist_range_get( - const View3D *v3d, - float r_dist_range[2]) -{ - r_dist_range[0] = v3d->grid * 0.001f; - r_dist_range[1] = v3d->far * 10.0f; -} - -/* copies logic of get_view3d_viewplane(), keep in sync */ -bool ED_view3d_clip_range_get( - const Depsgraph *depsgraph, - const View3D *v3d, const RegionView3D *rv3d, - float *r_clipsta, float *r_clipend, - const bool use_ortho_factor) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); - - if (use_ortho_factor && params.is_ortho) { - const float fac = 2.0f / (params.clipend - params.clipsta); - params.clipsta *= fac; - params.clipend *= fac; - } - - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - - return params.is_ortho; -} - -bool ED_view3d_viewplane_get( - const Depsgraph *depsgraph, - const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, - rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); - - if (r_viewplane) *r_viewplane = params.viewplane; - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - if (r_pixsize) *r_pixsize = params.viewdx; - - return params.is_ortho; -} - -/** - * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] - */ -void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) -{ - float viewdist; - - if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { - return; - } - - viewdist = rv3d->dist; - - /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ - if (dist != 0.0f) { - if (rv3d->persp == RV3D_CAMOB) { - if (rv3d->is_persp == false) { - viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); - } - } - } - - bglPolygonOffset(viewdist, dist); -} - /** * \param rect optional for picking (can be NULL). */ @@ -1044,75 +747,21 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat); } -static float view3d_quat_axis[6][4] = { - {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ - {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ - {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ - {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ - {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ - {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ -}; - - -bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) -{ - if (RV3D_VIEW_IS_AXIS(view)) { - copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); - return true; - } - else { - return false; - } -} - -char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) -{ - /* quat values are all unit length */ - - char view; - - for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { - if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) { - return view; - } - } - - return RV3D_VIEW_USER; -} - -char ED_view3d_lock_view_from_index(int index) -{ - switch (index) { - case 0: return RV3D_VIEW_FRONT; - case 1: return RV3D_VIEW_TOP; - case 2: return RV3D_VIEW_RIGHT; - default: return RV3D_VIEW_USER; - } - -} - -char ED_view3d_axis_view_opposite(char view) -{ - switch (view) { - case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; - case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; - case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; - case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; - case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; - case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; - } - - return RV3D_VIEW_USER; -} - - -bool ED_view3d_lock(RegionView3D *rv3d) -{ - return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); -} - -/* don't set windows active in here, is used by renderwin too */ -void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d) +/** + * Sets #RegionView3D.viewmat + * + * \param eval_ctx: Context. + * \param scene: Scene for camera and cursor location. + * \param v3d: View 3D space data. + * \param rv3d: 3D region which stores the final matrices. + * \param rect_scale: Optional 2D scale argument, + * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument. + * + * \note don't set windows active in here, is used by renderwin too. + */ +void view3d_viewmatrix_set( + const EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { @@ -1173,6 +822,17 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f); vec[2] = 0.0f; + + if (rect_scale) { + /* Since 'RegionView3D.winmat' has been calculated and this function doesn't take the 'ARegion' + * we don't know about the region size. + * Use 'rect_scale' when drawing a sub-region to apply 2D offset, + * scaled by the difference between the sub-region and the region size. + */ + vec[0] /= rect_scale[0]; + vec[1] /= rect_scale[1]; + } + mul_mat3_m4_v3(persinv, vec); translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]); } @@ -1180,6 +840,12 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name OpenGL Select Utilities + * \{ */ + /** * Optionally cache data for multiple calls to #view3d_opengl_select * @@ -1331,6 +997,12 @@ finally: return hits; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Layer Utilities + * \{ */ + int ED_view3d_view_layer_set(int lay, const int *values, int *active) { int i, tot = 0; @@ -1369,43 +1041,43 @@ int ED_view3d_view_layer_set(int lay, const int *values, int *active) return lay; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Game Engine Operator + * + * Start the game engine (handles context switching). + * \{ */ + #ifdef WITH_GAMEENGINE static ListBase queue_back; -static void SaveState(bContext *C, wmWindow *win) +static void game_engine_save_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + glPushAttrib(GL_ALL_ATTRIB_BITS); if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(1); - + queue_back = win->queue; - + BLI_listbase_clear(&win->queue); - - //XXX waitcursor(1); } -static void RestoreState(bContext *C, wmWindow *win) +static void game_engine_restore_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(0); - //XXX curarea->win_swap = 0; - //XXX curarea->head_swap = 0; - //XXX allqueue(REDRAWVIEW3D, 1); - //XXX allqueue(REDRAWBUTSALL, 0); - //XXX reset_slowparents(); - //XXX waitcursor(0); - //XXX G.qual = 0; - - if (win) /* check because closing win can set to NULL */ + /* check because closing win can set to NULL */ + if (win) { win->queue = queue_back; - + } + GPU_state_init(); glPopAttrib(); @@ -1476,33 +1148,6 @@ static int game_engine_poll(bContext *C) return 1; } -bool ED_view3d_context_activate(bContext *C) -{ - bScreen *sc = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar; - - /* sa can be NULL when called from python */ - if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { - sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); - } - - if (sa == NULL) { - return false; - } - - ar = BKE_area_find_region_active_win(sa); - if (ar == NULL) { - return false; - } - - /* bad context switch .. */ - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - return true; -} - static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE @@ -1514,12 +1159,12 @@ static int game_engine_exec(bContext *C, wmOperator *op) RegionView3D *rv3d; rcti cam_frame; - (void)op; /* unused */ - + UNUSED_VARS(op); + /* bad context switch .. */ if (!ED_view3d_context_activate(C)) return OPERATOR_CANCELLED; - + /* redraw to hide any menus/popups, we don't go back to * the window manager until after this operator exits */ WM_redraw_windows(C); @@ -1531,7 +1176,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) ar = CTX_wm_region(C); view3d_operator_needs_opengl(C); - + game_set_commmandline_options(&startscene->gm); if ((rv3d->persp == RV3D_CAMOB) && @@ -1556,7 +1201,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) } - SaveState(C, prevwin); + game_engine_save_state(C, prevwin); StartKetsjiShell(C, ar, &cam_frame, 1); @@ -1565,7 +1210,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) prevwin = NULL; CTX_wm_window_set(C, NULL); } - + ED_area_tag_redraw(CTX_wm_area(C)); if (prevwin) { @@ -1576,7 +1221,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) CTX_wm_area_set(C, prevsa); } - RestoreState(C, prevwin); + game_engine_restore_state(C, prevwin); //XXX restore_all_scene_cfra(scene_cfra_store); BKE_scene_set_background(CTX_data_main(C), startscene); @@ -1586,7 +1231,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; #else - (void)C; /* unused */ + UNUSED_VARS(C); BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); return OPERATOR_CANCELLED; #endif @@ -1594,168 +1239,15 @@ static int game_engine_exec(bContext *C, wmOperator *op) void VIEW3D_OT_game_start(wmOperatorType *ot) { - /* identifiers */ ot->name = "Start Game Engine"; ot->description = "Start game engine"; ot->idname = "VIEW3D_OT_game_start"; - + /* api callbacks */ ot->exec = game_engine_exec; - - ot->poll = game_engine_poll; -} - -/* ************************************** */ - -float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) -{ - return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; -} - -float ED_view3d_radius_to_dist_persp(const float angle, const float radius) -{ - return radius * (1.0f / tanf(angle / 2.0f)); -} - -float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) -{ - return radius / (DEFAULT_SENSOR_WIDTH / lens); -} - -/** - * Return a new RegionView3D.dist value to fit the \a radius. - * - * \note Depth isn't taken into account, this will fit a flat plane exactly, - * but points towards the view (with a perspective projection), - * may be within the radius but outside the view. eg: - * - * <pre> - * + - * pt --> + /^ radius - * / | - * / | - * view + + - * \ | - * \ | - * \| - * + - * </pre> - * - * \param ar Can be NULL if \a use_aspect is false. - * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) - * \param use_aspect Increase the distance to account for non 1:1 view aspect. - * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). - */ -float ED_view3d_radius_to_dist( - const View3D *v3d, const ARegion *ar, - const char persp, const bool use_aspect, - const float radius) -{ - float dist; - - BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); - BLI_assert((persp != RV3D_CAMOB) || v3d->camera); - - if (persp == RV3D_ORTHO) { - dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); - } - else { - float lens, sensor_size, zoom; - float angle; - - if (persp == RV3D_CAMOB) { - CameraParams params; - BKE_camera_params_init(¶ms); - params.clipsta = v3d->near; - params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, v3d->camera); - - lens = params.lens; - sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); - /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ - zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; - } - else { - lens = v3d->lens; - sensor_size = DEFAULT_SENSOR_WIDTH; - zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; - } - - angle = focallength_to_fov(lens, sensor_size); - - /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ - angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; - - dist = ED_view3d_radius_to_dist_persp(angle, radius); - } - - if (use_aspect) { - const RegionView3D *rv3d = ar->regiondata; - - float winx, winy; - - if (persp == RV3D_CAMOB) { - /* camera frame x/y in pixels */ - winx = ar->winx / rv3d->viewcamtexcofac[0]; - winy = ar->winy / rv3d->viewcamtexcofac[1]; - } - else { - winx = ar->winx; - winy = ar->winy; - } - - if (winx && winy) { - float aspect = winx / winy; - if (aspect < 1.0f) { - aspect = 1.0f / aspect; - } - dist *= aspect; - } - } - - return dist; -} - -/* view matrix properties utilities */ - -/* unused */ -#if 0 -void ED_view3d_operator_properties_viewmat(wmOperatorType *ot) -{ - PropertyRNA *prop; - - prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN); -} - -void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - if (!RNA_struct_property_is_set(op->ptr, "region_width")) - RNA_int_set(op->ptr, "region_width", ar->winx); - - if (!RNA_struct_property_is_set(op->ptr, "region_height")) - RNA_int_set(op->ptr, "region_height", ar->winy); - - if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix")) - RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat); + ot->poll = game_engine_poll; } -void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4]) -{ - *winx = RNA_int_get(op->ptr, "region_width"); - *winy = RNA_int_get(op->ptr, "region_height"); - - RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat); -} -#endif +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 724f60734f1..e65f9abae27 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -60,6 +60,8 @@ #include "RE_engine.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -510,6 +512,9 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); walk->rv3d = CTX_wm_region_view3d(C); walk->v3d = CTX_wm_view3d(C); @@ -610,7 +615,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, walk->scene, walk->v3d, walk->rv3d, + &eval_ctx, walk->scene, walk->v3d, walk->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* center the mouse */ diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index db6f2c27623..f882f3ecd65 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -622,7 +622,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - unsigned int pos; + unsigned int pos, color; efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */ ts = scene->toolsettings; @@ -671,58 +671,61 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (sima->flag & SI_DRAW_STRETCH) { draw_uvs_stretch(sima, scene, em, efa_act); } - else if (!(sima->flag & SI_NO_DRAWFACES)) { - /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - for (unsigned int i = 0; i < em->tottri; i++) { - efa = em->looptris[i][0]->f; + else { + unsigned int tri_count = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (uvedit_face_visible_test(scene, ima, efa)) { - const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); BM_elem_flag_enable(efa, BM_ELEM_TAG); - - if (efa == efa_act) { - /* only once */ - immUniformThemeColor(TH_EDITMESH_ACTIVE); - } - else { - immUniformColor4ubv(is_select ? col2 : col1); - } - - immBegin(GWN_PRIM_TRIS, (em->looptris[i][0]->f->len - 2) * 3); - draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); - immEnd(); + tri_count += efa->len - 2; } else { BM_elem_flag_disable(efa, BM_ELEM_TAG); } } - immUnbindProgram(); + if (!(sima->flag & SI_NO_DRAWFACES)) { + /* draw transparent faces */ + UI_GetThemeColor4ubv(TH_FACE, col1); + UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); - glDisable(GL_BLEND); - } - else { - /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + immBegin(GWN_PRIM_TRIS, tri_count * 3); + for (unsigned int i = 0; i < em->tottri; i++) { + efa = em->looptris[i][0]->f; + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); + + if (efa == efa_act) { + /* only once */ + unsigned char tmp_col[4]; + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4ubv(color, tmp_col); + } + else { + immAttrib4ubv(color, is_select ? col2 : col1); + } + + draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); + } } - else { - if (efa == efa_act) - efa_act = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); + immEnd(); + + immUnbindProgram(); + + glDisable(GL_BLEND); + } + else { + if (efa_act && !uvedit_face_visible_test(scene, ima, efa_act)) { + efa_act = NULL; } } - } /* 3. draw active face stippled */ @@ -813,7 +816,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); if (interpedges) { immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); @@ -900,7 +903,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 1e99db2c32f..0400fc1025b 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -166,6 +166,7 @@ Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( BLI_assert(polys_flat_len == polys_len * 2); /* Over alloc */ + /* Lines are pairs of (x, y) byte locations packed into an int32_t. */ int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__); int32_t *lines_step = lines; @@ -178,8 +179,6 @@ Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( (rect ? rect->ymin : -1.0f), }; - const bool hide_lines = true; - uint i_poly_prev = 0; uint i_poly = 0; while (i_poly != polys_len) { @@ -210,15 +209,22 @@ Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( } } - uint lines_len = (lines_step - lines); - uint lines_hide_len = 0; - if (hide_lines) { + uint lines_len = lines_step - lines; + + /* Hide Lines (we could make optional) */ + { qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int); + lines_step = lines; + + if (lines[0] != lines[1]) { + *lines_step++ = lines[0]; + } for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) { - if ((lines[i] == lines[i_prev])) { - lines_hide_len++; + if (lines[i] != lines[i_prev]) { + *lines_step++ = lines[i]; } } + lines_len = lines_step - lines; } /* We have vertices and tris, make a batch from this. */ @@ -229,18 +235,13 @@ Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( } Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, (lines_len - lines_hide_len) * 2); + const uint vbo_len_capacity = lines_len * 2; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); Gwn_VertBufRaw pos_step; GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); for (uint i = 0; i < lines_len; i++) { - if (hide_lines) { - if ((i + 1 != lines_len) && (lines[i + 1] == lines[i])) { - i++; - continue; - } - } union { uint8_t as_u8_pair[2][2]; uint32_t as_u32; @@ -253,6 +254,7 @@ Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( } } } + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); MEM_freeN(lines); return GWN_batch_create_ex( GWN_PRIM_LINES, vbo, diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 07c3b1e782b..780f4f59fb9 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -4135,9 +4135,14 @@ void node_bevel(float radius, vec3 N, out vec3 result) result = N; } +void node_displacement(float height, float dist, vec3 N, out vec3 result) +{ + result = height * dist * N; +} + /* output */ -void node_output_material(Closure surface, Closure volume, float displacement, out Closure result) +void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result) { #ifdef VOLUMETRICS result = volume; diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index b10ae4f6fe9..c4c4f4405a5 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -99,8 +99,8 @@ struct anim { int curtype; int curposition; /* index 0 = 1e, 1 = 2e, enz. */ int duration; - short frs_sec; - float frs_sec_base; + int frs_sec; + double frs_sec_base; int x, y; /* for number */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 25b0c0d7b1a..5472cae3ef2 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -55,6 +55,7 @@ #include <stdlib.h> #include <stdio.h> #include <math.h> +#include <limits.h> #ifndef _WIN32 #include <dirent.h> #else @@ -1365,16 +1366,32 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base) { + double frs_sec_base_double; if (anim->frs_sec) { - *frs_sec = anim->frs_sec; - *frs_sec_base = anim->frs_sec_base; + if (anim->frs_sec > SHRT_MAX) { + /* We cannot store original rational in our short/float format, + * we need to approximate it as best as we can... */ + *frs_sec = SHRT_MAX; + frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec; + } + else { + *frs_sec = anim->frs_sec; + frs_sec_base_double = anim->frs_sec_base; + } #ifdef WITH_FFMPEG if (no_av_base) { - *frs_sec_base /= AV_TIME_BASE; + *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE); + } + else { + *frs_sec_base = (float)frs_sec_base_double; } #else UNUSED_VARS(no_av_base); + *frs_sec_base = (float)frs_sec_base_double; #endif + BLI_assert(*frs_sec > 0); + BLI_assert(*frs_sec_base > 0.0f); + return true; } return false; diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index b6e8b43b009..d29518fc5bc 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -193,7 +193,7 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf dpx->srcFormat = format_DPX; dpx->numElements = swap_ushort(header.imageHeader.elements_per_image, dpx->isMSB); - size_t max_elements = sizeof(header.imageHeader.element)/sizeof(header.imageHeader.element[0]); + size_t max_elements = sizeof(header.imageHeader.element) / sizeof(header.imageHeader.element[0]); if (dpx->numElements == 0 || dpx->numElements >= max_elements) { if (verbose) printf("DPX: Wrong number of elements: %d\n", dpx->numElements); logImageClose(dpx); diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index ff81e04c5a1..806c1ca76fc 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -65,7 +65,7 @@ typedef struct LayerCollection { /* TODO(sergey): Get rid of this once we've got CoW in DEG, */ short flag_evaluated; short pad[2]; - ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects and collection->filter_objects */ + ListBase object_bases; /* (ObjectBase *)LinkData->data - synced with collection->objects */ ListBase overrides; ListBase layer_collections; /* synced with collection->collections */ struct IDProperty *properties; /* overrides */ @@ -102,12 +102,10 @@ typedef struct ViewLayer { typedef struct SceneCollection { struct SceneCollection *next, *prev; char name[64]; /* MAX_NAME */ - char filter[64]; /* MAX_NAME */ int active_object_index; /* for UI */ char type; char pad[3]; ListBase objects; /* (Object *)LinkData->data */ - ListBase filter_objects; /* (Object *)LinkData->data */ ListBase scene_collections; /* nested collections */ } SceneCollection; diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 75705f7dd37..649df714457 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -55,7 +55,9 @@ typedef struct LightProbe { float clipsta, clipend; float vis_bias, vis_bleedbias; /* VSM visibility biases */ - float vis_blur, pad2; + float vis_blur; + + float intensity; /* Intensity multiplier */ int grid_resolution_x; /* Irradiance grid resolution */ int grid_resolution_y; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index dd716014f66..375641d1115 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -45,6 +45,8 @@ struct PanelType; struct Scene; struct uiLayout; struct wmTimer; +struct wmTooltipState; + typedef struct bScreen { ID id; @@ -77,6 +79,8 @@ typedef struct bScreen { struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ + struct wmTooltipState *tool_tip; /* runtime */ + PreviewImage *preview; } bScreen; diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index ef3d7c0ae88..47f5d037d09 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -97,16 +97,6 @@ static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value) BKE_collection_rename(scene, sc, value); } -static void rna_SceneCollection_filter_set(PointerRNA *ptr, const char *value) -{ - Scene *scene = (Scene *)ptr->id.data; - SceneCollection *sc = (SceneCollection *)ptr->data; - BLI_strncpy_utf8(sc->filter, value, sizeof(sc->filter)); - - TODO_LAYER_SYNC_FILTER; - (void)scene; -} - static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *iter) { ListBaseIterator *internal = &iter->internal.listbase; @@ -1055,11 +1045,6 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Type of collection"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set"); - RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)"); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL); - prop = RNA_def_property(srna, "collections", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "scene_collections", NULL); RNA_def_property_struct_type(prop, "SceneCollection"); @@ -1073,12 +1058,6 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Objects", "All the objects directly added to this collection (not including sub-collection objects)"); rna_def_collection_objects(brna, prop); - prop = RNA_def_property(srna, "filters_objects", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "filter_objects", NULL); - RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL); - RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter"); - /* Functions */ func = RNA_def_function(srna, "move_above", "rna_SceneCollection_move_above"); RNA_def_function_ui_description(func, "Move collection after another"); @@ -2034,8 +2013,6 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollection_flag_update"); - - /* TODO_LAYER_OVERRIDE */ } static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c index 61dc835022b..6586b456960 100644 --- a/source/blender/makesrna/intern/rna_lightprobe.c +++ b/source/blender/makesrna/intern/rna_lightprobe.c @@ -179,6 +179,13 @@ static void rna_def_lightprobe(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur"); RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "intensity"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3); + RNA_def_property_ui_text(prop, "Intensity", "Modify the intensity of the lighting captured by this probe"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc"); + /* Data preview */ prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 62360ea34a3..79a9d072ad2 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1667,7 +1667,7 @@ static int rna_MeshPolygonStringPropertyLayer_data_length(PointerRNA *ptr) return me->totpoly; } -/* XXX, we dont have propper byte string support yet, so for now use the (bytes + 1) +/* XXX, we dont have proper byte string support yet, so for now use the (bytes + 1) * bmesh API exposes correct python/bytestring access */ void rna_MeshStringProperty_s_get(PointerRNA *ptr, char *value) { diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 4f7dc35c2c1..e23fce47aad 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5680,14 +5680,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "frs_sec"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 1, 120); + RNA_def_property_range(prop, 1, SHRT_MAX); + RNA_def_property_ui_range(prop, 1, 120, 1, -1); RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); prop = RNA_def_property(srna, "fps_base", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "frs_sec_base"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.1f, 120.0f); + RNA_def_property_range(prop, 1e-5f, 1e6f); + RNA_def_property_ui_range(prop, 0.1f, 120.0f, 2, -1); RNA_def_property_ui_text(prop, "FPS Base", "Framerate base"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 188b63d7d24..82077051c18 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -504,8 +504,11 @@ void RNA_api_wm(StructRNA *srna) /* invoke enum */ func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke"); - RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of " - "operator's type 'prop' EnumProperty, and execute it on confirmation)"); + RNA_def_function_ui_description( + func, + "Operator search popup invoke which " + "searches values of the operator's :class:`bpy.types.Operator.bl_property` " + "(which must be an EnumProperty), executing it on confirmation"); rna_generic_op_invoke(func, 0); /* invoke functions, for use with python */ diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 6fc1907ba0a..3cb35286114 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -52,11 +52,6 @@ static void copyData(ModifierData *md, ModifierData *target) modifier_copyData_generic(md, target); } -static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(useRenderParams)) -{ - return false; -} - static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md) { WireframeModifierData *wmd = (WireframeModifierData *)md; @@ -132,8 +127,8 @@ ModifierTypeInfo modifierType_Wireframe = { /* initData */ initData, /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, - /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, + /* isDisabled */ NULL, + /* updateDepgraph */ NULL, /* dependsOnTime */ NULL, /* dependsOnNormals */ dependsOnNormals, /* foreachObjectLink */ NULL, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index a6e04510b03..c83daa185a8 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -194,6 +194,7 @@ set(SRC shader/nodes/node_shader_subsurface_scattering.c shader/nodes/node_shader_tangent.c shader/nodes/node_shader_bevel.c + shader/nodes/node_shader_displacement.c shader/nodes/node_shader_tex_brick.c shader/nodes/node_shader_tex_checker.c shader/nodes/node_shader_tex_coord.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 62a92e8d084..cbdfd8d3dbf 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -79,6 +79,7 @@ void register_node_type_sh_tex_pointdensity(void); void register_node_type_sh_attribute(void); void register_node_type_sh_bevel(void); +void register_node_type_sh_displacement(void); void register_node_type_sh_geometry(void); void register_node_type_sh_light_path(void); void register_node_type_sh_light_falloff(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index a18ee154af8..e2c1fae1bde 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -128,6 +128,7 @@ DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UV DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" ) DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" ) +DefNode( ShaderNode, SH_NODE_DISPLACEMENT, 0, "DISPLACEMENT", Displacement, "Displacement", "" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c index 382492707ce..e1d17003ba4 100644 --- a/source/blender/nodes/intern/node_socket.c +++ b/source/blender/nodes/intern/node_socket.c @@ -112,22 +112,21 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in break; } if (sock) { - sock->type = stemp->type; + if (sock->type != stemp->type) { + nodeModifySocketType(ntree, node, sock, stemp->type, stemp->subtype); + } + sock->limit = (stemp->limit == 0 ? 0xFFF : stemp->limit); sock->flag |= stemp->flag; - - BLI_remlink(socklist, sock); - - return sock; } else { /* no socket for this template found, make a new one */ sock = node_add_socket_from_template(ntree, node, stemp, in_out); - /* remove the new socket from the node socket list first, - * will be added back after verification. - */ - BLI_remlink(socklist, sock); } + + /* remove the new socket from the node socket list first, + * will be added back after verification. */ + BLI_remlink(socklist, sock); return sock; } diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index bd22a2be647..2f65188841e 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -460,6 +460,21 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, * cycles in the Cycles material :) */ nodeRemLink(ntree, displacement_link); + + /* Convert displacement vector to bump height. */ + bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH); + bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY); + dot_node->custom1 = 3; /* dot product */ + + nodeAddLink(ntree, + displacement_node, displacement_socket, + dot_node, dot_node->inputs.first); + nodeAddLink(ntree, + geo_node, ntree_shader_node_find_output(geo_node, "Normal"), + dot_node, dot_node->inputs.last); + displacement_node = dot_node; + displacement_socket = ntree_shader_node_find_output(dot_node, "Value"); + /* We can't connect displacement to normal directly, use bump node for that * and hope that it gives good enough approximation. */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 15a8c47db7a..84481a50993 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -34,7 +34,7 @@ /* **************** BUMP ******************** */ static bNodeSocketTemplate sh_node_bump_in[] = { { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - { SOCK_FLOAT, 1, N_("Distance"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, { SOCK_FLOAT, 1, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE}, { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c new file mode 100644 index 00000000000..d5c191b3966 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_displacement_in[] = { + { SOCK_FLOAT, 0, N_("Height"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_FLOAT, 0, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_displacement_out[] = { + { SOCK_VECTOR, 0, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static int gpu_shader_displacement(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (!in[2].link) { + GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[2].link); + } + + return GPU_stack_link(mat, node, "node_displacement", in, out); +} + +/* node type definition */ +void register_node_type_sh_displacement(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_displacement); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index 0418b039337..e901e7c4590 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -34,7 +34,7 @@ static bNodeSocketTemplate sh_node_output_material_in[] = { { SOCK_SHADER, 1, N_("Surface")}, { SOCK_SHADER, 1, N_("Volume")}, - { SOCK_FLOAT, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_VECTOR, 1, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } }; diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index a0f3a053618..0557efccc2f 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -392,6 +392,7 @@ void RE_updateRenderInstances(Render *re, int flag); /******* defined in render_result.c *********/ bool RE_HasCombinedLayer(RenderResult *res); +bool RE_HasFloatPixels(RenderResult *res); bool RE_RenderResult_is_stereo(RenderResult *res); struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id); struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 999e0f7f70e..5a5c99724fe 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -449,8 +449,6 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) rr->rectz = rv->rectz; rr->rect32 = rv->rect32; - rr->have_combined = (rv->rectf != NULL); - /* active layer */ rl = render_get_active_layer(re, re->result); @@ -861,7 +859,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->result = MEM_callocN(sizeof(RenderResult), "new render result"); re->result->rectx = re->rectx; re->result->recty = re->recty; - render_result_view_new(re->result, "new temporary view"); + render_result_view_new(re->result, ""); } if (re->r.scemode & R_VIEWPORT_PREVIEW) @@ -3395,7 +3393,8 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen return false; bool is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; - bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && + RE_HasFloatPixels(rr); if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index c250a91f4cb..6749fedb16e 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -80,6 +80,8 @@ static void render_result_views_free(RenderResult *res) MEM_freeN(rv); } + + res->have_combined = false; } void render_result_free(RenderResult *res) @@ -1352,6 +1354,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I RenderView *rv = RE_RenderViewGetById(rr, view_id); if (ibuf->rect_float) { + rr->have_combined = true; + if (!rv->rectf) rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); @@ -1362,6 +1366,8 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I MEM_SAFE_FREE(rv->rect32); } else if (ibuf->rect) { + rr->have_combined = true; + if (!rv->rect32) rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); @@ -1417,6 +1423,19 @@ bool RE_HasCombinedLayer(RenderResult *res) return (rv->rect32 || rv->rectf); } +bool RE_HasFloatPixels(RenderResult *res) +{ + RenderView *rview; + + for (rview = res->views.first; rview; rview = rview->next) { + if (rview->rect32 && !rview->rectf) { + return false; + } + } + + return true; +} + bool RE_RenderResult_is_stereo(RenderResult *res) { if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index b5784fe543c..059055daea9 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC intern/wm_window.c intern/wm_stereo.c intern/wm_toolsystem.c + intern/wm_tooltip.c manipulators/intern/wm_manipulator.c manipulators/intern/wm_manipulator_group.c manipulators/intern/wm_manipulator_group_type.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 85f94721d40..7a66cc04014 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -576,6 +576,17 @@ void WM_toolsystem_link(struct bContext *C, struct WorkSpace *workspace); void WM_toolsystem_set(struct bContext *C, const struct bToolDef *tool); void WM_toolsystem_init(struct bContext *C); +/* wm_tooltip.c */ +typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *); + +void WM_tooltip_timer_init( + struct bContext *C, struct wmWindow *win, struct ARegion *ar, + wmTooltipInitFn init); +void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_init(struct bContext *C, struct wmWindow *win); +void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win); + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index e30a109057d..74703daeb9c 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -704,6 +704,23 @@ typedef struct wmDropBox { } wmDropBox; +/** + * Struct to store tool-tip timer and possible creation if the time is reached. + * Allows UI code to call #WM_tooltip_timer_init without each user having to handle the timer. + */ +typedef struct wmTooltipState { + /** Create tooltip on this event. */ + struct wmTimer *timer; + /** The region the tooltip is created in. */ + struct ARegion *region_from; + /** The tooltip region. */ + struct ARegion *region; + /** Create the tooltip region (assign to 'region'). */ + struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event); + /** Exit on any event, not needed for buttons since their highlight state is used. */ + bool exit_on_event; +} wmTooltipState; + /* *************** migrated stuff, clean later? ************** */ typedef struct RecentFile { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 6e559ef7157..133ac6564f8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2275,30 +2275,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers wm_manipulatormap_handler_context(C, handler); wm_region_mouse_co(C, event); - if (event->type == MOUSEMOVE) { - WM_manipulatormap_tooltip_clear(C, mmap); - } - /* handle manipulator highlighting */ if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) { int part; mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part); wm_manipulatormap_highlight_set(mmap, C, mpr, part); if (mpr != NULL) { - WM_manipulatormap_tooltip_timer_init(C, mmap); - } - } - /* handle user configurable manipulator-map keymap */ - else if ((event->type == TIMER) && - (event->customdata == WM_manipulatormap_tooltip_timer_get(mmap))) - { - if (mpr) { - if (mpr->state & WM_MANIPULATOR_STATE_MODAL) { - WM_manipulatormap_tooltip_clear(C, mmap); - } - else { - WM_manipulatormap_tooltip_create(C, mmap); - } + WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init); } } else { @@ -2735,6 +2718,13 @@ void wm_event_do_handlers(bContext *C) CTX_wm_window_set(C, win); + /* Clear tool-tip on mouse move. */ + if (screen->tool_tip && screen->tool_tip->exit_on_event) { + if (ISMOUSE(event->type)) { + WM_tooltip_clear(C, win); + } + } + /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ CTX_wm_area_set(C, area_event_inside(C, &event->x)); CTX_wm_region_set(C, region_event_inside(C, &event->x)); @@ -2751,7 +2741,16 @@ void wm_event_do_handlers(bContext *C) /* fileread case */ if (CTX_wm_window(C) == NULL) return; - + + /* check for a tooltip */ + if (screen == WM_window_get_active_screen(win)) { + if (screen->tool_tip && screen->tool_tip->timer) { + if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) { + WM_tooltip_init(C, win); + } + } + } + /* check dragging, creates new event or frees, adds draw tag */ wm_event_drag_test(wm, win, event); diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c new file mode 100644 index 00000000000..83d620d1522 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_tooltip.c @@ -0,0 +1,106 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_tooltip.c + * \ingroup wm + * + * Manages a per-window tool-tip. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +void WM_tooltip_timer_init( + bContext *C, wmWindow *win, ARegion *ar, + wmTooltipInitFn init) +{ + bScreen *screen = WM_window_get_active_screen(win); + wmWindowManager *wm = CTX_wm_manager(C); + if (screen->tool_tip == NULL) { + screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__); + } + screen->tool_tip->region_from = ar; + screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY); + screen->tool_tip->init = init; +} + +void WM_tooltip_timer_clear(bContext *C, wmWindow *win) +{ + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->timer != NULL) { + WM_event_remove_timer(wm, win, screen->tool_tip->timer); + screen->tool_tip->timer = NULL; + } + } +} + +void WM_tooltip_clear(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + MEM_freeN(screen->tool_tip); + screen->tool_tip = NULL; + } +} + +void WM_tooltip_init(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + screen->tool_tip->region = screen->tool_tip->init( + C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event); + if (screen->tool_tip->region == NULL) { + WM_tooltip_clear(C, win); + } +} + +void WM_tooltip_refresh(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = WM_window_get_active_screen(win); + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + WM_tooltip_init(C, win); + } +} diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h index 7a31f4e6f1f..53bee9c6775 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -259,14 +259,8 @@ bool WM_manipulatormap_minmax( const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select, float r_min[3], float r_max[3]); -void WM_manipulatormap_tooltip_create( - struct bContext *C, struct wmManipulatorMap *mmap); -void WM_manipulatormap_tooltip_clear( - struct bContext *C, struct wmManipulatorMap *mmap); -void WM_manipulatormap_tooltip_timer_init( - struct bContext *C, struct wmManipulatorMap *mmap); -const void *WM_manipulatormap_tooltip_timer_get( - struct wmManipulatorMap *mmap); +struct ARegion *WM_manipulatormap_tooltip_init( + struct bContext *C, struct ARegion *ar, bool *r_exit_on_event); /* -------------------------------------------------------------------- */ /* wmManipulatorMapType */ @@ -335,6 +329,6 @@ void WM_manipulator_group_type_unlink_delayed_ptr( void WM_manipulator_group_type_unlink_delayed(const char *idname); /* Utilities */ -void WM_manipulator_group_type_is_any_selected(const char *idname); +bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step); #endif /* __WM_MANIPULATOR_API_H__ */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c index dff8d8b4e6c..3a78dd32f94 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c @@ -735,3 +735,28 @@ void WM_manipulator_properties_free(PointerRNA *ptr) } /** \} */ + +/** \name General Utilities + * + * \{ */ + +bool WM_manipulator_context_check_drawstep(const struct bContext *C, eWM_ManipulatorMapDrawStep step) +{ + switch (step) { + case WM_MANIPULATORMAP_DRAWSTEP_2D: + { + break; + } + case WM_MANIPULATORMAP_DRAWSTEP_3D: + { + wmWindowManager *wm = CTX_wm_manager(C); + if (ED_screen_animation_playing(wm)) { + return false; + } + break; + } + } + return true; +} + +/** \} */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c index 2bd218298e6..0e63f3d6ffe 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c @@ -145,7 +145,7 @@ void wm_manipulatorgroup_manipulator_register(wmManipulatorGroup *mgroup, wmMani mpr->parent_mgroup = mgroup; } -wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( +wmManipulator *wm_manipulatorgroup_find_intersected_manipulator( const wmManipulatorGroup *mgroup, bContext *C, const wmEvent *event, int *r_part) { @@ -500,7 +500,7 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent * wmManipulator *mpr = mmap->mmap_context.highlight; /* Needed for single click actions which don't enter modal state. */ - WM_manipulatormap_tooltip_clear(C, mmap); + WM_tooltip_clear(C, CTX_wm_window(C)); if (!mpr) { /* wm_handlers_do_intern shouldn't let this happen */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h index fc814adaef1..b7982cf00df 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h @@ -69,7 +69,7 @@ struct wmManipulatorGroup *wm_manipulatorgroup_new_from_type( struct wmManipulatorMap *mmap, struct wmManipulatorGroupType *wgt); void wm_manipulatorgroup_free(bContext *C, struct wmManipulatorGroup *mgroup); void wm_manipulatorgroup_manipulator_register(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr); -struct wmManipulator *wm_manipulatorgroup_find_intersected_mainpulator( +struct wmManipulator *wm_manipulatorgroup_find_intersected_manipulator( const struct wmManipulatorGroup *mgroup, struct bContext *C, const struct wmEvent *event, int *r_part); void wm_manipulatorgroup_intersectable_manipulators_to_list( @@ -115,9 +115,6 @@ struct wmManipulatorMap { /* cursor location at point of entering modal (see: WM_MANIPULATOR_GRAB_CURSOR) */ int event_xy[2]; short event_grabcursor; - - struct ARegion *tooltip; - struct wmTimer *tooltip_timer; } mmap_context; }; diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c index d051c93d892..a9875020fbb 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c @@ -445,6 +445,10 @@ void WM_manipulatormap_draw( wmManipulatorMap *mmap, const bContext *C, const eWM_ManipulatorMapDrawStep drawstep) { + if (!WM_manipulator_context_check_drawstep(C, drawstep)) { + return; + } + ListBase draw_manipulators = {NULL}; manipulatormap_prepare_drawing(mmap, C, &draw_manipulators, drawstep); @@ -550,6 +554,7 @@ static wmManipulator *manipulator_find_intersected_3d( }; *r_part = 0; + /* set up view matrices */ view3d_operator_needs_opengl(C); @@ -588,6 +593,11 @@ wmManipulator *wm_manipulatormap_highlight_find( { wmManipulator *mpr = NULL; ListBase visible_3d_manipulators = {NULL}; + bool do_step[WM_MANIPULATORMAP_DRAWSTEP_MAX]; + + for (int i = 0; i < ARRAY_SIZE(do_step); i++) { + do_step[i] = WM_manipulator_context_check_drawstep(C, i); + } for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) { @@ -599,25 +609,28 @@ wmManipulator *wm_manipulatormap_highlight_find( } if (wm_manipulatorgroup_is_visible(mgroup, C)) { + eWM_ManipulatorMapDrawStep step; if (mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_3D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && - mgroup->type->refresh) - { - mgroup->type->refresh(C, mgroup); - /* cleared below */ - } - wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + step = WM_MANIPULATORMAP_DRAWSTEP_3D; } else { - if ((mmap->update_flag[WM_MANIPULATORMAP_DRAWSTEP_2D] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && - mgroup->type->refresh) + step = WM_MANIPULATORMAP_DRAWSTEP_2D; + } + + if (do_step[step]) { + if ((mmap->update_flag[step] & MANIPULATORMAP_IS_REFRESH_CALLBACK) && + (mgroup->type->refresh != NULL)) { mgroup->type->refresh(C, mgroup); /* cleared below */ } - - if ((mpr = wm_manipulatorgroup_find_intersected_mainpulator(mgroup, C, event, r_part))) { - break; + if (step == WM_MANIPULATORMAP_DRAWSTEP_3D) { + wm_manipulatorgroup_intersectable_manipulators_to_list(mgroup, &visible_3d_manipulators); + } + else if (step == WM_MANIPULATORMAP_DRAWSTEP_2D) { + if ((mpr = wm_manipulatorgroup_find_intersected_manipulator(mgroup, C, event, r_part))) { + break; + } } } } @@ -891,7 +904,7 @@ void wm_manipulatormap_modal_set( BLI_assert(mmap->mmap_context.modal == NULL); wmWindow *win = CTX_wm_window(C); - WM_manipulatormap_tooltip_clear(C, mmap); + WM_tooltip_clear(C, win); if (mpr->type->invoke && (mpr->type->modal || mpr->custom_modal)) @@ -1005,45 +1018,18 @@ void WM_manipulatormap_message_subscribe( * * \{ */ - -void WM_manipulatormap_tooltip_create( - bContext *C, wmManipulatorMap *mmap) +struct ARegion *WM_manipulatormap_tooltip_init( + struct bContext *C, struct ARegion *ar, bool *r_exit_on_event) { - WM_manipulatormap_tooltip_clear(C, mmap); - if (mmap->mmap_context.highlight) { - mmap->mmap_context.tooltip = UI_tooltip_create_from_manipulator(C, mmap->mmap_context.highlight); - } -} - -void WM_manipulatormap_tooltip_clear( - bContext *C, wmManipulatorMap *mmap) -{ - if (mmap->mmap_context.tooltip_timer != NULL) { - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - WM_event_remove_timer(wm, win, mmap->mmap_context.tooltip_timer); - mmap->mmap_context.tooltip_timer = NULL; - } - if (mmap->mmap_context.tooltip != NULL) { - UI_tooltip_free(C, mmap->mmap_context.tooltip); - mmap->mmap_context.tooltip = NULL; - } -} - -void WM_manipulatormap_tooltip_timer_init( - bContext *C, wmManipulatorMap *mmap) -{ - if (mmap->mmap_context.tooltip_timer == NULL) { - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - /* TODO: BUTTON_TOOLTIP_DELAY */ - mmap->mmap_context.tooltip_timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY); + wmManipulatorMap *mmap = ar->manipulator_map; + *r_exit_on_event = true; + if (mmap) { + wmManipulator *mpr = mmap->mmap_context.highlight; + if (mpr) { + return UI_tooltip_create_from_manipulator(C, mpr); + } } -} - -const void *WM_manipulatormap_tooltip_timer_get(wmManipulatorMap *mmap) -{ - return mmap->mmap_context.tooltip_timer; + return NULL; } /** \} */ /* wmManipulatorMapType */ |