Compositor: add new node: Kuwahara filter #107015
|
@ -79,6 +79,7 @@ struct CCLShadowContext
|
|||
#endif
|
||||
IntegratorShadowState isect_s;
|
||||
float throughput;
|
||||
float max_t;
|
||||
bool opaque_hit;
|
||||
numhit_t max_hits;
|
||||
numhit_t num_hits;
|
||||
|
@ -314,7 +315,7 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
|||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
RTCRay *ray = (RTCRay *)args->ray;
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
#if EMBREE_MAJOR_VERSION >= 4
|
||||
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
|
||||
|
@ -367,42 +368,51 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
|||
}
|
||||
}
|
||||
|
||||
/* Test if we need to record this transparent intersection. */
|
||||
const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
|
||||
if (ctx->num_recorded_hits < max_record_hits) {
|
||||
/* If maximum number of hits was reached, replace the intersection with the
|
||||
* highest distance. We want to find the N closest intersections. */
|
||||
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
|
||||
numhit_t isect_index = num_recorded_hits;
|
||||
if (num_recorded_hits + 1 >= max_record_hits) {
|
||||
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
|
||||
numhit_t max_recorded_hit = numhit_t(0);
|
||||
|
||||
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
|
||||
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
|
||||
if (isect_t > max_t) {
|
||||
max_recorded_hit = i;
|
||||
max_t = isect_t;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_recorded_hits >= max_record_hits) {
|
||||
isect_index = max_recorded_hit;
|
||||
}
|
||||
|
||||
/* Limit the ray distance and stop counting hits beyond this. */
|
||||
ray->tfar = max(current_isect.t, max_t);
|
||||
}
|
||||
|
||||
integrator_state_write_shadow_isect(ctx->isect_s, ¤t_isect, isect_index);
|
||||
}
|
||||
numhit_t isect_index = ctx->num_recorded_hits;
|
||||
|
||||
/* Always increase the number of recorded hits, even beyond the maximum,
|
||||
* so that we can detect this and trace another ray if needed. */
|
||||
* so that we can detect this and trace another ray if needed.
|
||||
* More details about the related logic can be found in implementation of
|
||||
* "shadow_intersections_has_remaining" and "integrate_transparent_shadow"
|
||||
* functions. */
|
||||
++ctx->num_recorded_hits;
|
||||
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
|
||||
const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
|
||||
/* If the maximum number of hits was reached, replace the furthest intersection
|
||||
* with a closer one so we get the N closest intersections. */
|
||||
if (isect_index >= max_record_hits) {
|
||||
/* When recording only N closest hits, max_t will always only decrease.
|
||||
* So let's test if we are already not meeting criteria and can skip max_t recalculation. */
|
||||
if (current_isect.t >= ctx->max_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
|
||||
numhit_t max_recorded_hit = numhit_t(0);
|
||||
|
||||
for (numhit_t i = numhit_t(1); i < max_record_hits; ++i) {
|
||||
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
|
||||
if (isect_t > max_t) {
|
||||
max_recorded_hit = i;
|
||||
max_t = isect_t;
|
||||
}
|
||||
}
|
||||
|
||||
isect_index = max_recorded_hit;
|
||||
|
||||
/* Limit the ray distance and avoid processing hits beyond this. */
|
||||
ctx->max_t = max_t;
|
||||
|
||||
/* If it's further away than max_t, we don't record this transparent intersection. */
|
||||
if (current_isect.t >= max_t) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
integrator_state_write_shadow_isect(ctx->isect_s, ¤t_isect, isect_index);
|
||||
}
|
||||
|
||||
ccl_device_forceinline void kernel_embree_filter_occluded_local_func_impl(
|
||||
|
|
|
@ -350,7 +350,7 @@ def main():
|
|||
if name.rpartition(".")[2].isdigit():
|
||||
continue
|
||||
|
||||
if not ob_eval.data.attributes.active_color:
|
||||
if (not hasattr(ob_eval.data, 'attributes')) or not ob_eval.data.attributes.active_color:
|
||||
print("Skipping:", name, "(no vertex colors)")
|
||||
continue
|
||||
|
||||
|
|
|
@ -1836,6 +1836,10 @@ def km_graph_editor(params):
|
|||
("graph.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
|
||||
("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
|
||||
("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
("graph.keyframe_jump", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("next", True)]}),
|
||||
("graph.keyframe_jump", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("next", False)]}),
|
||||
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True}, None),
|
||||
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "shift": True, "ctrl": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
|
|
|
@ -3111,7 +3111,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
|||
*_tools_annotate,
|
||||
],
|
||||
'EDIT_GPENCIL': [
|
||||
*_tools_gpencil_select,
|
||||
*_tools_select,
|
||||
_defs_view3d_generic.cursor,
|
||||
None,
|
||||
*_tools_transform,
|
||||
|
|
|
@ -38,6 +38,13 @@ typedef struct AssetTypeInfo {
|
|||
struct AssetMetaData *BKE_asset_metadata_create(void);
|
||||
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
|
||||
|
||||
/**
|
||||
* Create a copy of the #AssetMetaData so that it can be assigned to another asset.
|
||||
*
|
||||
* The caller becomes the owner of the returned pointer.
|
||||
*/
|
||||
struct AssetMetaData *BKE_asset_metadata_copy(const struct AssetMetaData *source);
|
||||
|
||||
struct AssetTagEnsureResult {
|
||||
struct AssetTag *tag;
|
||||
/* Set to false if a tag of this name was already present. */
|
||||
|
|
|
@ -51,5 +51,8 @@ struct GeometryDeformation {
|
|||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig,
|
||||
int drawing_index);
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
|
|
@ -39,6 +39,38 @@ void BKE_asset_metadata_free(AssetMetaData **asset_data)
|
|||
*asset_data = nullptr;
|
||||
}
|
||||
|
||||
AssetMetaData *BKE_asset_metadata_copy(const AssetMetaData *source)
|
||||
{
|
||||
AssetMetaData *copy = BKE_asset_metadata_create();
|
||||
|
||||
copy->local_type_info = source->local_type_info;
|
||||
|
||||
if (source->properties) {
|
||||
copy->properties = IDP_CopyProperty(source->properties);
|
||||
}
|
||||
|
||||
BKE_asset_metadata_catalog_id_set(copy, source->catalog_id, source->catalog_simple_name);
|
||||
|
||||
if (source->author) {
|
||||
copy->author = BLI_strdup(source->author);
|
||||
}
|
||||
if (source->description) {
|
||||
copy->description = BLI_strdup(source->description);
|
||||
}
|
||||
if (source->copyright) {
|
||||
copy->copyright = BLI_strdup(source->copyright);
|
||||
}
|
||||
if (source->license) {
|
||||
copy->license = BLI_strdup(source->license);
|
||||
}
|
||||
|
||||
BLI_duplicatelist(©->tags, &source->tags);
|
||||
copy->active_tag = source->active_tag;
|
||||
copy->tot_tags = source->tot_tags;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
AssetMetaData::~AssetMetaData()
|
||||
{
|
||||
if (properties) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BKE_curves.hh"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
|
@ -662,4 +663,37 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
|||
return get_evaluated_curves_deformation(ob_eval, ob_orig);
|
||||
}
|
||||
|
||||
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig,
|
||||
const int drawing_index)
|
||||
{
|
||||
BLI_assert(ob_orig.type == OB_GREASE_PENCIL);
|
||||
const GreasePencil &grease_pencil_orig = *static_cast<const GreasePencil *>(ob_orig.data);
|
||||
|
||||
GreasePencilDrawingBase *drawing_base = grease_pencil_orig.drawings()[drawing_index];
|
||||
|
||||
GeometryDeformation deformation;
|
||||
if (drawing_base->type == GP_DRAWING) {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = drawing->geometry.wrap().positions();
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
if (ob_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
const GeometrySet *geometry_eval = ob_eval->runtime.geometry_set_eval;
|
||||
if (geometry_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
|
||||
/* TODO: Read `GeometryComponentEditData` from `geometry_eval` and populate deformation with it.
|
||||
*/
|
||||
|
||||
return deformation;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
|
|
@ -1061,7 +1061,7 @@ enum ForeachDrawingMode {
|
|||
static void foreach_drawing_ex(GreasePencil &grease_pencil,
|
||||
int frame,
|
||||
ForeachDrawingMode mode,
|
||||
blender::FunctionRef<void(GreasePencilDrawing &)> function)
|
||||
blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
|
@ -1089,7 +1089,7 @@ static void foreach_drawing_ex(GreasePencil &grease_pencil,
|
|||
GreasePencilDrawingBase *drawing_base = drawings[index];
|
||||
if (drawing_base->type == GP_DRAWING) {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
function(*drawing);
|
||||
function(index, *drawing);
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO */
|
||||
|
@ -1098,13 +1098,13 @@ static void foreach_drawing_ex(GreasePencil &grease_pencil,
|
|||
}
|
||||
|
||||
void GreasePencil::foreach_visible_drawing(
|
||||
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
|
||||
int frame, blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
|
||||
{
|
||||
foreach_drawing_ex(*this, frame, VISIBLE, function);
|
||||
}
|
||||
|
||||
void GreasePencil::foreach_editable_drawing(
|
||||
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
|
||||
int frame, blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
|
||||
{
|
||||
foreach_drawing_ex(*this, frame, EDITABLE, function);
|
||||
}
|
||||
|
|
|
@ -204,7 +204,8 @@ static void grease_pencil_geom_batch_ensure(GreasePencil &grease_pencil, int cfr
|
|||
/* Get the visible drawings. */
|
||||
Vector<const GreasePencilDrawing *> drawings;
|
||||
grease_pencil.foreach_visible_drawing(
|
||||
cfra, [&](GreasePencilDrawing &drawing) { drawings.append(&drawing); });
|
||||
cfra,
|
||||
[&](int /*drawing_index*/, GreasePencilDrawing &drawing) { drawings.append(&drawing); });
|
||||
|
||||
/* First, count how many vertices and triangles are needed for the whole object. Also record the
|
||||
* offsets into the curves for the vertices and triangles. */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AssetMetaData;
|
||||
struct ID;
|
||||
struct Main;
|
||||
struct bContext;
|
||||
|
@ -42,6 +43,18 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
|
|||
*/
|
||||
bool ED_asset_clear_id(struct ID *id);
|
||||
|
||||
/**
|
||||
* Copy the asset metadata to the given destination ID.
|
||||
*
|
||||
* The copy is assigned to \a destination, any pre-existing asset metadata is
|
||||
* freed before that. If \a destination was not yet marked as asset, it will be
|
||||
* after this call.
|
||||
*
|
||||
* \return true when the copy succeeded, false otherwise. The only reason for
|
||||
* failure is when \a destination is of a type that cannot be an asset.
|
||||
*/
|
||||
bool ED_asset_copy_to_id(const struct AssetMetaData *asset_data, struct ID *destination);
|
||||
|
||||
void ED_assets_pre_save(struct Main *bmain);
|
||||
|
||||
bool ED_asset_can_mark_single_from_context(const struct bContext *C);
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include "ED_asset_mark_clear.h"
|
||||
#include "ED_asset_type.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
bool ED_asset_mark_id(ID *id)
|
||||
{
|
||||
if (id->asset_data) {
|
||||
|
@ -96,3 +99,16 @@ bool ED_asset_can_mark_single_from_context(const bContext *C)
|
|||
}
|
||||
return ED_asset_type_is_supported(id);
|
||||
}
|
||||
|
||||
bool ED_asset_copy_to_id(const struct AssetMetaData *asset_data, struct ID *destination)
|
||||
{
|
||||
if (!BKE_id_can_be_asset(destination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destination->asset_data) {
|
||||
BKE_asset_metadata_free(&destination->asset_data);
|
||||
}
|
||||
destination->asset_data = BKE_asset_metadata_copy(asset_data);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -48,10 +48,11 @@ static int select_all_exec(bContext *C, wmOperator *op)
|
|||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
|
||||
grease_pencil.foreach_editable_drawing(scene->r.cfra, [action](GreasePencilDrawing &drawing) {
|
||||
// TODO: Support different selection domains.
|
||||
blender::ed::curves::select_all(drawing.geometry.wrap(), ATTR_DOMAIN_POINT, action);
|
||||
});
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [action](int /*drawing_index*/, GreasePencilDrawing &drawing) {
|
||||
// TODO: Support different selection domains.
|
||||
blender::ed::curves::select_all(drawing.geometry.wrap(), ATTR_DOMAIN_POINT, action);
|
||||
});
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
|
||||
* attribute for now. */
|
||||
|
|
|
@ -2408,7 +2408,10 @@ void uiTemplateImage(uiLayout *layout,
|
|||
struct PointerRNA *userptr,
|
||||
bool compact,
|
||||
bool multiview);
|
||||
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management);
|
||||
void uiTemplateImageSettings(uiLayout *layout,
|
||||
struct PointerRNA *imfptr,
|
||||
bool color_management,
|
||||
bool show_z_buffer);
|
||||
void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
|
||||
void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
|
||||
void uiTemplateImageFormatViews(uiLayout *layout,
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "interface_intern.hh"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_path.h"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
|
@ -344,7 +345,10 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *
|
|||
}
|
||||
if (but->rnaprop) {
|
||||
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
const char *prop_id = RNA_property_identifier(but->rnaprop);
|
||||
/* Ignore the actual array index [pass -1] since the index is handled separately. */
|
||||
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
|
||||
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
|
||||
RNA_property_identifier(but->rnaprop);
|
||||
bUserMenuItem *umi = (bUserMenuItem *)ED_screen_user_menu_item_find_prop(
|
||||
&um->items, member_id_data_path, prop_id, but->rnaindex);
|
||||
MEM_freeN(member_id_data_path);
|
||||
|
@ -419,7 +423,10 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
|
|||
else if (but->rnaprop) {
|
||||
/* NOTE: 'member_id' may be a path. */
|
||||
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
|
||||
const char *prop_id = RNA_property_identifier(but->rnaprop);
|
||||
/* Ignore the actual array index [pass -1] since the index is handled separately. */
|
||||
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
|
||||
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
|
||||
RNA_property_identifier(but->rnaprop);
|
||||
/* NOTE: ignore 'drawstr', use property idname always. */
|
||||
ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex);
|
||||
MEM_freeN(member_id_data_path);
|
||||
|
|
|
@ -3180,6 +3180,12 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static bool keyframe_jump_poll(bContext *C)
|
||||
{
|
||||
/* There is a keyframe jump operator specifically for the Graph Editor. */
|
||||
return ED_operator_screenactive_norender(C) && CTX_wm_area(C)->spacetype != SPACE_GRAPH;
|
||||
}
|
||||
|
||||
static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Jump to Keyframe";
|
||||
|
@ -3188,7 +3194,7 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
|
|||
|
||||
ot->exec = keyframe_jump_exec;
|
||||
|
||||
ot->poll = ED_operator_screenactive_norender;
|
||||
ot->poll = keyframe_jump_poll;
|
||||
ot->flag = OPTYPE_UNDO_GROUPED;
|
||||
ot->undo_group = "Frame Change";
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
|
|||
/* image template */
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &scd->im_format, &ptr);
|
||||
uiTemplateImageSettings(layout, &ptr, false);
|
||||
uiTemplateImageSettings(layout, &ptr, false, true);
|
||||
|
||||
/* main draw call */
|
||||
uiDefAutoButsRNA(
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "BKE_global.h"
|
||||
#include "BKE_nla.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
|
@ -2179,6 +2180,104 @@ void GRAPH_OT_frame_jump(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static bool find_closest_frame(const FCurve *fcu,
|
||||
const float frame,
|
||||
const bool next,
|
||||
float *closest_frame)
|
||||
{
|
||||
bool replace;
|
||||
int bezt_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace);
|
||||
|
||||
BezTriple *bezt;
|
||||
if (next) {
|
||||
if (replace) {
|
||||
bezt_index++;
|
||||
}
|
||||
if (bezt_index > fcu->totvert - 1) {
|
||||
return false;
|
||||
}
|
||||
bezt = &fcu->bezt[bezt_index];
|
||||
}
|
||||
else {
|
||||
if (bezt_index - 1 < 0) {
|
||||
return false;
|
||||
}
|
||||
bezt = &fcu->bezt[bezt_index - 1];
|
||||
}
|
||||
|
||||
*closest_frame = bezt->vec[1][0];
|
||||
return true;
|
||||
}
|
||||
|
||||
static int keyframe_jump_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
bool next = RNA_boolean_get(op->ptr, "next");
|
||||
|
||||
/* Get editor data. */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
|
||||
ANIMFILTER_NODUPLIS);
|
||||
if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
|
||||
filter |= ANIMFILTER_SEL;
|
||||
}
|
||||
|
||||
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
||||
|
||||
float closest_frame = next ? FLT_MAX : -FLT_MAX;
|
||||
bool found = false;
|
||||
|
||||
const float current_frame = BKE_scene_frame_get(scene);
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
const FCurve *fcu = ale->key_data;
|
||||
if (!fcu->bezt) {
|
||||
continue;
|
||||
}
|
||||
float closest_fcu_frame;
|
||||
if (!find_closest_frame(fcu, current_frame, next, &closest_fcu_frame)) {
|
||||
continue;
|
||||
}
|
||||
if ((next && closest_fcu_frame < closest_frame) ||
|
||||
(!next && closest_fcu_frame > closest_frame)) {
|
||||
closest_frame = closest_fcu_frame;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_scene_frame_set(scene, closest_frame);
|
||||
|
||||
/* Set notifier that things have changed. */
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GRAPH_OT_keyframe_jump(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Jump to Keyframe";
|
||||
ot->description = "Jump to previous/next keyframe";
|
||||
ot->idname = "GRAPH_OT_keyframe_jump";
|
||||
|
||||
ot->exec = keyframe_jump_exec;
|
||||
|
||||
ot->poll = graphkeys_framejump_poll;
|
||||
ot->flag = OPTYPE_UNDO_GROUPED;
|
||||
ot->undo_group = "Frame Change";
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
|
||||
}
|
||||
|
||||
/* snap 2D cursor value to the average value of selected keyframe */
|
||||
static int graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
|
|
|
@ -131,6 +131,7 @@ void GRAPH_OT_extrapolation_type(struct wmOperatorType *ot);
|
|||
void GRAPH_OT_easing_type(struct wmOperatorType *ot);
|
||||
|
||||
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_keyframe_jump(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_snap(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_equalize_handles(struct wmOperatorType *ot);
|
||||
|
|
|
@ -449,6 +449,7 @@ void graphedit_operatortypes(void)
|
|||
WM_operatortype_append(GRAPH_OT_equalize_handles);
|
||||
WM_operatortype_append(GRAPH_OT_mirror);
|
||||
WM_operatortype_append(GRAPH_OT_frame_jump);
|
||||
WM_operatortype_append(GRAPH_OT_keyframe_jump);
|
||||
WM_operatortype_append(GRAPH_OT_snap_cursor_value);
|
||||
WM_operatortype_append(GRAPH_OT_handle_type);
|
||||
WM_operatortype_append(GRAPH_OT_interpolation_type);
|
||||
|
|
|
@ -962,7 +962,10 @@ void uiTemplateImage(uiLayout *layout,
|
|||
UI_block_funcN_set(block, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management)
|
||||
void uiTemplateImageSettings(uiLayout *layout,
|
||||
PointerRNA *imfptr,
|
||||
bool color_management,
|
||||
bool show_z_buffer)
|
||||
{
|
||||
ImageFormatData *imf = imfptr->data;
|
||||
ID *id = imfptr->owner_id;
|
||||
|
@ -1014,7 +1017,7 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
|
|||
uiItemR(col, imfptr, "exr_codec", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
if (BKE_imtype_supports_zbuf(imf->imtype)) {
|
||||
if (BKE_imtype_supports_zbuf(imf->imtype) && show_z_buffer) {
|
||||
uiItemR(col, imfptr, "use_zbuffer", 0, NULL, ICON_NONE);
|
||||
}
|
||||
|
||||
|
|
|
@ -2007,7 +2007,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
|
|||
|
||||
/* Image format settings. */
|
||||
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->opts.im_format, &imf_ptr);
|
||||
uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
|
||||
uiTemplateImageSettings(layout, &imf_ptr, save_as_render, true);
|
||||
|
||||
if (!save_as_render) {
|
||||
PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_mball.h"
|
||||
#include "BKE_mesh.hh"
|
||||
|
@ -1171,6 +1172,43 @@ static bool do_lasso_select_meta(ViewContext *vc,
|
|||
return data.is_changed;
|
||||
}
|
||||
|
||||
static bool do_lasso_select_grease_pencil(ViewContext *vc,
|
||||
const int mcoords[][2],
|
||||
const int mcoords_len,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
using namespace blender;
|
||||
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph,
|
||||
const_cast<Object *>(vc->obedit));
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc->obedit->data);
|
||||
|
||||
bool changed = false;
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
vc->scene->r.cfra, [&](int drawing_index, GreasePencilDrawing &drawing) {
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc->obedit, drawing_index);
|
||||
|
||||
/* TODO: Support different selection domains. */
|
||||
changed = ed::curves::select_lasso(
|
||||
*vc,
|
||||
drawing.geometry.wrap(),
|
||||
deformation.positions,
|
||||
ATTR_DOMAIN_POINT,
|
||||
Span<int2>(reinterpret_cast<const int2 *>(mcoords), mcoords_len),
|
||||
sel_op);
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(vc->C, NC_GEOM | ND_DATA, vc->obedit->data);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
struct LassoSelectUserData_ForMeshVert {
|
||||
LassoSelectUserData lasso_data;
|
||||
blender::MutableSpan<bool> select_vert;
|
||||
|
@ -1388,6 +1426,10 @@ static bool view3d_lasso_select(bContext *C,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case OB_GREASE_PENCIL: {
|
||||
changed = do_lasso_select_grease_pencil(vc, mcoords, mcoords_len, sel_op);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_msg(0, "lasso select on incorrect object type");
|
||||
break;
|
||||
|
@ -3097,6 +3139,112 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
|
|||
return true;
|
||||
}
|
||||
|
||||
struct ClosestGreasePencilDrawing {
|
||||
GreasePencilDrawing *drawing = nullptr;
|
||||
blender::ed::curves::FindClosestData elem = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Cursor selection for all Grease Pencil curves in edit mode.
|
||||
*
|
||||
* \returns true if the selection changed.
|
||||
*/
|
||||
static bool ed_grease_pencil_select_pick(bContext *C,
|
||||
const int mval[2],
|
||||
const SelectPick_Params ¶ms)
|
||||
{
|
||||
using namespace blender;
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
ViewContext vc;
|
||||
/* Setup view context for argument to callbacks. */
|
||||
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
||||
|
||||
/* Collect editable drawings. */
|
||||
const Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, const_cast<Object *>(vc.obedit));
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc.obedit->data);
|
||||
Vector<GreasePencilDrawing *> drawings;
|
||||
Vector<int> drawing_indices;
|
||||
grease_pencil.foreach_editable_drawing(vc.scene->r.cfra,
|
||||
[&](int drawing_index, GreasePencilDrawing &drawing) {
|
||||
drawings.append(&drawing);
|
||||
drawing_indices.append(drawing_index);
|
||||
});
|
||||
|
||||
/* TODO: Support different selection domains. */
|
||||
const eAttrDomain selection_domain = ATTR_DOMAIN_POINT;
|
||||
|
||||
const ClosestGreasePencilDrawing closest = threading::parallel_reduce(
|
||||
drawings.index_range(),
|
||||
1L,
|
||||
ClosestGreasePencilDrawing(),
|
||||
[&](const IndexRange range, const ClosestGreasePencilDrawing &init) {
|
||||
ClosestGreasePencilDrawing new_closest = init;
|
||||
for (const int i : range) {
|
||||
/* Get deformation by modifiers. */
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc.obedit, drawing_indices[i]);
|
||||
std::optional<ed::curves::FindClosestData> new_closest_elem =
|
||||
ed::curves::closest_elem_find_screen_space(vc,
|
||||
*vc.obedit,
|
||||
drawings[i]->geometry.wrap(),
|
||||
deformation.positions,
|
||||
selection_domain,
|
||||
mval,
|
||||
new_closest.elem);
|
||||
if (new_closest_elem) {
|
||||
new_closest.elem = *new_closest_elem;
|
||||
new_closest.drawing = drawings[i];
|
||||
}
|
||||
}
|
||||
return new_closest;
|
||||
},
|
||||
[](const ClosestGreasePencilDrawing &a, const ClosestGreasePencilDrawing &b) {
|
||||
return (a.elem.distance < b.elem.distance) ? a : b;
|
||||
});
|
||||
|
||||
std::atomic<bool> deselected = false;
|
||||
if (params.deselect_all || params.sel_op == SEL_OP_SET) {
|
||||
threading::parallel_for(drawings.index_range(), 1L, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
bke::CurvesGeometry &curves = drawings[i]->geometry.wrap();
|
||||
if (ed::curves::has_anything_selected(curves)) {
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
|
||||
deselected = true;
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!closest.drawing) {
|
||||
return deselected;
|
||||
}
|
||||
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
closest.drawing->geometry.wrap(), selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::apply_selection_operation_at_index(
|
||||
selection.span, closest.elem.index, params.sel_op);
|
||||
selection.finish();
|
||||
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
if (!deselected) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
@ -3193,6 +3341,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
|||
else if (obedit->type == OB_CURVES) {
|
||||
changed = ed_curves_select_pick(*C, mval, params);
|
||||
}
|
||||
else if (obedit->type == OB_GREASE_PENCIL) {
|
||||
changed = ed_grease_pencil_select_pick(C, mval, params);
|
||||
}
|
||||
}
|
||||
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
|
||||
changed = PE_mouse_particles(C, mval, ¶ms);
|
||||
|
@ -4028,6 +4179,32 @@ static bool do_pose_box_select(bContext *C,
|
|||
return changed_multi;
|
||||
}
|
||||
|
||||
static bool do_grease_pencil_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
|
||||
{
|
||||
using namespace blender;
|
||||
Scene *scene = vc->scene;
|
||||
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph,
|
||||
const_cast<Object *>(vc->obedit));
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc->obedit->data);
|
||||
|
||||
bool changed = false;
|
||||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [&](int drawing_index, GreasePencilDrawing &drawing) {
|
||||
bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
|
||||
ob_eval, *vc->obedit, drawing_index);
|
||||
changed |= ed::curves::select_box(
|
||||
*vc, drawing.geometry.wrap(), deformation.positions, ATTR_DOMAIN_POINT, *rect, sel_op);
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(vc->C, NC_GEOM | ND_DATA, &grease_pencil);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace blender;
|
||||
|
@ -4113,6 +4290,10 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case OB_GREASE_PENCIL: {
|
||||
changed = do_grease_pencil_box_select(&vc, &rect, sel_op);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_msg(0, "box select on incorrect object type");
|
||||
break;
|
||||
|
|
|
@ -428,13 +428,11 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5()
|
|||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5);
|
||||
#endif
|
||||
|
||||
#if RUN_UNSUPPORTED
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F()
|
||||
{
|
||||
texture_create_upload_read_with_bias<GPU_DEPTH_COMPONENT32F, GPU_DATA_FLOAT>(0.0f);
|
||||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F);
|
||||
#endif
|
||||
|
||||
#if RUN_COMPONENT_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24()
|
||||
|
@ -622,7 +620,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R32UI()
|
|||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R32UI);
|
||||
|
||||
#if RUN_UNSUPPORTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH32F_STENCIL8()
|
||||
{
|
||||
texture_create_upload_read<GPU_DEPTH32F_STENCIL8, GPU_DATA_UINT, uint32_t>();
|
||||
|
@ -634,7 +631,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8()
|
|||
texture_create_upload_read<GPU_DEPTH24_STENCIL8, GPU_DATA_UINT, uint32_t>();
|
||||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8);
|
||||
#endif
|
||||
|
||||
#if RUN_UNSUPPORTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB8UI()
|
||||
|
@ -656,7 +652,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI()
|
|||
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI);
|
||||
#endif
|
||||
|
||||
#if RUN_COMPONENT_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT32F()
|
||||
{
|
||||
texture_create_upload_read<GPU_DEPTH_COMPONENT32F, GPU_DATA_UINT, uint32_t>();
|
||||
|
@ -669,6 +664,7 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24()
|
|||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24);
|
||||
|
||||
#if RUN_COMPONENT_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16()
|
||||
{
|
||||
texture_create_upload_read<GPU_DEPTH_COMPONENT16, GPU_DATA_UINT, uint32_t>();
|
||||
|
@ -718,13 +714,11 @@ static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_R8()
|
|||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_R8);
|
||||
|
||||
#if RUN_SRGB_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8()
|
||||
{
|
||||
texture_create_upload_read<GPU_SRGB8_A8, GPU_DATA_UBYTE, uint8_t>();
|
||||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8);
|
||||
#endif
|
||||
|
||||
#if RUN_UNSUPPORTED
|
||||
static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8I()
|
||||
|
|
|
@ -73,6 +73,18 @@ void VKBackend::platform_init(const VKDevice &device)
|
|||
driver_version.c_str());
|
||||
}
|
||||
|
||||
void VKBackend::detect_workarounds(VKDevice &device)
|
||||
{
|
||||
VKWorkarounds workarounds;
|
||||
|
||||
/* AMD GPUs don't support texture formats that use are aligned to 24 or 48 bits. */
|
||||
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
|
||||
workarounds.not_aligned_pixel_formats = true;
|
||||
}
|
||||
|
||||
device.workarounds_ = workarounds;
|
||||
}
|
||||
|
||||
void VKBackend::platform_exit()
|
||||
{
|
||||
GPG.clear();
|
||||
|
@ -174,7 +186,7 @@ shaderc::Compiler &VKBackend::get_shaderc_compiler()
|
|||
return shaderc_compiler_;
|
||||
}
|
||||
|
||||
void VKBackend::capabilities_init(const VKDevice &device)
|
||||
void VKBackend::capabilities_init(VKDevice &device)
|
||||
{
|
||||
const VkPhysicalDeviceProperties &properties = device.physical_device_properties_get();
|
||||
const VkPhysicalDeviceLimits &limits = properties.limits;
|
||||
|
@ -205,6 +217,8 @@ void VKBackend::capabilities_init(const VKDevice &device)
|
|||
GCaps.max_varying_floats = limits.maxVertexOutputComponents;
|
||||
GCaps.max_shader_storage_buffer_bindings = limits.maxPerStageDescriptorStorageBuffers;
|
||||
GCaps.max_compute_shader_storage_blocks = limits.maxPerStageDescriptorStorageBuffers;
|
||||
|
||||
detect_workarounds(device);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -88,9 +88,10 @@ class VKBackend : public GPUBackend {
|
|||
}
|
||||
|
||||
static void platform_init(const VKDevice &device);
|
||||
static void capabilities_init(const VKDevice &device);
|
||||
static void capabilities_init(VKDevice &device);
|
||||
|
||||
private:
|
||||
static void detect_workarounds(VKDevice &device);
|
||||
static void platform_init();
|
||||
static void platform_exit();
|
||||
|
||||
|
|
|
@ -201,15 +201,28 @@ void VKCommandBuffer::copy(VKTexture &dst_texture,
|
|||
}
|
||||
|
||||
void VKCommandBuffer::blit(VKTexture &dst_texture,
|
||||
VKTexture &src_buffer,
|
||||
VKTexture &src_texture,
|
||||
Span<VkImageBlit> regions)
|
||||
{
|
||||
blit(dst_texture,
|
||||
dst_texture.current_layout_get(),
|
||||
src_texture,
|
||||
src_texture.current_layout_get(),
|
||||
regions);
|
||||
}
|
||||
|
||||
void VKCommandBuffer::blit(VKTexture &dst_texture,
|
||||
VkImageLayout dst_layout,
|
||||
VKTexture &src_texture,
|
||||
VkImageLayout src_layout,
|
||||
Span<VkImageBlit> regions)
|
||||
{
|
||||
ensure_no_active_framebuffer();
|
||||
vkCmdBlitImage(vk_command_buffer_,
|
||||
src_buffer.vk_image_handle(),
|
||||
src_buffer.current_layout_get(),
|
||||
src_texture.vk_image_handle(),
|
||||
src_layout,
|
||||
dst_texture.vk_image_handle(),
|
||||
dst_texture.current_layout_get(),
|
||||
dst_layout,
|
||||
regions.size(),
|
||||
regions.data(),
|
||||
VK_FILTER_NEAREST);
|
||||
|
|
|
@ -165,6 +165,11 @@ class VKCommandBuffer : NonCopyable, NonMovable {
|
|||
void copy(VKTexture &dst_texture, VKBuffer &src_buffer, Span<VkBufferImageCopy> regions);
|
||||
void copy(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageCopy> regions);
|
||||
void blit(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageBlit> regions);
|
||||
void blit(VKTexture &dst_texture,
|
||||
VkImageLayout dst_layout,
|
||||
VKTexture &src_texture,
|
||||
VkImageLayout src_layout,
|
||||
Span<VkImageBlit> regions);
|
||||
void pipeline_barrier(VkPipelineStageFlags source_stages,
|
||||
VkPipelineStageFlags destination_stages);
|
||||
void pipeline_barrier(Span<VkImageMemoryBarrier> image_memory_barriers);
|
||||
|
|
|
@ -32,6 +32,9 @@ enum class ConversionType {
|
|||
FLOAT_TO_SNORM16,
|
||||
SNORM16_TO_FLOAT,
|
||||
|
||||
FLOAT_TO_UNORM32,
|
||||
UNORM32_TO_FLOAT,
|
||||
|
||||
UI32_TO_UI16,
|
||||
UI16_TO_UI32,
|
||||
|
||||
|
@ -239,6 +242,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
|
|||
case GPU_RGBA32UI:
|
||||
case GPU_RG32UI:
|
||||
case GPU_R32UI:
|
||||
case GPU_DEPTH_COMPONENT24:
|
||||
return ConversionType::PASS_THROUGH;
|
||||
|
||||
case GPU_RGBA16UI:
|
||||
|
@ -252,6 +256,10 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
|
|||
case GPU_R8UI:
|
||||
return ConversionType::UI32_TO_UI8;
|
||||
|
||||
case GPU_DEPTH_COMPONENT32F:
|
||||
case GPU_DEPTH32F_STENCIL8:
|
||||
return ConversionType::UNORM32_TO_FLOAT;
|
||||
|
||||
case GPU_RGBA8I:
|
||||
case GPU_RGBA8:
|
||||
case GPU_RGBA16I:
|
||||
|
@ -276,7 +284,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
|
|||
case GPU_RGB10_A2:
|
||||
case GPU_RGB10_A2UI:
|
||||
case GPU_R11F_G11F_B10F:
|
||||
case GPU_DEPTH32F_STENCIL8:
|
||||
case GPU_DEPTH24_STENCIL8:
|
||||
case GPU_SRGB8_A8:
|
||||
case GPU_RGBA8_SNORM:
|
||||
|
@ -304,8 +311,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
|
|||
case GPU_RGBA8_DXT5:
|
||||
case GPU_SRGB8:
|
||||
case GPU_RGB9_E5:
|
||||
case GPU_DEPTH_COMPONENT32F:
|
||||
case GPU_DEPTH_COMPONENT24:
|
||||
case GPU_DEPTH_COMPONENT16:
|
||||
return ConversionType::UNSUPPORTED;
|
||||
}
|
||||
|
@ -396,6 +401,7 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format)
|
|||
case GPU_RG8:
|
||||
case GPU_R8UI:
|
||||
case GPU_R8:
|
||||
case GPU_SRGB8_A8:
|
||||
return ConversionType::PASS_THROUGH;
|
||||
|
||||
case GPU_RGBA8I:
|
||||
|
@ -427,7 +433,6 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format)
|
|||
case GPU_R11F_G11F_B10F:
|
||||
case GPU_DEPTH32F_STENCIL8:
|
||||
case GPU_DEPTH24_STENCIL8:
|
||||
case GPU_SRGB8_A8:
|
||||
case GPU_RGBA8_SNORM:
|
||||
case GPU_RGBA16_SNORM:
|
||||
case GPU_RGB8UI:
|
||||
|
@ -523,6 +528,7 @@ static ConversionType reversed(ConversionType type)
|
|||
CASE_PAIR(FLOAT, SNORM8)
|
||||
CASE_PAIR(FLOAT, UNORM16)
|
||||
CASE_PAIR(FLOAT, SNORM16)
|
||||
CASE_PAIR(FLOAT, UNORM32)
|
||||
CASE_PAIR(UI32, UI16)
|
||||
CASE_PAIR(I32, I16)
|
||||
CASE_PAIR(UI32, UI8)
|
||||
|
@ -632,6 +638,7 @@ template<typename InnerType> struct SignedNormalized {
|
|||
|
||||
template<typename InnerType> struct UnsignedNormalized {
|
||||
static_assert(std::is_same<InnerType, uint8_t>() || std::is_same<InnerType, uint16_t>() ||
|
||||
std::is_same<InnerType, uint32_t>() ||
|
||||
std::is_same<InnerType, DepthComponent24>());
|
||||
InnerType value;
|
||||
|
||||
|
@ -645,15 +652,24 @@ template<typename InnerType> struct UnsignedNormalized {
|
|||
}
|
||||
}
|
||||
|
||||
static constexpr int32_t scalar()
|
||||
static constexpr uint32_t scalar()
|
||||
{
|
||||
|
||||
return (1 << (used_byte_size() * 8)) - 1;
|
||||
if constexpr (std::is_same<InnerType, DepthComponent24>()) {
|
||||
return (1 << (used_byte_size() * 8)) - 1;
|
||||
}
|
||||
else {
|
||||
return std::numeric_limits<InnerType>::max();
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int32_t max()
|
||||
static constexpr uint32_t max()
|
||||
{
|
||||
return ((1 << (used_byte_size() * 8)) - 1);
|
||||
if constexpr (std::is_same<InnerType, DepthComponent24>()) {
|
||||
return (1 << (used_byte_size() * 8)) - 1;
|
||||
}
|
||||
else {
|
||||
return std::numeric_limits<InnerType>::max();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -674,15 +690,15 @@ template<typename StorageType> void convert(F32 &dst, const SignedNormalized<Sto
|
|||
|
||||
template<typename StorageType> void convert(UnsignedNormalized<StorageType> &dst, const F32 &src)
|
||||
{
|
||||
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
static constexpr int32_t max = scalar;
|
||||
dst.value = (clamp_i((src.value * scalar), 0, max));
|
||||
static constexpr uint32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
static constexpr uint32_t max = scalar;
|
||||
dst.value = (clamp_f((src.value * scalar), 0, max));
|
||||
}
|
||||
|
||||
template<typename StorageType> void convert(F32 &dst, const UnsignedNormalized<StorageType> &src)
|
||||
{
|
||||
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
dst.value = float(int32_t(src.value)) / scalar;
|
||||
static constexpr uint32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
dst.value = float(uint32_t(src.value)) / scalar;
|
||||
}
|
||||
|
||||
/* Copy the contents of src to dst with out performing any actual conversion. */
|
||||
|
@ -860,6 +876,15 @@ static void convert_buffer(void *dst_memory,
|
|||
dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
|
||||
case ConversionType::FLOAT_TO_UNORM32:
|
||||
convert_per_component<UnsignedNormalized<uint32_t>, F32>(
|
||||
dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
case ConversionType::UNORM32_TO_FLOAT:
|
||||
convert_per_component<F32, UnsignedNormalized<uint32_t>>(
|
||||
dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
|
||||
case ConversionType::FLOAT_TO_HALF:
|
||||
convert_per_component<F16, F32>(dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
#include "vk_descriptor_pools.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKBackend;
|
||||
|
||||
struct VKWorkarounds {
|
||||
/**
|
||||
* Some devices don't support pixel formats that are aligned to 24 and 48 bits.
|
||||
* In this case we need to use a different texture format.
|
||||
*
|
||||
* If set to true we should work around this issue by using a different texture format.
|
||||
*/
|
||||
bool not_aligned_pixel_formats = false;
|
||||
};
|
||||
|
||||
class VKDevice : public NonCopyable {
|
||||
private:
|
||||
|
@ -35,6 +46,9 @@ class VKDevice : public NonCopyable {
|
|||
/** Functions of vk_ext_debugutils for this device/instance. */
|
||||
debug::VKDebuggingTools debugging_tools_;
|
||||
|
||||
/* Workarounds */
|
||||
VKWorkarounds workarounds_;
|
||||
|
||||
public:
|
||||
VkPhysicalDevice physical_device_get() const
|
||||
{
|
||||
|
@ -95,11 +109,19 @@ class VKDevice : public NonCopyable {
|
|||
std::string vendor_name() const;
|
||||
std::string driver_version() const;
|
||||
|
||||
const VKWorkarounds &workarounds_get() const
|
||||
{
|
||||
return workarounds_;
|
||||
}
|
||||
|
||||
private:
|
||||
void init_physical_device_properties();
|
||||
void init_debug_callbacks();
|
||||
void init_memory_allocator();
|
||||
void init_descriptor_pools();
|
||||
|
||||
/* During initialization the backend requires access to update the workarounds. */
|
||||
friend VKBackend;
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -914,6 +914,7 @@ bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
|
|||
{
|
||||
return false;
|
||||
};
|
||||
debug::object_label(layout_, name_get());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ void VKStateManager::image_unbind(Texture *tex)
|
|||
|
||||
void VKStateManager::image_unbind_all()
|
||||
{
|
||||
for (TextureBinding &binding : texture_bindings_) {
|
||||
for (ImageBinding &binding : image_bindings_) {
|
||||
binding.texture = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,56 @@ void VKTexture::init(VkImage vk_image, VkImageLayout layout)
|
|||
|
||||
void VKTexture::generate_mipmap()
|
||||
{
|
||||
NOT_YET_IMPLEMENTED
|
||||
if (mipmaps_ <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensure_allocated();
|
||||
|
||||
VKContext &context = *VKContext::get();
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
for (int src_mipmap : IndexRange(mipmaps_ - 1)) {
|
||||
int dst_mipmap = src_mipmap + 1;
|
||||
int3 src_size(1);
|
||||
int3 dst_size(1);
|
||||
mip_size_get(src_mipmap, src_size);
|
||||
mip_size_get(dst_mipmap, dst_size);
|
||||
|
||||
layout_ensure(context,
|
||||
IndexRange(src_mipmap, 1),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
VkImageBlit image_blit = {};
|
||||
image_blit.srcOffsets[0] = {0, 0, 0};
|
||||
image_blit.srcOffsets[1] = {src_size.x, src_size.y, src_size.z};
|
||||
image_blit.srcSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
image_blit.srcSubresource.mipLevel = src_mipmap;
|
||||
image_blit.srcSubresource.baseArrayLayer = 0;
|
||||
image_blit.srcSubresource.layerCount = layer_count();
|
||||
|
||||
image_blit.dstOffsets[0] = {0, 0, 0};
|
||||
image_blit.dstOffsets[1] = {dst_size.x, dst_size.y, dst_size.z};
|
||||
image_blit.dstSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
image_blit.dstSubresource.mipLevel = dst_mipmap;
|
||||
image_blit.dstSubresource.baseArrayLayer = 0;
|
||||
image_blit.dstSubresource.layerCount = layer_count();
|
||||
|
||||
command_buffer.blit(*this,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
*this,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
Span<VkImageBlit>(&image_blit, 1));
|
||||
}
|
||||
/* Ensure that all mipmap levels are in `VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL`. All miplevels are
|
||||
* except the last one. */
|
||||
layout_ensure(context,
|
||||
IndexRange(mipmaps_ - 1, 1),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
current_layout_set(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
}
|
||||
|
||||
void VKTexture::copy_to(Texture *tex)
|
||||
|
@ -151,10 +200,6 @@ void *VKTexture::read(int mip, eGPUDataFormat format)
|
|||
void VKTexture::update_sub(
|
||||
int mip, int offset[3], int extent_[3], eGPUDataFormat format, const void *data)
|
||||
{
|
||||
if (mip != 0) {
|
||||
NOT_YET_IMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
if (!is_allocated()) {
|
||||
allocate();
|
||||
}
|
||||
|
@ -220,6 +265,15 @@ bool VKTexture::init_internal()
|
|||
* at this moment, so we cannot initialize here. The initialization is postponed until the
|
||||
* allocation of the texture on the device. */
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
const VKWorkarounds &workarounds = device.workarounds_get();
|
||||
if (format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
|
||||
format_ = GPU_DEPTH_COMPONENT32F;
|
||||
}
|
||||
if (format_ == GPU_DEPTH24_STENCIL8 && workarounds.not_aligned_pixel_formats) {
|
||||
format_ = GPU_DEPTH32F_STENCIL8;
|
||||
}
|
||||
|
||||
/* TODO: return false when texture format isn't supported. */
|
||||
return true;
|
||||
}
|
||||
|
@ -330,7 +384,7 @@ bool VKTexture::allocate()
|
|||
image_info.extent.width = extent[0];
|
||||
image_info.extent.height = extent[1];
|
||||
image_info.extent.depth = extent[2];
|
||||
image_info.mipLevels = 1;
|
||||
image_info.mipLevels = max_ii(mipmaps_, 1);
|
||||
image_info.arrayLayers = 1;
|
||||
image_info.format = to_vk_format(format_);
|
||||
/* Some platforms (NVIDIA) requires that attached textures are always tiled optimal.
|
||||
|
@ -449,16 +503,27 @@ void VKTexture::layout_ensure(VKContext &context, const VkImageLayout requested_
|
|||
if (current_layout == requested_layout) {
|
||||
return;
|
||||
}
|
||||
layout_ensure(context, IndexRange(0, VK_REMAINING_MIP_LEVELS), current_layout, requested_layout);
|
||||
current_layout_set(requested_layout);
|
||||
}
|
||||
|
||||
void VKTexture::layout_ensure(VKContext &context,
|
||||
const IndexRange mipmap_range,
|
||||
const VkImageLayout current_layout,
|
||||
const VkImageLayout requested_layout)
|
||||
{
|
||||
BLI_assert(is_allocated());
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = current_layout;
|
||||
barrier.newLayout = requested_layout;
|
||||
barrier.image = vk_image_;
|
||||
barrier.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
barrier.subresourceRange.baseMipLevel = uint32_t(mipmap_range.start());
|
||||
barrier.subresourceRange.levelCount = uint32_t(mipmap_range.size());
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
context.command_buffer_get().pipeline_barrier(Span<VkImageMemoryBarrier>(&barrier, 1));
|
||||
current_layout_set(requested_layout);
|
||||
}
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -111,6 +111,17 @@ class VKTexture : public Texture {
|
|||
*/
|
||||
void layout_ensure(VKContext &context, VkImageLayout requested_layout);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Internal function to ensure the layout of a single mipmap level. Note that the caller is
|
||||
* responsible to update the current_layout of the image at the end of the operation and make
|
||||
* sure that all mipmap levels are in that given layout.
|
||||
*/
|
||||
void layout_ensure(VKContext &context,
|
||||
IndexRange mipmap_range,
|
||||
VkImageLayout current_layout,
|
||||
VkImageLayout requested_layout);
|
||||
|
||||
/** \} */
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKUniformBuffer::~VKUniformBuffer()
|
||||
{
|
||||
unbind();
|
||||
}
|
||||
|
||||
void VKUniformBuffer::update(const void *data)
|
||||
{
|
||||
if (!buffer_.is_allocated()) {
|
||||
|
@ -68,8 +73,10 @@ void VKUniformBuffer::bind_as_ssbo(int slot)
|
|||
|
||||
void VKUniformBuffer::unbind()
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
context.state_manager_get().uniform_buffer_unbind(this);
|
||||
VKContext *context = VKContext::get();
|
||||
if (context) {
|
||||
context->state_manager_get().uniform_buffer_unbind(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -21,6 +21,7 @@ class VKUniformBuffer : public UniformBuf, NonCopyable {
|
|||
|
||||
public:
|
||||
VKUniformBuffer(int size, const char *name) : UniformBuf(size, name) {}
|
||||
~VKUniformBuffer();
|
||||
|
||||
void update(const void *data) override;
|
||||
void clear_to_zero() override;
|
||||
|
|
|
@ -119,9 +119,9 @@ void VKVertexBuffer::resize_data()
|
|||
|
||||
void VKVertexBuffer::release_data()
|
||||
{
|
||||
if (should_unbind_) {
|
||||
VKContext &context = *VKContext::get();
|
||||
context.state_manager_get().texel_buffer_unbind(this);
|
||||
VKContext *context = VKContext::get();
|
||||
if (should_unbind_ && context) {
|
||||
context->state_manager_get().texel_buffer_unbind(this);
|
||||
}
|
||||
|
||||
if (vk_buffer_view_ != VK_NULL_HANDLE) {
|
||||
|
|
|
@ -453,9 +453,9 @@ typedef struct GreasePencil {
|
|||
void remove_drawing(int index);
|
||||
|
||||
void foreach_visible_drawing(int frame,
|
||||
blender::FunctionRef<void(GreasePencilDrawing &)> function);
|
||||
blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
|
||||
void foreach_editable_drawing(int frame,
|
||||
blender::FunctionRef<void(GreasePencilDrawing &)> function);
|
||||
blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
|
||||
|
||||
bool bounds_min_max(blender::float3 &min, blender::float3 &max) const;
|
||||
|
||||
|
|
|
@ -725,6 +725,38 @@ static void rna_ID_asset_clear(ID *id)
|
|||
}
|
||||
}
|
||||
|
||||
static void rna_ID_asset_data_set(PointerRNA *ptr, PointerRNA value, struct ReportList *reports)
|
||||
{
|
||||
ID *destination = ptr->data;
|
||||
|
||||
/* Avoid marking as asset by assigning. This should be done wiht .asset_mark(). This is just for
|
||||
* clarity of the API, and to accomodate future changes. */
|
||||
if (destination->asset_data == NULL) {
|
||||
BKE_report(reports,
|
||||
RPT_ERROR,
|
||||
"Asset data can only be assigned to assets. Use asset_mark() to mark as an asset");
|
||||
return;
|
||||
}
|
||||
|
||||
const AssetMetaData *asset_data = value.data;
|
||||
if (asset_data == NULL) {
|
||||
/* Avoid clearing the asset data on assets. Un-marking as asset should be done with
|
||||
* .asset_clear(). This is just for clarity of the API, and to accomodate future changes. */
|
||||
BKE_report(reports, RPT_ERROR, "Asset data cannot be None");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool assigned_ok = ED_asset_copy_to_id(asset_data, destination);
|
||||
if (!assigned_ok) {
|
||||
BKE_reportf(
|
||||
reports, RPT_ERROR, "'%s' is of a type that cannot be an asset", destination->name + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_ASSET | NA_EDITED, NULL);
|
||||
WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
|
||||
{
|
||||
if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
|
||||
|
@ -2131,7 +2163,8 @@ static void rna_def_ID(BlenderRNA *brna)
|
|||
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
|
||||
|
||||
prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_funcs(prop, NULL, "rna_ID_asset_data_set", NULL, NULL);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
|
||||
RNA_def_property_ui_text(prop, "Asset Data", "Additional data for an asset data-block");
|
||||
|
||||
|
|
|
@ -1637,6 +1637,7 @@ void RNA_api_ui_layout(StructRNA *srna)
|
|||
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_boolean(func, "color_management", false, "", "Show color management settings");
|
||||
RNA_def_boolean(func, "show_z_buffer", true, "", "Show option to save z-buffer");
|
||||
|
||||
func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d");
|
||||
RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options");
|
||||
|
|
|
@ -305,9 +305,11 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
|
|||
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
|
||||
const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
|
||||
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
|
||||
/* Unclear where to get z-information from, so deactivate it. */
|
||||
const bool show_z_buffer = false;
|
||||
|
||||
node_composit_buts_file_output(layout, C, ptr);
|
||||
uiTemplateImageSettings(layout, &imfptr, true);
|
||||
uiTemplateImageSettings(layout, &imfptr, true, show_z_buffer);
|
||||
|
||||
/* disable stereo output for multilayer, too much work for something that no one will use */
|
||||
/* if someone asks for that we can implement it */
|
||||
|
@ -430,7 +432,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
|
|||
const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render");
|
||||
|
||||
col = uiLayoutColumn(layout, false);
|
||||
uiTemplateImageSettings(col, &imfptr, use_color_management);
|
||||
uiTemplateImageSettings(col, &imfptr, use_color_management, show_z_buffer);
|
||||
|
||||
if (is_multiview) {
|
||||
col = uiLayoutColumn(layout, false);
|
||||
|
|
Loading…
Reference in New Issue