Initial Grease Pencil 3.0 stage #106848
|
@ -28,6 +28,9 @@ void legacy_gpencil_to_grease_pencil(bGPdata &gpd, GreasePencil &grease_pencil);
|
|||
|
||||
} // namespace blender::bke
|
||||
|
||||
void *BKE_grease_pencil_add(Main *bmain, const char *name);
|
||||
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob);
|
||||
|
||||
inline const blender::Map<int, int> &GreasePencilLayer::frames() const
|
||||
{
|
||||
return this->runtime->frames;
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "BKE_idtype.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
|
@ -25,6 +27,7 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
using blender::Vector;
|
||||
|
||||
|
@ -216,6 +219,54 @@ IDTypeInfo IDType_ID_GP = {
|
|||
/*lib_override_apply_post*/ nullptr,
|
||||
};
|
||||
|
||||
|
||||
void *BKE_grease_pencil_add(Main *bmain, const char *name)
|
||||
{
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(BKE_id_new(bmain, ID_GP, name));
|
||||
|
||||
return grease_pencil;
|
||||
}
|
||||
|
||||
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob)
|
||||
{
|
||||
BLI_assert(ob->type == OB_CURVES);
|
||||
const GreasePencil *grease_pencil = static_cast<const GreasePencil *>(ob->data);
|
||||
|
||||
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
|
||||
float3 min(FLT_MAX);
|
||||
float3 max(-FLT_MAX);
|
||||
|
||||
for (int i = 0; i < grease_pencil->drawing_array_size; i++) {
|
||||
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil->drawing_array[i];
|
||||
switch (drawing_or_ref->type) {
|
||||
case GREASE_PENCIL_DRAWING: {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
|
||||
const blender::bke::CurvesGeometry &curves = drawing->geometry.wrap();
|
||||
|
||||
if (!curves.bounds_min_max(min, max)) {
|
||||
min = float3(-1);
|
||||
max = float3(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GREASE_PENCIL_DRAWING_REFERENCE: {
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
}
|
||||
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
// Span<GreasePencilDrawingOrReference> blender::bke::GreasePencil::drawings() const
|
||||
// {
|
||||
// return Span<GreasePencilDrawingOrReference>{this->drawing_array, this->drawing_array_size};
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_gpencil_legacy_types.h"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
@ -344,6 +345,10 @@ Material ***BKE_object_material_array_p(Object *ob)
|
|||
Volume *volume = static_cast<Volume *>(ob->data);
|
||||
return &(volume->mat);
|
||||
}
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
|
||||
return &(grease_pencil->material_array);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -377,6 +382,10 @@ short *BKE_object_material_len_p(Object *ob)
|
|||
Volume *volume = static_cast<Volume *>(ob->data);
|
||||
return &(volume->totcol);
|
||||
}
|
||||
if (ob->type == OB_GREASE_PENCIL) {
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
|
||||
return reinterpret_cast<short *>(&(grease_pencil->material_array_size));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_gpencil_legacy_types.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_light_types.h"
|
||||
|
@ -89,6 +90,7 @@
|
|||
#include "BKE_gpencil_geom_legacy.h"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_gpencil_modifier_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_icons.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_idtype.h"
|
||||
|
@ -1413,7 +1415,8 @@ bool BKE_object_supports_modifiers(const Object *ob)
|
|||
OB_FONT,
|
||||
OB_LATTICE,
|
||||
OB_POINTCLOUD,
|
||||
OB_VOLUME);
|
||||
OB_VOLUME,
|
||||
OB_GREASE_PENCIL);
|
||||
}
|
||||
|
||||
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
|
||||
|
@ -1910,6 +1913,8 @@ bool BKE_object_is_in_editmode(const Object *ob)
|
|||
case OB_CURVES:
|
||||
/* Curves object has no edit mode data. */
|
||||
return ob->mode == OB_MODE_EDIT;
|
||||
case OB_GREASE_PENCIL:
|
||||
return ob->mode == OB_MODE_EDIT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2135,6 +2140,8 @@ static const char *get_obdata_defname(int type)
|
|||
return DATA_("GPencil");
|
||||
case OB_LIGHTPROBE:
|
||||
return DATA_("LightProbe");
|
||||
case OB_GREASE_PENCIL:
|
||||
return DATA_("GreasePencil");
|
||||
default:
|
||||
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
|
||||
return DATA_("Empty");
|
||||
|
@ -2204,6 +2211,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
|
|||
return BKE_pointcloud_add_default(bmain, name);
|
||||
case OB_VOLUME:
|
||||
return BKE_volume_add(bmain, name);
|
||||
case OB_GREASE_PENCIL:
|
||||
return BKE_grease_pencil_add(bmain, name);
|
||||
case OB_EMPTY:
|
||||
return nullptr;
|
||||
default:
|
||||
|
@ -2242,6 +2251,8 @@ int BKE_object_obdata_to_type(const ID *id)
|
|||
return OB_POINTCLOUD;
|
||||
case ID_VO:
|
||||
return OB_VOLUME;
|
||||
case ID_GP:
|
||||
return OB_GREASE_PENCIL;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -3749,6 +3760,8 @@ const BoundBox *BKE_object_boundbox_get(Object *ob)
|
|||
case OB_VOLUME:
|
||||
bb = BKE_volume_boundbox_get(ob);
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
bb = BKE_grease_pencil_boundbox_get(ob);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3933,7 +3946,6 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
|
|||
changed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case OB_POINTCLOUD: {
|
||||
const BoundBox bb = *BKE_pointcloud_boundbox_get(ob);
|
||||
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
|
||||
filedescriptor marked this conversation as resolved
Outdated
Falk David
commented
Fix line Fix line
|
||||
|
@ -3946,6 +3958,12 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
|
|||
changed = true;
|
||||
break;
|
||||
}
|
||||
case OB_GREASE_PENCIL: {
|
||||
const BoundBox bb = *BKE_grease_pencil_boundbox_get(ob);
|
||||
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed == false) {
|
||||
|
@ -5118,7 +5136,8 @@ bool BKE_object_supports_material_slots(struct Object *ob)
|
|||
OB_CURVES,
|
||||
OB_POINTCLOUD,
|
||||
OB_VOLUME,
|
||||
OB_GPENCIL_LEGACY);
|
||||
OB_GPENCIL_LEGACY,
|
||||
OB_GREASE_PENCIL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -196,6 +196,9 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
case OB_VOLUME:
|
||||
BKE_volume_data_update(depsgraph, scene, ob);
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
/* TODO: data update. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* particles */
|
||||
|
@ -316,6 +319,9 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
|
|||
case OB_VOLUME:
|
||||
BKE_volume_batch_cache_dirty_tag((struct Volume *)ob->data, BKE_VOLUME_BATCH_DIRTY_ALL);
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
/* TODO: tag batches. */
|
||||
filedescriptor marked this conversation as resolved
Outdated
Falk David
commented
Remove todo. Remove todo.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -938,6 +938,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
|
|||
case OB_CURVES:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_VOLUME:
|
||||
case OB_GREASE_PENCIL:
|
||||
build_object_data_geometry(object);
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
|
|
|
@ -952,7 +952,8 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
|
|||
case OB_GPENCIL_LEGACY:
|
||||
case OB_CURVES:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_VOLUME: {
|
||||
case OB_VOLUME:
|
||||
case OB_GREASE_PENCIL: {
|
||||
build_object_data_geometry(object);
|
||||
/* TODO(sergey): Only for until we support granular
|
||||
* update of curves. */
|
||||
|
|
|
@ -589,6 +589,7 @@ NodeType geometry_tag_to_component(const ID *id)
|
|||
case OB_CURVES:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_VOLUME:
|
||||
case OB_GREASE_PENCIL:
|
||||
return NodeType::GEOMETRY;
|
||||
case OB_ARMATURE:
|
||||
return NodeType::EVAL_POSE;
|
||||
|
|
|
@ -111,7 +111,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (ELEM(object->type, OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) {
|
||||
else if (ELEM(object->type, OB_CURVES, OB_POINTCLOUD, OB_VOLUME, OB_GREASE_PENCIL)) {
|
||||
if (object->id.recalc & ID_RECALC_GEOMETRY) {
|
||||
/* Free evaluated caches. */
|
||||
object->data = data_orig;
|
||||
|
|
|
@ -332,7 +332,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
|||
OB_GPENCIL_LEGACY,
|
||||
OB_CURVES,
|
||||
OB_POINTCLOUD,
|
||||
OB_VOLUME);
|
||||
OB_VOLUME,
|
||||
OB_GREASE_PENCIL);
|
||||
const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE));
|
||||
const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) &&
|
||||
!is_select;
|
||||
|
|
|
@ -697,6 +697,8 @@ static int acf_object_icon(bAnimListElem *ale)
|
|||
return ICON_OUTLINER_OB_EMPTY;
|
||||
case OB_GPENCIL_LEGACY:
|
||||
return ICON_OUTLINER_OB_GREASEPENCIL;
|
||||
case OB_GREASE_PENCIL:
|
||||
return ICON_OUTLINER_OB_GREASEPENCIL;
|
||||
default:
|
||||
return ICON_OBJECT_DATA;
|
||||
}
|
||||
|
|
|
@ -3088,6 +3088,31 @@ static int object_convert_exec(bContext *C, wmOperator *op)
|
|||
BKE_object_free_derived_caches(newob);
|
||||
BKE_object_free_modifiers(newob, 0);
|
||||
}
|
||||
else if (ob->type == OB_GPENCIL_LEGACY && target == OB_GREASE_PENCIL) {
|
||||
ob->flag |= OB_DONE;
|
||||
|
||||
bGPdata *gpd = static_cast<bGPdata *>(ob->data);
|
||||
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
|
||||
bGPDframe &gpf = *BKE_gpencil_layer_frame_find(gpl, scene->r.cfra);
|
||||
|
||||
if (keep_original) {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
else {
|
||||
newob = ob;
|
||||
}
|
||||
|
||||
Curves *new_curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, newob->id.name + 2));
|
||||
|
||||
newob->data = new_curves;
|
||||
newob->type = OB_CURVES;
|
||||
|
||||
new_curves->geometry.wrap() = std::move(
|
||||
bke::gpencil::convert::legacy_gpencil_frame_to_curves_geometry(gpf));
|
||||
|
||||
BKE_object_free_derived_caches(newob);
|
||||
BKE_object_free_modifiers(newob, 0);
|
||||
}
|
||||
else if (target == OB_CURVES) {
|
||||
ob->flag |= OB_DONE;
|
||||
|
||||
|
|
|
@ -682,6 +682,9 @@ static bool ED_object_editmode_load_free_ex(Main *bmain,
|
|||
else if (obedit->type == OB_CURVES) {
|
||||
/* Curves don't have specific edit mode data, so pass. */
|
||||
}
|
||||
else if (obedit->type == OB_GREASE_PENCIL) {
|
||||
/* Grease Pencil does not have specific edit mode data, so pass. */
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
@ -870,6 +873,10 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
|
|||
ok = true;
|
||||
WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVES, scene);
|
||||
}
|
||||
else if (ob->type == OB_CURVES) {
|
||||
ok = true;
|
||||
/* TODO: Add NS_EDITMODE_GREASE_PENCIL for WM_main_add_notifier. */
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
|
|
|
@ -146,6 +146,11 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
if (mode & (OB_MODE_EDIT)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1912,6 +1912,11 @@ static void single_obdata_users(
|
|||
ob->data,
|
||||
BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
|
||||
break;
|
||||
case OB_GREASE_PENCIL:
|
||||
ob->data = ID_NEW_SET(
|
||||
ob->data,
|
||||
BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS));
|
||||
break;
|
||||
default:
|
||||
printf("ERROR %s: can't copy %s\n", __func__, id->name);
|
||||
BLI_assert_msg(0, "This should never happen.");
|
||||
|
|
|
@ -184,7 +184,8 @@ static void stats_object(Object *ob,
|
|||
}
|
||||
case OB_CURVES:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_VOLUME: {
|
||||
case OB_VOLUME:
|
||||
case OB_GREASE_PENCIL: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2359,6 +2359,8 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id)
|
|||
}
|
||||
case OB_GPENCIL_LEGACY:
|
||||
return ICON_OUTLINER_OB_GREASEPENCIL;
|
||||
case OB_GREASE_PENCIL:
|
||||
return ICON_OUTLINER_OB_GREASEPENCIL;
|
||||
}
|
||||
|
||||
return ICON_NONE;
|
||||
|
|
|
@ -120,6 +120,7 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const Hierarch
|
|||
case OB_GPENCIL_LEGACY:
|
||||
case OB_POINTCLOUD:
|
||||
case OB_CURVES:
|
||||
case OB_GREASE_PENCIL:
|
||||
return nullptr;
|
||||
case OB_TYPE_MAX:
|
||||
BLI_assert_msg(0, "OB_TYPE_MAX should not be used");
|
||||
|
|
|
@ -508,7 +508,6 @@ enum {
|
|||
|
||||
OB_ARMATURE = 25,
|
||||
|
||||
/** Grease Pencil object used in 3D view but not used for annotation in 2D. */
|
||||
OB_GPENCIL_LEGACY = 26,
|
||||
|
||||
OB_CURVES = 27,
|
||||
|
@ -517,6 +516,8 @@ enum {
|
|||
|
||||
OB_VOLUME = 29,
|
||||
|
||||
OB_GREASE_PENCIL = 30,
|
||||
|
||||
/* Keep last. */
|
||||
OB_TYPE_MAX,
|
||||
};
|
||||
|
@ -524,7 +525,7 @@ enum {
|
|||
/* check if the object type supports materials */
|
||||
#define OB_TYPE_SUPPORT_MATERIAL(_type) \
|
||||
(((_type) >= OB_MESH && (_type) <= OB_MBALL) || \
|
||||
((_type) >= OB_GPENCIL_LEGACY && (_type) <= OB_VOLUME))
|
||||
((_type) >= OB_GPENCIL_LEGACY && (_type) <= OB_GREASE_PENCIL))
|
||||
/** Does the object have some render-able geometry (unlike empties, cameras, etc.). */
|
||||
#define OB_TYPE_IS_GEOMETRY(_type) \
|
||||
(ELEM(_type, \
|
||||
|
@ -535,7 +536,8 @@ enum {
|
|||
OB_GPENCIL_LEGACY, \
|
||||
OB_CURVES, \
|
||||
OB_POINTCLOUD, \
|
||||
OB_VOLUME))
|
||||
OB_VOLUME, \
|
||||
OB_GREASE_PENCIL))
|
||||
#define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL_LEGACY))
|
||||
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
|
||||
(ELEM(_type, \
|
||||
|
@ -546,13 +548,14 @@ enum {
|
|||
OB_MBALL, \
|
||||
OB_LATTICE, \
|
||||
OB_ARMATURE, \
|
||||
OB_CURVES))
|
||||
OB_CURVES, \
|
||||
OB_GREASE_PENCIL))
|
||||
#define OB_TYPE_SUPPORT_PARVERT(_type) \
|
||||
(ELEM(_type, OB_MESH, OB_SURF, OB_CURVES_LEGACY, OB_LATTICE))
|
||||
|
||||
/** Matches #OB_TYPE_SUPPORT_EDITMODE. */
|
||||
#define OB_DATA_SUPPORT_EDITMODE(_type) \
|
||||
(ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR, ID_CV))
|
||||
(ELEM(_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_AR, ID_CV, ID_GP))
|
||||
|
||||
/* is this ID type used as object data */
|
||||
#define OB_DATA_SUPPORT_ID(_id_type) \
|
||||
|
@ -569,7 +572,8 @@ enum {
|
|||
ID_AR, \
|
||||
ID_CV, \
|
||||
ID_PT, \
|
||||
ID_VO))
|
||||
ID_VO, \
|
||||
ID_GP))
|
||||
|
||||
#define OB_DATA_SUPPORT_ID_CASE \
|
||||
ID_ME: \
|
||||
|
@ -584,7 +588,8 @@ enum {
|
|||
case ID_AR: \
|
||||
case ID_CV: \
|
||||
case ID_PT: \
|
||||
case ID_VO
|
||||
case ID_VO: \
|
||||
case ID_GP
|
||||
|
||||
/** #Object.partype: first 4 bits: type. */
|
||||
enum {
|
||||
|
|
|
@ -256,6 +256,7 @@ const EnumPropertyItem rna_enum_object_type_items[] = {
|
|||
{OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""},
|
||||
{OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""},
|
||||
Bastien Montagne
commented
This change should also be conditioned to This change should also be conditioned to `#ifdef WITH_GREASE_PENCIL_V3` ?
|
||||
{OB_GPENCIL_LEGACY, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""},
|
||||
{OB_GREASE_PENCIL, "GREASEPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""},
|
||||
RNA_ENUM_ITEM_SEPR,
|
||||
{OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""},
|
||||
{OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""},
|
||||
|
|
Loading…
Reference in New Issue
Needs to walk the parents of layers too (once added).