The goal is to solve confusion of the "All rights reserved" for licensing
code under an open-source license.
The phrase "All rights reserved" comes from a historical convention that
required this phrase for the copyright protection to apply. This convention
is no longer relevant.
However, even though the phrase has no meaning in establishing the copyright
it has not lost meaning in terms of licensing.
This change makes it so code under the Blender Foundation copyright does
not use "all rights reserved". This is also how the GPL license itself
states how to apply it to the source code:
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software ...
This change does not change copyright notice in cases when the copyright
is dual (BF and an author), or just an author of the code. It also does
mot change copyright which is inherited from NaN Holding BV as it needs
some further investigation about what is the proper way to handle it.
723 lines
19 KiB
C
723 lines
19 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2018 Blender Foundation */
|
|
|
|
/** \file
|
|
* \ingroup edobj
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_gpencil_legacy_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_shader_fx_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_string.h"
|
|
#include "BLI_string_utf8.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BLT_translation.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_lib_id.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_report.h"
|
|
#include "BKE_shader_fx.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
#include "DEG_depsgraph_build.h"
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_define.h"
|
|
#include "RNA_enum_types.h"
|
|
#include "RNA_prototypes.h"
|
|
|
|
#include "ED_object.h"
|
|
#include "ED_screen.h"
|
|
|
|
#include "UI_interface.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "object_intern.h"
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Public API
|
|
* \{ */
|
|
|
|
ShaderFxData *ED_object_shaderfx_add(
|
|
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
|
|
{
|
|
ShaderFxData *new_fx = NULL;
|
|
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
|
|
|
|
if (ob->type != OB_GPENCIL_LEGACY) {
|
|
BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
|
|
return NULL;
|
|
}
|
|
|
|
if (fxi->flags & eShaderFxTypeFlag_Single) {
|
|
if (BKE_shaderfx_findby_type(ob, type)) {
|
|
BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* get new effect data to add */
|
|
new_fx = BKE_shaderfx_new(type);
|
|
|
|
BLI_addtail(&ob->shader_fx, new_fx);
|
|
|
|
if (name) {
|
|
BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name));
|
|
}
|
|
|
|
/* make sure effect data has unique name */
|
|
BKE_shaderfx_unique_name(&ob->shader_fx, new_fx);
|
|
|
|
bGPdata *gpd = ob->data;
|
|
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
DEG_relations_tag_update(bmain);
|
|
|
|
return new_fx;
|
|
}
|
|
|
|
/* Return true if the object has a effect of type 'type' other than
|
|
* the shaderfx pointed to be 'exclude', otherwise returns false. */
|
|
static bool UNUSED_FUNCTION(object_has_shaderfx)(const Object *ob,
|
|
const ShaderFxData *exclude,
|
|
ShaderFxType type)
|
|
{
|
|
ShaderFxData *fx;
|
|
|
|
for (fx = ob->shader_fx.first; fx; fx = fx->next) {
|
|
if ((fx != exclude) && (fx->type == type)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool object_shaderfx_remove(Main *bmain,
|
|
Object *ob,
|
|
ShaderFxData *fx,
|
|
bool *UNUSED(r_sort_depsgraph))
|
|
{
|
|
/* It seems on rapid delete it is possible to
|
|
* get called twice on same effect, so make
|
|
* sure it is in list. */
|
|
if (BLI_findindex(&ob->shader_fx, fx) == -1) {
|
|
return 0;
|
|
}
|
|
|
|
DEG_relations_tag_update(bmain);
|
|
|
|
BLI_remlink(&ob->shader_fx, fx);
|
|
BKE_shaderfx_free(fx);
|
|
BKE_object_free_derived_caches(ob);
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx)
|
|
{
|
|
bool sort_depsgraph = false;
|
|
bool ok;
|
|
|
|
ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
|
|
|
|
if (!ok) {
|
|
BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name);
|
|
return 0;
|
|
}
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
DEG_relations_tag_update(bmain);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void ED_object_shaderfx_clear(Main *bmain, Object *ob)
|
|
{
|
|
ShaderFxData *fx = ob->shader_fx.first;
|
|
bool sort_depsgraph = false;
|
|
|
|
if (!fx) {
|
|
return;
|
|
}
|
|
|
|
while (fx) {
|
|
ShaderFxData *next_fx;
|
|
|
|
next_fx = fx->next;
|
|
|
|
object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
|
|
|
|
fx = next_fx;
|
|
}
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
DEG_relations_tag_update(bmain);
|
|
}
|
|
|
|
int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
|
|
{
|
|
if (fx->prev) {
|
|
BLI_remlink(&ob->shader_fx, fx);
|
|
BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
|
|
{
|
|
if (fx->next) {
|
|
BLI_remlink(&ob->shader_fx, fx);
|
|
BLI_insertlinkafter(&ob->shader_fx, fx->next, fx);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool ED_object_shaderfx_move_to_index(ReportList *reports,
|
|
Object *ob,
|
|
ShaderFxData *fx,
|
|
const int index)
|
|
{
|
|
BLI_assert(fx != NULL);
|
|
BLI_assert(index >= 0);
|
|
if (index >= BLI_listbase_count(&ob->shader_fx)) {
|
|
BKE_report(reports, RPT_WARNING, "Cannot move effect beyond the end of the stack");
|
|
return false;
|
|
}
|
|
|
|
int fx_index = BLI_findindex(&ob->shader_fx, fx);
|
|
BLI_assert(fx_index != -1);
|
|
if (fx_index < index) {
|
|
/* Move shaderfx down in list. */
|
|
for (; fx_index < index; fx_index++) {
|
|
if (!ED_object_shaderfx_move_down(reports, ob, fx)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Move shaderfx up in list. */
|
|
for (; fx_index > index; fx_index--) {
|
|
if (!ED_object_shaderfx_move_up(reports, ob, fx)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ED_object_shaderfx_link(Object *dst, Object *src)
|
|
{
|
|
BLI_freelistN(&dst->shader_fx);
|
|
BKE_shaderfx_copy(&dst->shader_fx, &src->shader_fx);
|
|
|
|
DEG_id_tag_update(&dst->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, dst);
|
|
}
|
|
|
|
void ED_object_shaderfx_copy(Object *dst, ShaderFxData *fx)
|
|
{
|
|
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
|
|
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
|
|
BKE_shaderfx_copydata(fx, nfx);
|
|
BLI_addtail(&dst->shader_fx, nfx);
|
|
|
|
DEG_id_tag_update(&dst->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, dst);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Generic Poll Callback Helpers
|
|
* \{ */
|
|
|
|
static bool edit_shaderfx_poll_generic(bContext *C,
|
|
StructRNA *rna_type,
|
|
int obtype_flag,
|
|
const bool is_liboverride_allowed)
|
|
{
|
|
PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
|
|
Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
|
|
ShaderFxData *fx = ptr.data; /* May be NULL. */
|
|
|
|
if (!ED_operator_object_active_editable_ex(C, ob)) {
|
|
return false;
|
|
}
|
|
|
|
/* NOTE: Temporary 'forbid all' for overrides, until we implement support to add shaderfx to
|
|
* overrides. */
|
|
if (ID_IS_OVERRIDE_LIBRARY(ob)) {
|
|
CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs in a library override");
|
|
return false;
|
|
}
|
|
|
|
if (obtype_flag != 0 && ((1 << ob->type) & obtype_flag) == 0) {
|
|
CTX_wm_operator_poll_msg_set(C, "Object type is not supported");
|
|
return false;
|
|
}
|
|
if (ptr.owner_id != NULL && !BKE_id_is_editable(CTX_data_main(C), ptr.owner_id)) {
|
|
CTX_wm_operator_poll_msg_set(C, "Cannot edit library or override data");
|
|
return false;
|
|
}
|
|
if (!is_liboverride_allowed && BKE_shaderfx_is_nonlocal_in_liboverride(ob, fx)) {
|
|
CTX_wm_operator_poll_msg_set(
|
|
C, "Cannot edit shaderfxs coming from linked data in a library override");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool edit_shaderfx_poll(bContext *C)
|
|
{
|
|
return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0, false);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Add Effect Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_add_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Main *bmain = CTX_data_main(C);
|
|
Scene *scene = CTX_data_scene(C);
|
|
Object *ob = ED_object_active_context(C);
|
|
int type = RNA_enum_get(op->ptr, "type");
|
|
|
|
if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type)) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static const EnumPropertyItem *shaderfx_add_itemf(bContext *C,
|
|
PointerRNA *UNUSED(ptr),
|
|
PropertyRNA *UNUSED(prop),
|
|
bool *r_free)
|
|
{
|
|
Object *ob = ED_object_active_context(C);
|
|
EnumPropertyItem *item = NULL;
|
|
const EnumPropertyItem *fx_item, *group_item = NULL;
|
|
const ShaderFxTypeInfo *mti;
|
|
int totitem = 0, a;
|
|
|
|
if (!ob) {
|
|
return rna_enum_object_shaderfx_type_items;
|
|
}
|
|
|
|
for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
|
|
fx_item = &rna_enum_object_shaderfx_type_items[a];
|
|
if (fx_item->identifier[0]) {
|
|
mti = BKE_shaderfx_get_info(fx_item->value);
|
|
|
|
if (mti->flags & eShaderFxTypeFlag_NoUserAdd) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
group_item = fx_item;
|
|
fx_item = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (group_item) {
|
|
RNA_enum_item_add(&item, &totitem, group_item);
|
|
group_item = NULL;
|
|
}
|
|
|
|
RNA_enum_item_add(&item, &totitem, fx_item);
|
|
}
|
|
|
|
RNA_enum_item_end(&item, &totitem);
|
|
*r_free = true;
|
|
|
|
return item;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Add Effect";
|
|
ot->description = "Add a visual effect to the active object";
|
|
ot->idname = "OBJECT_OT_shaderfx_add";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = WM_menu_invoke;
|
|
ot->exec = shaderfx_add_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
/* properties */
|
|
ot->prop = RNA_def_enum(
|
|
ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", "");
|
|
RNA_def_enum_funcs(ot->prop, shaderfx_add_itemf);
|
|
|
|
/* Abused, for "Light"... */
|
|
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ID);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Generic Functions for Operators Using Names and Data Context
|
|
* \{ */
|
|
|
|
static void edit_shaderfx_properties(wmOperatorType *ot)
|
|
{
|
|
PropertyRNA *prop = RNA_def_string(
|
|
ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit");
|
|
RNA_def_property_flag(prop, PROP_HIDDEN);
|
|
}
|
|
|
|
static void edit_shaderfx_report_property(wmOperatorType *ot)
|
|
{
|
|
PropertyRNA *prop = RNA_def_boolean(
|
|
ot->srna, "report", false, "Report", "Create a notification after the operation");
|
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
|
}
|
|
|
|
/**
|
|
* \param event: If this isn't NULL, the operator will also look for panels underneath
|
|
* the cursor with custom-data set to a modifier.
|
|
* \param r_retval: This should be used if #event is used in order to return
|
|
* #OPERATOR_PASS_THROUGH to check other operators with the same key set.
|
|
*/
|
|
static bool edit_shaderfx_invoke_properties(bContext *C,
|
|
wmOperator *op,
|
|
const wmEvent *event,
|
|
int *r_retval)
|
|
{
|
|
if (RNA_struct_property_is_set(op->ptr, "shaderfx")) {
|
|
return true;
|
|
}
|
|
|
|
PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
|
|
if (ctx_ptr.data != NULL) {
|
|
ShaderFxData *fx = ctx_ptr.data;
|
|
RNA_string_set(op->ptr, "shaderfx", fx->name);
|
|
return true;
|
|
}
|
|
|
|
/* Check the custom data of panels under the mouse for an effect. */
|
|
if (event != NULL) {
|
|
PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event);
|
|
|
|
if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) {
|
|
if (RNA_struct_is_a(panel_ptr->type, &RNA_ShaderFx)) {
|
|
ShaderFxData *fx = panel_ptr->data;
|
|
RNA_string_set(op->ptr, "shaderfx", fx->name);
|
|
return true;
|
|
}
|
|
|
|
BLI_assert(r_retval != NULL); /* We need the return value in this case. */
|
|
if (r_retval != NULL) {
|
|
*r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (r_retval != NULL) {
|
|
*r_retval = OPERATOR_CANCELLED;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type)
|
|
{
|
|
char shaderfx_name[MAX_NAME];
|
|
ShaderFxData *fx;
|
|
RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
|
|
|
|
fx = BKE_shaderfx_findby_name(ob, shaderfx_name);
|
|
|
|
if (fx && type != 0 && fx->type != type) {
|
|
fx = NULL;
|
|
}
|
|
|
|
return fx;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Remove ShaderFX Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_remove_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Main *bmain = CTX_data_main(C);
|
|
Object *ob = ED_object_active_context(C);
|
|
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
|
|
if (!fx) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
/* Store name temporarily for report. */
|
|
char name[MAX_NAME];
|
|
strcpy(name, fx->name);
|
|
|
|
if (!ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
if (RNA_boolean_get(op->ptr, "report")) {
|
|
BKE_reportf(op->reports, RPT_INFO, "Removed effect: %s", name);
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int retval;
|
|
if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
|
|
return shaderfx_remove_exec(C, op);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
|
|
{
|
|
ot->name = "Remove Grease Pencil Effect";
|
|
ot->description = "Remove a effect from the active grease pencil object";
|
|
ot->idname = "OBJECT_OT_shaderfx_remove";
|
|
|
|
ot->invoke = shaderfx_remove_invoke;
|
|
ot->exec = shaderfx_remove_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
edit_shaderfx_properties(ot);
|
|
edit_shaderfx_report_property(ot);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Move up ShaderFX Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Object *ob = ED_object_active_context(C);
|
|
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
|
|
|
|
if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int retval;
|
|
if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
|
|
return shaderfx_move_up_exec(C, op);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
|
|
{
|
|
ot->name = "Move Up Effect";
|
|
ot->description = "Move effect up in the stack";
|
|
ot->idname = "OBJECT_OT_shaderfx_move_up";
|
|
|
|
ot->invoke = shaderfx_move_up_invoke;
|
|
ot->exec = shaderfx_move_up_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
edit_shaderfx_properties(ot);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Move Down ShaderFX Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Object *ob = ED_object_active_context(C);
|
|
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
|
|
|
|
if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int retval;
|
|
if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
|
|
return shaderfx_move_down_exec(C, op);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
|
|
{
|
|
ot->name = "Move Down Effect";
|
|
ot->description = "Move effect down in the stack";
|
|
ot->idname = "OBJECT_OT_shaderfx_move_down";
|
|
|
|
ot->invoke = shaderfx_move_down_invoke;
|
|
ot->exec = shaderfx_move_down_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
edit_shaderfx_properties(ot);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Move ShaderFX to Index Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_move_to_index_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Object *ob = ED_object_active_context(C);
|
|
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
|
|
int index = RNA_int_get(op->ptr, "index");
|
|
|
|
if (!fx || !ED_object_shaderfx_move_to_index(op->reports, ob, fx, index)) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int shaderfx_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int retval;
|
|
if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
|
|
return shaderfx_move_to_index_exec(C, op);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot)
|
|
{
|
|
ot->name = "Move Effect to Index";
|
|
ot->idname = "OBJECT_OT_shaderfx_move_to_index";
|
|
ot->description =
|
|
"Change the effect's position in the list so it evaluates after the set number of "
|
|
"others";
|
|
|
|
ot->invoke = shaderfx_move_to_index_invoke;
|
|
ot->exec = shaderfx_move_to_index_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
edit_shaderfx_properties(ot);
|
|
RNA_def_int(
|
|
ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Copy Shader Operator
|
|
* \{ */
|
|
|
|
static int shaderfx_copy_exec(bContext *C, wmOperator *op)
|
|
{
|
|
Object *ob = ED_object_active_context(C);
|
|
ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
|
|
if (!fx) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
|
|
if (!nfx) {
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
|
|
/* Make sure effect data has unique name. */
|
|
BKE_shaderfx_unique_name(&ob->shader_fx, nfx);
|
|
|
|
BKE_shaderfx_copydata(fx, nfx);
|
|
BLI_insertlinkafter(&ob->shader_fx, fx, nfx);
|
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
|
WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, ob);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int shaderfx_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
{
|
|
int retval;
|
|
if (edit_shaderfx_invoke_properties(C, op, event, &retval)) {
|
|
return shaderfx_copy_exec(C, op);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void OBJECT_OT_shaderfx_copy(wmOperatorType *ot)
|
|
{
|
|
ot->name = "Copy Effect";
|
|
ot->description = "Duplicate effect at the same position in the stack";
|
|
ot->idname = "OBJECT_OT_shaderfx_copy";
|
|
|
|
ot->invoke = shaderfx_copy_invoke;
|
|
ot->exec = shaderfx_copy_exec;
|
|
ot->poll = edit_shaderfx_poll;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
edit_shaderfx_properties(ot);
|
|
}
|
|
|
|
/** \} */
|