2011-07-11 10:59:53 +00:00
|
|
|
/*
|
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2004 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): Joshua Leung
|
|
|
|
|
*
|
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** \file blender/editors/space_outliner/outliner_tree.c
|
|
|
|
|
* \ingroup spoutliner
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
|
#include "DNA_armature_types.h"
|
|
|
|
|
#include "DNA_constraint_types.h"
|
|
|
|
|
#include "DNA_camera_types.h"
|
Basic Alembic support
All in all, this patch adds an Alembic importer, an Alembic exporter,
and a new CacheFile data block which, for now, wraps around an Alembic
archive. This data block is made available through a new modifier ("Mesh
Sequence Cache") as well as a new constraint ("Transform Cache") to
somewhat properly support respectively geometric and transformation data
streaming from alembic caches.
A more in-depth documentation is to be found on the wiki, as well as a
guide to compile alembic: https://wiki.blender.org/index.php/
User:Kevindietrich/AlembicBasicIo.
Many thanks to everyone involved in this little project, and huge shout
out to "cgstrive" for the thorough testings with Maya, 3ds Max, Houdini
and Realflow as well as @fjuhec, @jensverwiebe and @jasperge for the
custom builds and compile fixes.
Reviewers: sergey, campbellbarton, mont29
Reviewed By: sergey, campbellbarton, mont29
Differential Revision: https://developer.blender.org/D2060
2016-08-06 06:20:37 +02:00
|
|
|
#include "DNA_cachefile_types.h"
|
2015-02-07 12:28:17 +13:00
|
|
|
#include "DNA_gpencil_types.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
#include "DNA_group_types.h"
|
|
|
|
|
#include "DNA_key_types.h"
|
|
|
|
|
#include "DNA_lamp_types.h"
|
|
|
|
|
#include "DNA_material_types.h"
|
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meta_types.h"
|
|
|
|
|
#include "DNA_particle_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_world_types.h"
|
|
|
|
|
#include "DNA_sequence_types.h"
|
2011-08-01 11:44:20 +00:00
|
|
|
#include "DNA_speaker_types.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
#include "DNA_object_types.h"
|
2013-09-04 01:15:23 +00:00
|
|
|
#include "DNA_linestyle_types.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
|
#include "BLI_utildefines.h"
|
2013-08-03 11:35:09 +00:00
|
|
|
#include "BLI_mempool.h"
|
2013-08-27 18:29:30 +00:00
|
|
|
#include "BLI_fnmatch.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2015-08-16 17:32:01 +10:00
|
|
|
#include "BLT_translation.h"
|
2013-03-11 15:01:03 +00:00
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
#include "BKE_fcurve.h"
|
|
|
|
|
#include "BKE_main.h"
|
2012-12-22 13:39:44 +00:00
|
|
|
#include "BKE_library.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
#include "BKE_modifier.h"
|
|
|
|
|
#include "BKE_sequencer.h"
|
2012-12-22 14:04:09 +00:00
|
|
|
#include "BKE_idcode.h"
|
2015-04-07 11:01:47 +10:00
|
|
|
#include "BKE_outliner_treehash.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
#include "ED_armature.h"
|
|
|
|
|
#include "ED_screen.h"
|
|
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
|
|
|
|
|
|
#include "outliner_intern.h"
|
|
|
|
|
|
2014-05-01 07:21:08 +10:00
|
|
|
#ifdef WIN32
|
|
|
|
|
# include "BLI_math_base.h" /* M_PI */
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* ********************************************************* */
|
2011-11-03 03:00:45 +00:00
|
|
|
/* Persistent Data */
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
static void outliner_storage_cleanup(SpaceOops *soops)
|
|
|
|
|
{
|
2013-08-03 11:35:09 +00:00
|
|
|
BLI_mempool *ts = soops->treestore;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ts) {
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeStoreElem *tselem;
|
2013-08-03 11:35:09 +00:00
|
|
|
int unused = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* each element used once, for ID blocks with more users to have each a treestore */
|
2013-08-03 11:35:09 +00:00
|
|
|
BLI_mempool_iter iter;
|
|
|
|
|
|
|
|
|
|
BLI_mempool_iternew(ts, &iter);
|
|
|
|
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
|
|
|
|
tselem->used = 0;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* cleanup only after reading file or undo step, and always for
|
|
|
|
|
* RNA datablocks view in order to save memory */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
|
2015-05-11 10:58:53 +10:00
|
|
|
soops->storeflag &= ~SO_TREESTORE_CLEANUP;
|
|
|
|
|
|
2013-08-03 11:35:09 +00:00
|
|
|
BLI_mempool_iternew(ts, &iter);
|
|
|
|
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
2012-05-07 17:56:30 +00:00
|
|
|
if (tselem->id == NULL) unused++;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (unused) {
|
2013-08-03 11:35:09 +00:00
|
|
|
if (BLI_mempool_count(ts) == unused) {
|
|
|
|
|
BLI_mempool_destroy(ts);
|
|
|
|
|
soops->treestore = NULL;
|
|
|
|
|
if (soops->treehash) {
|
2015-04-07 11:01:47 +10:00
|
|
|
BKE_outliner_treehash_free(soops->treehash);
|
2013-08-03 11:35:09 +00:00
|
|
|
soops->treehash = NULL;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-08-03 11:35:09 +00:00
|
|
|
TreeStoreElem *tsenew;
|
|
|
|
|
BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_count(ts) - unused,
|
|
|
|
|
512, BLI_MEMPOOL_ALLOW_ITER);
|
|
|
|
|
BLI_mempool_iternew(ts, &iter);
|
|
|
|
|
while ((tselem = BLI_mempool_iterstep(&iter))) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tselem->id) {
|
2013-08-03 11:35:09 +00:00
|
|
|
tsenew = BLI_mempool_alloc(new_ts);
|
|
|
|
|
*tsenew = *tselem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BLI_mempool_destroy(ts);
|
|
|
|
|
soops->treestore = new_ts;
|
|
|
|
|
if (soops->treehash) {
|
|
|
|
|
/* update hash table to fix broken pointers */
|
2015-04-07 11:01:47 +10:00
|
|
|
BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-03 03:00:45 +00:00
|
|
|
static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2013-08-17 11:49:18 +00:00
|
|
|
TreeStoreElem *tselem;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (soops->treestore == NULL) {
|
2013-08-03 11:35:09 +00:00
|
|
|
/* if treestore was not created in readfile.c, create it here */
|
|
|
|
|
soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
|
2013-08-18 20:07:49 +00:00
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-08-23 20:35:00 +00:00
|
|
|
if (soops->treehash == NULL) {
|
2015-04-07 11:01:47 +10:00
|
|
|
soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
|
2013-08-18 20:07:49 +00:00
|
|
|
/* find any unused tree element in treestore and mark it as used
|
|
|
|
|
* (note that there may be multiple unused elements in case of linked objects) */
|
2015-04-07 11:01:47 +10:00
|
|
|
tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
|
2013-08-17 11:49:18 +00:00
|
|
|
if (tselem) {
|
2013-08-03 11:35:09 +00:00
|
|
|
te->store_elem = tselem;
|
|
|
|
|
tselem->used = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add 1 element to treestore */
|
|
|
|
|
tselem = BLI_mempool_alloc(soops->treestore);
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem->type = type;
|
2013-08-03 11:35:09 +00:00
|
|
|
tselem->nr = type ? nr : 0;
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem->id = id;
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->used = 0;
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem->flag = TSE_CLOSED;
|
2013-08-03 11:35:09 +00:00
|
|
|
te->store_elem = tselem;
|
2015-04-07 11:01:47 +10:00
|
|
|
BKE_outliner_treehash_add_element(soops->treehash, tselem);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ********************************************************* */
|
|
|
|
|
/* Tree Management */
|
|
|
|
|
|
|
|
|
|
void outliner_free_tree(ListBase *lb)
|
|
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
while (lb->first) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *te = lb->first;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
outliner_free_tree(&te->subtree);
|
|
|
|
|
BLI_remlink(lb, te);
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
|
2011-07-11 10:59:53 +00:00
|
|
|
MEM_freeN(te);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-02 13:23:44 +00:00
|
|
|
void outliner_cleanup_tree(SpaceOops *soops)
|
|
|
|
|
{
|
|
|
|
|
outliner_free_tree(&soops->tree);
|
|
|
|
|
outliner_storage_cleanup(soops);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-03 11:35:09 +00:00
|
|
|
/* Find specific item from the treestore */
|
2016-04-26 13:08:38 +10:00
|
|
|
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2013-08-03 11:35:09 +00:00
|
|
|
TreeElement *te, *tes;
|
|
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
|
if (te->store_elem == store_elem) return te;
|
|
|
|
|
tes = outliner_find_tree_element(&te->subtree, store_elem);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tes) return tes;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* tse is not in the treestore, we use its contents to find a match */
|
2016-04-26 13:08:38 +10:00
|
|
|
TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2013-08-17 11:49:18 +00:00
|
|
|
TreeStoreElem *tselem;
|
2013-08-03 11:35:09 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (tse->id == NULL) return NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* check if 'tse' is in treestore */
|
2015-04-07 11:01:47 +10:00
|
|
|
tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tselem)
|
2013-08-03 11:35:09 +00:00
|
|
|
return outliner_find_tree_element(&soops->tree, tselem);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find treestore that refers to given ID */
|
2016-04-26 13:08:38 +10:00
|
|
|
TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2016-04-26 13:08:38 +10:00
|
|
|
for (TreeElement *te = lb->first; te; te = te->next) {
|
|
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
2012-05-07 17:56:30 +00:00
|
|
|
if (tselem->type == 0) {
|
2016-04-26 13:08:38 +10:00
|
|
|
if (tselem->id == id) {
|
|
|
|
|
return te;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
/* only deeper on scene or object */
|
2016-04-26 13:08:38 +10:00
|
|
|
if (ELEM(te->idcode, ID_OB, ID_SCE) ||
|
|
|
|
|
((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR)))
|
|
|
|
|
{
|
|
|
|
|
TreeElement *tes = outliner_find_id(soops, &te->subtree, id);
|
|
|
|
|
if (tes) {
|
|
|
|
|
return tes;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-16 15:19:18 +02:00
|
|
|
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
|
2016-04-26 12:54:51 +10:00
|
|
|
{
|
|
|
|
|
for (TreeElement *te = lb->first; te; te = te->next) {
|
|
|
|
|
if (te->directdata == pchan) {
|
|
|
|
|
return te;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
|
|
|
|
if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
|
2016-10-16 15:19:18 +02:00
|
|
|
TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan);
|
2016-04-26 12:54:51 +10:00
|
|
|
if (tes) {
|
|
|
|
|
return tes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-16 15:19:18 +02:00
|
|
|
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
|
2016-04-26 12:54:51 +10:00
|
|
|
{
|
|
|
|
|
for (TreeElement *te = lb->first; te; te = te->next) {
|
|
|
|
|
if (te->directdata == ebone) {
|
|
|
|
|
return te;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
|
|
|
|
if (ELEM(tselem->type, 0, TSE_EBONE)) {
|
2016-10-16 15:19:18 +02:00
|
|
|
TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
|
2016-04-26 12:54:51 +10:00
|
|
|
if (tes) {
|
|
|
|
|
return tes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-08-03 11:35:09 +00:00
|
|
|
ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
|
TreeStoreElem *tselem;
|
2012-05-07 17:56:30 +00:00
|
|
|
te = te->parent;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
while (te) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
|
|
|
|
if (tselem->type == 0 && te->idcode == idcode) return tselem->id;
|
|
|
|
|
te = te->parent;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ********************************************************* */
|
|
|
|
|
|
|
|
|
|
/* Prototype, see functions below */
|
|
|
|
|
static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *parent, short type, short index);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-07-11 13:36:38 +00:00
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* special handling of hierarchical non-lib data */
|
2016-10-16 15:19:18 +02:00
|
|
|
static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *parent, int *a)
|
2011-07-11 13:36:38 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
|
2011-07-11 13:36:38 +00:00
|
|
|
|
|
|
|
|
(*a)++;
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = curBone->name;
|
|
|
|
|
te->directdata = curBone;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) {
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------- */
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
#define LOG2I(x) (int)(log(x) / M_LN2)
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
|
|
|
|
|
{
|
|
|
|
|
TreeStoreElem *tselem = NULL;
|
|
|
|
|
TreeElement *te = NULL;
|
|
|
|
|
|
|
|
|
|
/* log stuff is to convert bitflags (powers of 2) to small integers,
|
|
|
|
|
* in order to not overflow short tselem->nr */
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Combined");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* save cpu cycles, but we add the first to invoke an open/close triangle */
|
|
|
|
|
tselem = TREESTORE(tenla);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tselem->flag & TSE_CLOSED)
|
2011-07-11 10:59:53 +00:00
|
|
|
return;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Z");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Vector");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Normal");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("UV");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Mist");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Index Object");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Index Material");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Color");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Diffuse");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Specular");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Shadow");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("AO");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Reflection");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Refraction");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Indirect");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Environment");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
|
|
|
|
|
|
|
|
|
te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT));
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Emit");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = &srl->passflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOG2I
|
|
|
|
|
|
2013-04-28 15:37:18 +00:00
|
|
|
static bool outliner_animdata_test(AnimData *adt)
|
2013-04-28 09:16:10 +00:00
|
|
|
{
|
|
|
|
|
if (adt)
|
|
|
|
|
return (adt->action || adt->drivers.first || adt->nla_tracks.first);
|
2013-04-28 15:37:18 +00:00
|
|
|
return false;
|
2013-04-28 09:16:10 +00:00
|
|
|
}
|
|
|
|
|
|
2014-05-08 10:00:49 +09:00
|
|
|
#ifdef WITH_FREESTYLE
|
2013-09-04 01:15:23 +00:00
|
|
|
static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
|
|
|
|
|
{
|
|
|
|
|
SceneRenderLayer *srl;
|
|
|
|
|
FreestyleLineSet *lineset;
|
|
|
|
|
|
|
|
|
|
for (srl = sce->r.layers.first; srl; srl = srl->next) {
|
|
|
|
|
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
|
2013-09-30 08:43:22 +00:00
|
|
|
FreestyleLineStyle *linestyle = lineset->linestyle;
|
|
|
|
|
if (linestyle) {
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
linestyle->id.tag |= LIB_TAG_DOIT;
|
2013-09-30 08:43:22 +00:00
|
|
|
}
|
2013-09-04 01:15:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (srl = sce->r.layers.first; srl; srl = srl->next) {
|
|
|
|
|
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
|
|
|
|
|
FreestyleLineStyle *linestyle = lineset->linestyle;
|
2013-09-30 08:43:22 +00:00
|
|
|
if (linestyle) {
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
if (!(linestyle->id.tag & LIB_TAG_DOIT))
|
2013-09-30 08:43:22 +00:00
|
|
|
continue;
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
linestyle->id.tag &= ~LIB_TAG_DOIT;
|
2013-09-30 08:43:22 +00:00
|
|
|
outliner_add_element(soops, lb, linestyle, te, 0, 0);
|
|
|
|
|
}
|
2013-09-04 01:15:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-08 10:00:49 +09:00
|
|
|
#endif
|
2013-09-04 01:15:23 +00:00
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
|
|
|
|
|
{
|
|
|
|
|
SceneRenderLayer *srl;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla->name = IFACE_("RenderLayers");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0, srl = sce->r.layers.first; srl; srl = srl->next, a++) {
|
|
|
|
|
TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
|
|
|
|
|
tenlay->name = srl->name;
|
2013-08-03 15:00:22 +00:00
|
|
|
tenlay->directdata = &srl->layflag;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (srl->light_override)
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (srl->mat_override)
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
|
|
|
|
|
|
|
|
|
|
outliner_add_passes(soops, tenlay, &sce->id, srl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: move this to the front?
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(sce->adt))
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
|
2015-02-07 12:28:17 +13:00
|
|
|
|
|
|
|
|
outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
outliner_add_element(soops, lb, sce->world, te, 0, 0);
|
2013-10-14 23:08:45 +00:00
|
|
|
|
2014-05-08 10:00:49 +09:00
|
|
|
#ifdef WITH_FREESTYLE
|
2014-10-28 12:49:04 +01:00
|
|
|
if (STREQ(sce->r.engine, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
|
2013-10-14 19:57:16 +00:00
|
|
|
outliner_add_line_styles(soops, lb, sce, te);
|
2014-05-08 10:00:49 +09:00
|
|
|
#endif
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-11 13:36:38 +00:00
|
|
|
// can be inlined if necessary
|
|
|
|
|
static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(ob->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2016-07-06 14:11:01 +02:00
|
|
|
if (ob->proxy && !ID_IS_LINKED_DATABLOCK(ob))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
|
2015-02-07 12:28:17 +13:00
|
|
|
|
|
|
|
|
outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
|
2011-07-11 13:36:38 +00:00
|
|
|
|
|
|
|
|
outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (ob->pose) {
|
2012-05-07 17:56:30 +00:00
|
|
|
bArmature *arm = ob->data;
|
2011-07-11 13:36:38 +00:00
|
|
|
bPoseChannel *pchan;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla->name = IFACE_("Pose");
|
2011-07-11 13:36:38 +00:00
|
|
|
|
|
|
|
|
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
|
|
|
|
|
if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten;
|
2012-05-07 17:56:30 +00:00
|
|
|
int a = 0, const_index = 1000; /* ensure unique id for bone constraints */
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) {
|
|
|
|
|
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
|
|
|
|
|
ten->name = pchan->name;
|
|
|
|
|
ten->directdata = pchan;
|
|
|
|
|
pchan->temp = (void *)ten;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pchan->constraints.first) {
|
2011-07-11 10:59:53 +00:00
|
|
|
//Object *target;
|
|
|
|
|
bConstraint *con;
|
2011-07-11 13:36:38 +00:00
|
|
|
TreeElement *ten1;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
//char *str;
|
|
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla1->name = IFACE_("Constraints");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (con = pchan->constraints.first; con; con = con->next, const_index++) {
|
|
|
|
|
ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
|
2011-07-11 13:36:38 +00:00
|
|
|
#if 0 /* disabled as it needs to be reworked for recoded constraints system */
|
2012-05-07 17:56:30 +00:00
|
|
|
target = get_constraint_target(con, &str);
|
|
|
|
|
if (str && str[0]) ten1->name = str;
|
|
|
|
|
else if (target) ten1->name = target->id.name + 2;
|
|
|
|
|
else ten1->name = con->name;
|
2011-07-11 10:59:53 +00:00
|
|
|
#endif
|
2012-05-07 17:56:30 +00:00
|
|
|
ten1->name = con->name;
|
|
|
|
|
ten1->directdata = con;
|
2011-07-11 10:59:53 +00:00
|
|
|
/* possible add all other types links? */
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
/* make hierarchy */
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = tenla->subtree.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (ten) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *nten = ten->next, *par;
|
|
|
|
|
tselem = TREESTORE(ten);
|
|
|
|
|
if (tselem->type == TSE_POSE_CHANNEL) {
|
|
|
|
|
pchan = (bPoseChannel *)ten->directdata;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pchan->parent) {
|
2011-07-11 13:36:38 +00:00
|
|
|
BLI_remlink(&tenla->subtree, ten);
|
2012-05-07 17:56:30 +00:00
|
|
|
par = (TreeElement *)pchan->parent->temp;
|
2011-07-11 13:36:38 +00:00
|
|
|
BLI_addtail(&par->subtree, ten);
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->parent = par;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = nten;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pose Groups */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->pose->agroups.first) {
|
2011-07-11 13:36:38 +00:00
|
|
|
bActionGroup *agrp;
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten_bonegrp = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
|
2012-05-07 17:56:30 +00:00
|
|
|
int a = 0;
|
2015-11-23 15:44:15 +11:00
|
|
|
|
|
|
|
|
ten_bonegrp->name = IFACE_("Bone Groups");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten;
|
|
|
|
|
ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a);
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->name = agrp->name;
|
|
|
|
|
ten->directdata = agrp;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-23 15:44:15 +11:00
|
|
|
for (int a = 0; a < ob->totcol; a++) {
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
|
2015-11-23 15:44:15 +11:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->constraints.first) {
|
2011-07-11 13:36:38 +00:00
|
|
|
//Object *target;
|
|
|
|
|
bConstraint *con;
|
|
|
|
|
TreeElement *ten;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
|
2011-07-11 13:36:38 +00:00
|
|
|
//char *str;
|
2015-11-23 15:44:15 +11:00
|
|
|
int a;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla->name = IFACE_("Constraints");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
|
|
|
|
|
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
|
2011-07-11 13:36:38 +00:00
|
|
|
#if 0 /* disabled due to constraints system targets recode... code here needs review */
|
2012-05-07 17:56:30 +00:00
|
|
|
target = get_constraint_target(con, &str);
|
|
|
|
|
if (str && str[0]) ten->name = str;
|
|
|
|
|
else if (target) ten->name = target->id.name + 2;
|
|
|
|
|
else ten->name = con->name;
|
2011-07-11 13:36:38 +00:00
|
|
|
#endif
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->name = con->name;
|
|
|
|
|
ten->directdata = con;
|
2011-07-11 13:36:38 +00:00
|
|
|
/* possible add all other types links? */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ob->modifiers.first) {
|
|
|
|
|
ModifierData *md;
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
|
2011-07-11 13:36:38 +00:00
|
|
|
int index;
|
|
|
|
|
|
2015-11-23 15:44:15 +11:00
|
|
|
ten_mod->name = IFACE_("Modifiers");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten = outliner_add_element(soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
|
|
|
|
|
ten->name = md->name;
|
|
|
|
|
ten->directdata = md;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (md->type == eModifierType_Lattice) {
|
2015-11-23 15:44:15 +11:00
|
|
|
outliner_add_element(soops, &ten->subtree, ((LatticeModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (md->type == eModifierType_Curve) {
|
2015-11-23 15:44:15 +11:00
|
|
|
outliner_add_element(soops, &ten->subtree, ((CurveModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (md->type == eModifierType_Armature) {
|
2015-11-23 15:44:15 +11:00
|
|
|
outliner_add_element(soops, &ten->subtree, ((ArmatureModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (md->type == eModifierType_Hook) {
|
2015-11-23 15:44:15 +11:00
|
|
|
outliner_add_element(soops, &ten->subtree, ((HookModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (md->type == eModifierType_ParticleSystem) {
|
|
|
|
|
ParticleSystem *psys = ((ParticleSystemModifierData *) md)->psys;
|
2015-11-23 15:44:15 +11:00
|
|
|
TreeElement *ten_psys;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2015-11-24 14:24:26 +05:00
|
|
|
ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
|
2015-11-23 15:44:15 +11:00
|
|
|
ten_psys->directdata = psys;
|
|
|
|
|
ten_psys->name = psys->part->id.name + 2;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* vertex groups */
|
|
|
|
|
if (ob->defbase.first) {
|
|
|
|
|
bDeformGroup *defgroup;
|
|
|
|
|
TreeElement *ten;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
|
2015-11-23 15:44:15 +11:00
|
|
|
int a;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla->name = IFACE_("Vertex Groups");
|
2012-05-07 17:56:30 +00:00
|
|
|
for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
|
|
|
|
|
ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
|
|
|
|
|
ten->name = defgroup->name;
|
|
|
|
|
ten->directdata = defgroup;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* duplicated group */
|
|
|
|
|
if (ob->dup_group)
|
2012-10-21 05:46:41 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-22 16:49:50 +00:00
|
|
|
|
2011-07-11 13:36:38 +00:00
|
|
|
// can be inlined if necessary
|
|
|
|
|
static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, ID *id)
|
|
|
|
|
{
|
|
|
|
|
/* tuck pointer back in object, to construct hierarchy */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (GS(id->name) == ID_OB) id->newid = (ID *)te;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
|
|
|
|
/* expand specific data always */
|
|
|
|
|
switch (GS(id->name)) {
|
|
|
|
|
case ID_LI:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = ((Library *)id)->name;
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_SCE:
|
|
|
|
|
{
|
|
|
|
|
outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_OB:
|
|
|
|
|
{
|
|
|
|
|
outliner_add_object_contents(soops, te, tselem, (Object *)id);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_ME:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Mesh *me = (Mesh *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(me->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
|
|
|
|
outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < me->totcol; a++)
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
|
|
|
|
|
/* could do tfaces with image links, but the images are not grouped nicely.
|
2012-03-03 16:31:46 +00:00
|
|
|
* would require going over all tfaces, sort images in use. etc... */
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_CU:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Curve *cu = (Curve *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(cu->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < cu->totcol; a++)
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_MB:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
MetaBall *mb = (MetaBall *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(mb->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < mb->totcol; a++)
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_MA:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Material *ma = (Material *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(ma->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < MAX_MTEX; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_TE:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Tex *tex = (Tex *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(tex->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
|
|
|
|
outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_CA:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Camera *ca = (Camera *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(ca->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
Basic Alembic support
All in all, this patch adds an Alembic importer, an Alembic exporter,
and a new CacheFile data block which, for now, wraps around an Alembic
archive. This data block is made available through a new modifier ("Mesh
Sequence Cache") as well as a new constraint ("Transform Cache") to
somewhat properly support respectively geometric and transformation data
streaming from alembic caches.
A more in-depth documentation is to be found on the wiki, as well as a
guide to compile alembic: https://wiki.blender.org/index.php/
User:Kevindietrich/AlembicBasicIo.
Many thanks to everyone involved in this little project, and huge shout
out to "cgstrive" for the thorough testings with Maya, 3ds Max, Houdini
and Realflow as well as @fjuhec, @jensverwiebe and @jasperge for the
custom builds and compile fixes.
Reviewers: sergey, campbellbarton, mont29
Reviewed By: sergey, campbellbarton, mont29
Differential Revision: https://developer.blender.org/D2060
2016-08-06 06:20:37 +02:00
|
|
|
case ID_CF:
|
|
|
|
|
{
|
|
|
|
|
CacheFile *cache_file = (CacheFile *)id;
|
|
|
|
|
|
|
|
|
|
if (outliner_animdata_test(cache_file->adt)) {
|
|
|
|
|
outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
case ID_LA:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Lamp *la = (Lamp *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(la->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < MAX_MTEX; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
2011-08-01 11:44:20 +00:00
|
|
|
case ID_SPK:
|
2012-05-07 17:56:30 +00:00
|
|
|
{
|
|
|
|
|
Speaker *spk = (Speaker *)id;
|
2011-08-01 11:44:20 +00:00
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(spk->adt))
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2012-05-07 17:56:30 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
case ID_WO:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
World *wrld = (World *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(wrld->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < MAX_MTEX; a++) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_KE:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Key *key = (Key *)id;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(key->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_AC:
|
|
|
|
|
{
|
|
|
|
|
// XXX do we want to be exposing the F-Curves here?
|
2012-10-26 04:14:10 +00:00
|
|
|
//bAction *act = (bAction *)id;
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
case ID_AR:
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
bArmature *arm = (bArmature *)id;
|
|
|
|
|
int a = 0;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2013-04-28 09:16:10 +00:00
|
|
|
if (outliner_animdata_test(arm->adt))
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (arm->edbo) {
|
2011-07-11 13:36:38 +00:00
|
|
|
EditBone *ebone;
|
|
|
|
|
TreeElement *ten;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) {
|
|
|
|
|
ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
|
|
|
|
|
ten->directdata = ebone;
|
|
|
|
|
ten->name = ebone->name;
|
2015-03-28 04:34:28 +11:00
|
|
|
ebone->temp.p = ten;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
/* make hierarchy */
|
2015-03-28 04:34:28 +11:00
|
|
|
ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (ten) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *nten = ten->next, *par;
|
|
|
|
|
ebone = (EditBone *)ten->directdata;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ebone->parent) {
|
2011-07-11 13:36:38 +00:00
|
|
|
BLI_remlink(&te->subtree, ten);
|
2015-03-28 04:34:28 +11:00
|
|
|
par = ebone->parent->temp.p;
|
2011-07-11 13:36:38 +00:00
|
|
|
BLI_addtail(&par->subtree, ten);
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->parent = par;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = nten;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* do not extend Armature when we have posemode */
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te->parent);
|
2012-10-07 09:48:59 +00:00
|
|
|
if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
else {
|
2011-07-11 13:36:38 +00:00
|
|
|
Bone *curBone;
|
2012-05-07 17:56:30 +00:00
|
|
|
for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
|
2011-07-11 13:36:38 +00:00
|
|
|
outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-09-04 01:15:23 +00:00
|
|
|
case ID_LS:
|
|
|
|
|
{
|
|
|
|
|
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
|
2014-04-23 15:07:04 +09:00
|
|
|
int a;
|
2013-09-04 01:15:23 +00:00
|
|
|
|
|
|
|
|
if (outliner_animdata_test(linestyle->adt))
|
|
|
|
|
outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
|
2014-04-23 15:07:04 +09:00
|
|
|
|
|
|
|
|
for (a = 0; a < MAX_MTEX; a++) {
|
2014-05-02 12:33:24 +09:00
|
|
|
if (linestyle->mtex[a])
|
|
|
|
|
outliner_add_element(soops, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
|
2014-04-23 15:07:04 +09:00
|
|
|
}
|
2013-09-04 01:15:23 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2015-02-07 12:28:17 +13:00
|
|
|
case ID_GD:
|
|
|
|
|
{
|
|
|
|
|
bGPdata *gpd = (bGPdata *)id;
|
|
|
|
|
bGPDlayer *gpl;
|
|
|
|
|
int a = 0;
|
|
|
|
|
|
|
|
|
|
if (outliner_animdata_test(gpd->adt))
|
|
|
|
|
outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
|
2015-02-07 12:50:22 +13:00
|
|
|
|
|
|
|
|
// TODO: base element for layers?
|
2015-02-07 12:28:17 +13:00
|
|
|
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
2015-02-07 12:50:22 +13:00
|
|
|
outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
|
2015-02-07 12:28:17 +13:00
|
|
|
a++;
|
|
|
|
|
}
|
2015-02-11 18:38:41 +11:00
|
|
|
break;
|
2015-02-07 12:28:17 +13:00
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: this function needs to be split up! It's getting a bit too large...
|
2012-12-22 13:39:44 +00:00
|
|
|
// Note: "ID" is not always a real ID
|
2016-10-16 15:19:18 +02:00
|
|
|
static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *parent, short type, short index)
|
2011-07-11 13:36:38 +00:00
|
|
|
{
|
|
|
|
|
TreeElement *te;
|
|
|
|
|
TreeStoreElem *tselem;
|
2012-05-07 17:56:30 +00:00
|
|
|
ID *id = idv;
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
id = ((PointerRNA *)idv)->id.data;
|
|
|
|
|
if (!id) id = ((PointerRNA *)idv)->data;
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
2015-08-22 16:37:35 +10:00
|
|
|
else if (type == TSE_GP_LAYER) {
|
|
|
|
|
/* idv is the layer its self */
|
|
|
|
|
id = TREESTORE(parent)->id;
|
|
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2012-12-22 16:49:50 +00:00
|
|
|
/* One exception */
|
2012-12-23 01:18:35 +00:00
|
|
|
if (type == TSE_ID_BASE) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (id == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2015-04-30 14:04:41 +02:00
|
|
|
if (type == 0) {
|
|
|
|
|
/* Zero type means real ID, ensure we do not get non-outliner ID types here... */
|
|
|
|
|
BLI_assert(TREESTORE_ID_TYPE(id));
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = MEM_callocN(sizeof(TreeElement), "tree elem");
|
2011-07-11 13:36:38 +00:00
|
|
|
/* add to the visual tree */
|
|
|
|
|
BLI_addtail(lb, te);
|
|
|
|
|
/* add to the storage */
|
2011-11-03 03:00:45 +00:00
|
|
|
check_persistent(soops, te, id, type, index);
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 13:36:38 +00:00
|
|
|
|
2011-09-09 12:46:07 +00:00
|
|
|
/* if we are searching for something expand to see child elements */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (SEARCHING_OUTLINER(soops))
|
2011-09-09 12:46:07 +00:00
|
|
|
tselem->flag |= TSE_CHILDSEARCH;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->parent = parent;
|
|
|
|
|
te->index = index; // for data arays
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
|
2012-10-07 09:48:59 +00:00
|
|
|
/* pass */
|
|
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
|
2012-10-07 09:48:59 +00:00
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (type == TSE_ANIM_DATA) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2015-02-07 12:50:22 +13:00
|
|
|
else if (type == TSE_GP_LAYER) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2012-12-22 13:39:44 +00:00
|
|
|
else if (type == TSE_ID_BASE) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
2011-07-11 13:36:38 +00:00
|
|
|
else {
|
2012-12-27 19:07:16 +00:00
|
|
|
/* do here too, for blend file viewer, own ID_LI then shows file name */
|
|
|
|
|
if (GS(id->name) == ID_LI)
|
|
|
|
|
te->name = ((Library *)id)->name;
|
|
|
|
|
else
|
|
|
|
|
te->name = id->name + 2; // default, can be overridden by Library or non-ID data
|
2012-05-07 17:56:30 +00:00
|
|
|
te->idcode = GS(id->name);
|
2011-07-11 13:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (type == 0) {
|
2012-12-22 13:39:44 +00:00
|
|
|
TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
|
|
|
|
|
|
2011-07-11 13:36:38 +00:00
|
|
|
/* ID datablock */
|
2012-12-23 01:18:35 +00:00
|
|
|
if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
|
2012-12-22 13:39:44 +00:00
|
|
|
outliner_add_id_contents(soops, te, tselem, id);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (type == TSE_ANIM_DATA) {
|
2011-07-11 10:59:53 +00:00
|
|
|
IdAdtTemplate *iat = (IdAdtTemplate *)idv;
|
2012-05-07 17:56:30 +00:00
|
|
|
AnimData *adt = (AnimData *)iat->adt;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* this element's info */
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Animation");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = adt;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* Action */
|
|
|
|
|
outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Drivers */
|
|
|
|
|
if (adt->drivers.first) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
|
|
|
|
|
ID *lastadded = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
FCurve *fcu;
|
|
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
ted->name = IFACE_("Drivers");
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
|
2012-02-27 10:35:39 +00:00
|
|
|
if (fcu->driver && fcu->driver->variables.first) {
|
2012-05-07 17:56:30 +00:00
|
|
|
ChannelDriver *driver = fcu->driver;
|
2011-07-11 10:59:53 +00:00
|
|
|
DriverVar *dvar;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* loop over all targets used here */
|
|
|
|
|
DRIVER_TARGETS_USED_LOOPER(dvar)
|
|
|
|
|
{
|
|
|
|
|
if (lastadded != dtar->id) {
|
|
|
|
|
// XXX this lastadded check is rather lame, and also fails quite badly...
|
|
|
|
|
outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
|
2012-05-07 17:56:30 +00:00
|
|
|
lastadded = dtar->id;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DRIVER_TARGETS_LOOPER_END
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* NLA Data */
|
|
|
|
|
if (adt->nla_tracks.first) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
NlaTrack *nlt;
|
2012-05-07 17:56:30 +00:00
|
|
|
int a = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-03-11 15:01:03 +00:00
|
|
|
tenla->name = IFACE_("NLA Tracks");
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
|
|
|
|
|
TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
NlaStrip *strip;
|
|
|
|
|
TreeElement *ten;
|
2012-05-07 17:56:30 +00:00
|
|
|
int b = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
tenlt->name = nlt->name;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (strip = nlt->strips.first; strip; strip = strip->next, b++) {
|
|
|
|
|
ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
|
|
|
|
|
if (ten) ten->directdata = strip;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-07 12:50:22 +13:00
|
|
|
else if (type == TSE_GP_LAYER) {
|
|
|
|
|
bGPDlayer *gpl = (bGPDlayer *)idv;
|
|
|
|
|
|
|
|
|
|
te->name = gpl->info;
|
|
|
|
|
te->directdata = gpl;
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (type == TSE_SEQUENCE) {
|
|
|
|
|
Sequence *seq = (Sequence *) idv;
|
2011-07-11 10:59:53 +00:00
|
|
|
Sequence *p;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The idcode is a little hack, but the outliner
|
|
|
|
|
* only check te->idcode if te->type is equal to zero,
|
|
|
|
|
* so this is "safe".
|
|
|
|
|
*/
|
2012-05-07 17:56:30 +00:00
|
|
|
te->idcode = seq->type;
|
|
|
|
|
te->directdata = seq;
|
2012-05-29 05:45:06 +00:00
|
|
|
te->name = seq->name + 2;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2015-07-01 17:32:56 +02:00
|
|
|
if (!(seq->type & SEQ_TYPE_EFFECT)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/*
|
|
|
|
|
* This work like the sequence.
|
|
|
|
|
* If the sequence have a name (not default name)
|
|
|
|
|
* show it, in other case put the filename.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-06-07 15:49:02 +00:00
|
|
|
if (seq->type == SEQ_TYPE_META) {
|
2012-05-07 17:56:30 +00:00
|
|
|
p = seq->seqbase.first;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (p) {
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
|
|
|
|
|
p = p->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (type == TSE_SEQ_STRIP) {
|
|
|
|
|
Strip *strip = (Strip *)idv;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-07-16 11:42:07 +00:00
|
|
|
if (strip->dir[0] != '\0')
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = strip->dir;
|
2011-07-11 10:59:53 +00:00
|
|
|
else
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("Strip None");
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = strip;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (type == TSE_SEQUENCE_DUP) {
|
|
|
|
|
Sequence *seq = (Sequence *)idv;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->idcode = seq->type;
|
|
|
|
|
te->directdata = seq;
|
|
|
|
|
te->name = seq->strip->stripdata->name;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
|
2011-07-11 10:59:53 +00:00
|
|
|
PropertyRNA *prop, *iterprop;
|
|
|
|
|
PropertyType proptype;
|
|
|
|
|
int a, tot;
|
|
|
|
|
|
|
|
|
|
/* we do lazy build, for speed and to avoid infinite recusion */
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ptr->data == NULL) {
|
2013-03-11 15:01:03 +00:00
|
|
|
te->name = IFACE_("(empty)");
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (type == TSE_RNA_STRUCT) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* struct */
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (te->name)
|
2011-07-11 10:59:53 +00:00
|
|
|
te->flag |= TE_FREE_NAME;
|
|
|
|
|
else
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = RNA_struct_ui_name(ptr->type);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-09-09 12:46:07 +00:00
|
|
|
/* If searching don't expand RNA entries */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
|
2011-09-09 12:46:07 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
iterprop = RNA_struct_iterator_property(ptr->type);
|
|
|
|
|
tot = RNA_property_collection_length(ptr, iterprop);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* auto open these cases */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
|
|
|
|
|
if (!tselem->used)
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
2016-11-19 01:15:08 +01:00
|
|
|
for (a = 0; a < tot; a++) {
|
|
|
|
|
RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
|
|
|
|
|
if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
|
|
|
|
|
outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (tot)
|
2011-07-11 10:59:53 +00:00
|
|
|
te->flag |= TE_LAZY_CLOSED;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->rnaptr = *ptr;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (type == TSE_RNA_PROPERTY) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* property */
|
2012-05-07 17:56:30 +00:00
|
|
|
iterprop = RNA_struct_iterator_property(ptr->type);
|
2011-07-11 10:59:53 +00:00
|
|
|
RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
prop = propptr.data;
|
|
|
|
|
proptype = RNA_property_type(prop);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = RNA_property_ui_name(prop);
|
|
|
|
|
te->directdata = prop;
|
|
|
|
|
te->rnaptr = *ptr;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-09-09 12:46:07 +00:00
|
|
|
/* If searching don't expand RNA entries */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
|
2011-09-09 12:46:07 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (proptype == PROP_POINTER) {
|
2012-05-07 17:56:30 +00:00
|
|
|
pptr = RNA_property_pointer_get(ptr, prop);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pptr.data) {
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops))
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
|
2011-07-11 10:59:53 +00:00
|
|
|
else
|
|
|
|
|
te->flag |= TE_LAZY_CLOSED;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (proptype == PROP_COLLECTION) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tot = RNA_property_collection_length(ptr, prop);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < tot; a++) {
|
2011-07-11 10:59:53 +00:00
|
|
|
RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (tot)
|
2011-07-11 10:59:53 +00:00
|
|
|
te->flag |= TE_LAZY_CLOSED;
|
|
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tot = RNA_property_array_length(ptr, prop);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
for (a = 0; a < tot; a++)
|
|
|
|
|
outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (tot)
|
2011-07-11 10:59:53 +00:00
|
|
|
te->flag |= TE_LAZY_CLOSED;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (type == TSE_RNA_ARRAY_ELEM) {
|
2011-07-11 10:59:53 +00:00
|
|
|
char c;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
prop = parent->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = prop;
|
|
|
|
|
te->rnaptr = *ptr;
|
|
|
|
|
te->index = index;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
c = RNA_property_array_item_char(prop, index);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName");
|
2012-03-24 06:38:07 +00:00
|
|
|
if (c) sprintf((char *)te->name, " %c", c);
|
2012-05-07 17:56:30 +00:00
|
|
|
else sprintf((char *)te->name, " %d", index + 1);
|
2011-07-11 10:59:53 +00:00
|
|
|
te->flag |= TE_FREE_NAME;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (type == TSE_KEYMAP) {
|
2012-05-07 17:56:30 +00:00
|
|
|
wmKeyMap *km = (wmKeyMap *)idv;
|
2011-07-11 10:59:53 +00:00
|
|
|
wmKeyMapItem *kmi;
|
|
|
|
|
char opname[OP_MAX_TYPENAME];
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te->directdata = idv;
|
|
|
|
|
te->name = km->idname;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
2013-07-30 08:45:45 +00:00
|
|
|
int a = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 02:51:46 +00:00
|
|
|
for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
|
2015-07-03 15:07:46 +02:00
|
|
|
const char *key = WM_key_event_string(kmi->type, false);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (key[0]) {
|
2012-05-07 17:56:30 +00:00
|
|
|
wmOperatorType *ot = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-10-07 09:48:59 +00:00
|
|
|
if (kmi->propvalue) {
|
|
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ot = WM_operatortype_find(kmi->idname, 0);
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ot || kmi->propvalue) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *ten = outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->directdata = kmi;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (kmi->propvalue) {
|
2013-03-11 15:01:03 +00:00
|
|
|
ten->name = IFACE_("Modal map, not yet");
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
WM_operator_py_idname(opname, ot->idname);
|
2012-05-07 17:56:30 +00:00
|
|
|
ten->name = BLI_strdup(opname);
|
2011-07-11 10:59:53 +00:00
|
|
|
ten->flag |= TE_FREE_NAME;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
te->flag |= TE_LAZY_CLOSED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return te;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ======================================================= */
|
|
|
|
|
/* Sequencer mode tree building */
|
|
|
|
|
|
|
|
|
|
/* Helped function to put duplicate sequence in the same tree. */
|
|
|
|
|
static int need_add_seq_dup(Sequence *seq)
|
|
|
|
|
{
|
|
|
|
|
Sequence *p;
|
|
|
|
|
|
2013-07-29 04:45:40 +00:00
|
|
|
if ((!seq->strip) || (!seq->strip->stripdata))
|
2011-07-11 10:59:53 +00:00
|
|
|
return(1);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* First check backward, if we found a duplicate
|
|
|
|
|
* sequence before this, don't need it, just return.
|
|
|
|
|
*/
|
2012-05-07 17:56:30 +00:00
|
|
|
p = seq->prev;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (p) {
|
2013-07-27 09:20:10 +00:00
|
|
|
if ((!p->strip) || (!p->strip->stripdata)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->prev;
|
2011-07-11 10:59:53 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 16:03:11 +01:00
|
|
|
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
|
2011-07-11 10:59:53 +00:00
|
|
|
return(2);
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->prev;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
p = seq->next;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (p) {
|
2013-07-27 09:20:10 +00:00
|
|
|
if ((!p->strip) || (!p->strip->stripdata)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 16:03:11 +01:00
|
|
|
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
|
2011-07-11 10:59:53 +00:00
|
|
|
return(0);
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index)
|
|
|
|
|
{
|
2011-09-20 08:48:48 +00:00
|
|
|
/* TreeElement *ch; */ /* UNUSED */
|
2011-07-11 10:59:53 +00:00
|
|
|
Sequence *p;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
p = seq;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (p) {
|
2013-07-16 11:42:07 +00:00
|
|
|
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 16:03:11 +01:00
|
|
|
if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
|
2012-10-26 04:14:10 +00:00
|
|
|
/* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
|
2012-05-07 17:56:30 +00:00
|
|
|
p = p->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-16 00:25:55 +13:00
|
|
|
|
|
|
|
|
/* ----------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
|
|
|
|
|
{
|
|
|
|
|
TreeElement *ten;
|
|
|
|
|
ListBase *lbarray[MAX_LIBARRAY];
|
|
|
|
|
int a, tot;
|
|
|
|
|
|
|
|
|
|
tot = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
for (a = 0; a < tot; a++) {
|
|
|
|
|
if (lbarray[a]->first) {
|
|
|
|
|
ID *id = lbarray[a]->first;
|
|
|
|
|
|
|
|
|
|
/* check if there's data in current lib */
|
|
|
|
|
for (; id; id = id->next)
|
|
|
|
|
if (id->lib == lib)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (id) {
|
2015-07-12 02:53:37 +10:00
|
|
|
ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
|
2015-02-16 00:25:55 +13:00
|
|
|
ten->directdata = lbarray[a];
|
|
|
|
|
|
|
|
|
|
ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
|
|
|
|
|
if (ten->name == NULL)
|
|
|
|
|
ten->name = "UNKNOWN";
|
|
|
|
|
|
|
|
|
|
for (id = lbarray[a]->first; id; id = id->next) {
|
|
|
|
|
if (id->lib == lib)
|
|
|
|
|
outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
|
|
|
|
|
{
|
|
|
|
|
TreeElement *ten;
|
|
|
|
|
ListBase *lbarray[MAX_LIBARRAY];
|
|
|
|
|
int a, tot;
|
|
|
|
|
|
|
|
|
|
tot = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
for (a = 0; a < tot; a++) {
|
|
|
|
|
if (lbarray[a]->first) {
|
|
|
|
|
ID *id = lbarray[a]->first;
|
|
|
|
|
|
|
|
|
|
/* check if there are any datablocks of this type which are orphans */
|
|
|
|
|
for (; id; id = id->next) {
|
|
|
|
|
if (ID_REAL_USERS(id) <= 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (id) {
|
|
|
|
|
/* header for this type of datablock */
|
2015-02-16 01:20:53 +13:00
|
|
|
/* TODO's:
|
|
|
|
|
* - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
|
|
|
|
|
* - Ensure that this uses nice icons for the datablock type involved instead of the dot?
|
|
|
|
|
*/
|
2015-07-12 02:53:37 +10:00
|
|
|
ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
|
2015-02-16 00:25:55 +13:00
|
|
|
ten->directdata = lbarray[a];
|
|
|
|
|
|
|
|
|
|
ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
|
|
|
|
|
if (ten->name == NULL)
|
|
|
|
|
ten->name = "UNKNOWN";
|
|
|
|
|
|
|
|
|
|
/* add the orphaned datablocks - these will not be added with any subtrees attached */
|
|
|
|
|
for (id = lbarray[a]->first; id; id = id->next) {
|
|
|
|
|
if (ID_REAL_USERS(id) <= 0)
|
|
|
|
|
outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* ======================================================= */
|
|
|
|
|
/* Generic Tree Building helpers - order these are called is top to bottom */
|
|
|
|
|
|
|
|
|
|
/* Hierarchy --------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/* make sure elements are correctly nested */
|
2013-08-03 11:35:09 +00:00
|
|
|
static void outliner_make_hierarchy(ListBase *lb)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
|
TreeElement *te, *ten, *tep;
|
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
|
|
|
|
|
/* build hierarchy */
|
|
|
|
|
// XXX also, set extents here...
|
2012-05-07 17:56:30 +00:00
|
|
|
te = lb->first;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (te) {
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = te->next;
|
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (tselem->type == 0 && te->idcode == ID_OB) {
|
|
|
|
|
Object *ob = (Object *)tselem->id;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->parent && ob->parent->id.newid) {
|
2011-07-11 10:59:53 +00:00
|
|
|
BLI_remlink(lb, te);
|
2012-05-07 17:56:30 +00:00
|
|
|
tep = (TreeElement *)ob->parent->id.newid;
|
2011-07-11 10:59:53 +00:00
|
|
|
BLI_addtail(&tep->subtree, te);
|
|
|
|
|
// set correct parent pointers
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = tep->subtree.first; te; te = te->next) te->parent = tep;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
te = ten;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sorting ------------------------------------------------------ */
|
|
|
|
|
|
|
|
|
|
typedef struct tTreeSort {
|
|
|
|
|
TreeElement *te;
|
|
|
|
|
ID *id;
|
|
|
|
|
const char *name;
|
|
|
|
|
short idcode;
|
|
|
|
|
} tTreeSort;
|
|
|
|
|
|
2012-12-22 13:39:44 +00:00
|
|
|
/* alphabetical comparator, tryping to put objects first */
|
|
|
|
|
static int treesort_alpha_ob(const void *v1, const void *v2)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
const tTreeSort *x1 = v1, *x2 = v2;
|
2011-07-11 10:59:53 +00:00
|
|
|
int comp;
|
|
|
|
|
|
|
|
|
|
/* first put objects last (hierarchy) */
|
2012-05-07 17:56:30 +00:00
|
|
|
comp = (x1->idcode == ID_OB);
|
|
|
|
|
if (x2->idcode == ID_OB) comp += 2;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (comp == 1) return 1;
|
|
|
|
|
else if (comp == 2) return -1;
|
|
|
|
|
else if (comp == 3) {
|
|
|
|
|
comp = strcmp(x1->name, x2->name);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (comp > 0) return 1;
|
|
|
|
|
else if (comp < 0) return -1;
|
2011-07-11 10:59:53 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-22 13:39:44 +00:00
|
|
|
/* alphabetical comparator */
|
|
|
|
|
static int treesort_alpha(const void *v1, const void *v2)
|
|
|
|
|
{
|
|
|
|
|
const tTreeSort *x1 = v1, *x2 = v2;
|
|
|
|
|
int comp;
|
|
|
|
|
|
|
|
|
|
comp = strcmp(x1->name, x2->name);
|
|
|
|
|
|
|
|
|
|
if (comp > 0) return 1;
|
|
|
|
|
else if (comp < 0) return -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* this is nice option for later? doesnt look too useful... */
|
|
|
|
|
#if 0
|
|
|
|
|
static int treesort_obtype_alpha(const void *v1, const void *v2)
|
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
const tTreeSort *x1 = v1, *x2 = v2;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* first put objects last (hierarchy) */
|
2013-03-09 03:46:30 +00:00
|
|
|
if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
else {
|
|
|
|
|
/* 2nd we check ob type */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
|
2013-03-09 03:46:30 +00:00
|
|
|
if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
|
2012-09-09 00:00:21 +00:00
|
|
|
else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
|
2011-07-11 10:59:53 +00:00
|
|
|
else return 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-05-07 17:56:30 +00:00
|
|
|
int comp = strcmp(x1->name, x2->name);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-03-09 03:46:30 +00:00
|
|
|
if (comp > 0) return 1;
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (comp < 0) return -1;
|
2011-07-11 10:59:53 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* sort happens on each subtree individual */
|
2016-10-16 15:19:18 +02:00
|
|
|
static void outliner_sort(ListBase *lb)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
|
TreeElement *te;
|
|
|
|
|
TreeStoreElem *tselem;
|
2012-05-07 17:56:30 +00:00
|
|
|
int totelem = 0;
|
2015-01-19 01:01:23 +01:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = lb->last;
|
|
|
|
|
if (te == NULL) return;
|
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-12-22 13:39:44 +00:00
|
|
|
/* sorting rules; only object lists, ID lists, or deformgroups */
|
|
|
|
|
if ( ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* count first */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) totelem++;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (totelem > 1) {
|
|
|
|
|
tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
|
|
|
|
|
tTreeSort *tp = tear;
|
|
|
|
|
int skip = 0;
|
|
|
|
|
|
|
|
|
|
for (te = lb->first; te; te = te->next, tp++) {
|
|
|
|
|
tselem = TREESTORE(te);
|
|
|
|
|
tp->te = te;
|
|
|
|
|
tp->name = te->name;
|
|
|
|
|
tp->idcode = te->idcode;
|
2012-12-22 13:39:44 +00:00
|
|
|
|
|
|
|
|
if (tselem->type && tselem->type != TSE_DEFGROUP)
|
|
|
|
|
tp->idcode = 0; // don't sort this
|
|
|
|
|
if (tselem->type == TSE_ID_BASE)
|
|
|
|
|
tp->idcode = 1; // do sort this
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
tp->id = tselem->id;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-22 13:39:44 +00:00
|
|
|
/* just sort alphabetically */
|
|
|
|
|
if (tear->idcode == 1) {
|
|
|
|
|
qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* keep beginning of list */
|
|
|
|
|
for (tp = tear, skip = 0; skip < totelem; skip++, tp++)
|
|
|
|
|
if (tp->idcode) break;
|
|
|
|
|
|
|
|
|
|
if (skip < totelem)
|
|
|
|
|
qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2014-02-08 06:07:10 +11:00
|
|
|
BLI_listbase_clear(lb);
|
2012-05-07 17:56:30 +00:00
|
|
|
tp = tear;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (totelem--) {
|
2011-07-11 10:59:53 +00:00
|
|
|
BLI_addtail(lb, tp->te);
|
|
|
|
|
tp++;
|
|
|
|
|
}
|
|
|
|
|
MEM_freeN(tear);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
2016-10-16 15:19:18 +02:00
|
|
|
outliner_sort(&te->subtree);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Filtering ----------------------------------------------- */
|
|
|
|
|
|
2015-01-03 10:13:02 +01:00
|
|
|
static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
int fn_flag = 0;
|
2015-01-03 10:13:02 +01:00
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
if ((flags & SO_FIND_CASE_SENSITIVE) == 0)
|
|
|
|
|
fn_flag |= FNM_CASEFOLD;
|
|
|
|
|
|
2015-01-03 10:13:02 +01:00
|
|
|
return fnmatch(name, te->name, fn_flag) == 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
|
|
|
|
|
{
|
|
|
|
|
TreeElement *te, *ten;
|
|
|
|
|
TreeStoreElem *tselem;
|
2015-01-03 10:13:02 +01:00
|
|
|
char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
|
|
|
|
|
char *search_string;
|
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
/* although we don't have any search string, we return true
|
2011-07-11 10:59:53 +00:00
|
|
|
* since the entire tree is ok then...
|
|
|
|
|
*/
|
2012-05-07 17:56:30 +00:00
|
|
|
if (soops->search_string[0] == 0)
|
2011-07-11 10:59:53 +00:00
|
|
|
return 1;
|
|
|
|
|
|
2015-01-03 10:13:02 +01:00
|
|
|
if (soops->search_flags & SO_FIND_COMPLETE) {
|
|
|
|
|
search_string = soops->search_string;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Implicitly add heading/trailing wildcards if needed. */
|
2015-01-10 22:54:32 +01:00
|
|
|
BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
|
|
|
|
|
search_string = search_buff;
|
2015-01-03 10:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = ten) {
|
|
|
|
|
ten = te->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2015-01-03 10:13:02 +01:00
|
|
|
if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* item isn't something we're looking for, but...
|
2012-05-07 17:56:30 +00:00
|
|
|
* - if the subtree is expanded, check if there are any matches that can be easily found
|
2011-07-11 10:59:53 +00:00
|
|
|
* so that searching for "cu" in the default scene will still match the Cube
|
|
|
|
|
* - otherwise, we can't see within the subtree and the item doesn't match,
|
|
|
|
|
* so these can be safely ignored (i.e. the subtree can get freed)
|
|
|
|
|
*/
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-09-09 12:46:07 +00:00
|
|
|
/* flag as not a found item */
|
|
|
|
|
tselem->flag &= ~TSE_SEARCHMATCH;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_free_tree(&te->subtree);
|
|
|
|
|
BLI_remlink(lb, te);
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
|
2011-07-11 10:59:53 +00:00
|
|
|
MEM_freeN(te);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
2011-09-09 12:46:07 +00:00
|
|
|
|
|
|
|
|
/* flag as a found item - we can then highlight it */
|
|
|
|
|
tselem->flag |= TSE_SEARCHMATCH;
|
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* filter subtree too */
|
|
|
|
|
outliner_filter_tree(soops, &te->subtree);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if there are still items in the list, that means that there were still some matches */
|
2014-02-08 06:07:10 +11:00
|
|
|
return (BLI_listbase_is_empty(lb) == false);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ======================================================= */
|
|
|
|
|
/* Main Tree Building API */
|
|
|
|
|
|
|
|
|
|
/* Main entry point for building the tree data-structure that the outliner represents */
|
|
|
|
|
// TODO: split each mode into its own function?
|
|
|
|
|
void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
|
|
|
|
|
{
|
|
|
|
|
Base *base;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *te = NULL, *ten;
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeStoreElem *tselem;
|
2013-08-03 11:35:09 +00:00
|
|
|
int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-09-09 12:46:07 +00:00
|
|
|
/* Are we looking for something - we want to tag parents to filter child matches
|
2012-03-03 16:31:46 +00:00
|
|
|
* - NOT in datablocks view - searching all datablocks takes way too long to be useful
|
|
|
|
|
* - this variable is only set once per tree build */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATABLOCKS)
|
2011-09-09 12:46:07 +00:00
|
|
|
soops->search_flags |= SO_SEARCH_RECURSIVE;
|
|
|
|
|
else
|
|
|
|
|
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
|
|
|
|
|
|
2015-05-15 15:52:24 +02:00
|
|
|
if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
|
2015-05-11 11:06:35 +10:00
|
|
|
soops->storeflag &= ~SO_TREESTORE_REBUILD;
|
|
|
|
|
BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
|
2011-07-11 10:59:53 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
outliner_free_tree(&soops->tree);
|
|
|
|
|
outliner_storage_cleanup(soops);
|
|
|
|
|
|
|
|
|
|
/* clear ob id.new flags */
|
2015-11-23 15:44:15 +11:00
|
|
|
for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
|
|
|
|
|
ob->id.newid = NULL;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
/* options */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (soops->outlinevis == SO_LIBRARIES) {
|
2011-07-11 10:59:53 +00:00
|
|
|
Library *lib;
|
|
|
|
|
|
2012-12-22 17:32:56 +00:00
|
|
|
/* current file first - mainvar provides tselem with unique pointer - not used */
|
|
|
|
|
ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0);
|
2013-03-11 15:01:03 +00:00
|
|
|
ten->name = IFACE_("Current File");
|
2012-12-22 16:49:50 +00:00
|
|
|
|
|
|
|
|
tselem = TREESTORE(ten);
|
|
|
|
|
if (!tselem->used)
|
|
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
|
|
|
|
|
|
outliner_add_library_contents(mainvar, soops, ten, NULL);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (lib = mainvar->library.first; lib; lib = lib->id.next) {
|
|
|
|
|
ten = outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
|
|
|
|
|
lib->id.newid = (ID *)ten;
|
2012-12-22 16:49:50 +00:00
|
|
|
|
|
|
|
|
outliner_add_library_contents(mainvar, soops, ten, lib);
|
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
/* make hierarchy */
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = soops->tree.first;
|
2012-12-23 01:18:35 +00:00
|
|
|
ten = ten->next; /* first one is main */
|
2012-03-24 06:38:07 +00:00
|
|
|
while (ten) {
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *nten = ten->next, *par;
|
|
|
|
|
tselem = TREESTORE(ten);
|
|
|
|
|
lib = (Library *)tselem->id;
|
2012-12-22 16:49:50 +00:00
|
|
|
if (lib && lib->parent) {
|
2012-05-07 17:56:30 +00:00
|
|
|
par = (TreeElement *)lib->parent->id.newid;
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
if (tselem->id->tag & LIB_TAG_INDIRECT) {
|
2015-01-05 11:28:34 +01:00
|
|
|
/* Only remove from 'first level' if lib is not also directly used. */
|
|
|
|
|
BLI_remlink(&soops->tree, ten);
|
|
|
|
|
BLI_addtail(&par->subtree, ten);
|
|
|
|
|
ten->parent = par;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Else, make a new copy of the libtree for our parent. */
|
|
|
|
|
TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
|
|
|
|
|
outliner_add_library_contents(mainvar, soops, dupten, lib);
|
|
|
|
|
dupten->parent = par;
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = nten;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
/* restore newid pointers */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (lib = mainvar->library.first; lib; lib = lib->id.next)
|
|
|
|
|
lib->id.newid = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_ALL_SCENES) {
|
2011-07-11 10:59:53 +00:00
|
|
|
Scene *sce;
|
2012-05-07 17:56:30 +00:00
|
|
|
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
|
|
|
|
|
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
|
|
|
|
|
tselem = TREESTORE(te);
|
|
|
|
|
if (sce == scene && show_opened)
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = sce->base.first; base; base = base->next) {
|
|
|
|
|
ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
|
|
|
|
|
ten->directdata = base;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&te->subtree);
|
2011-07-11 10:59:53 +00:00
|
|
|
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_CUR_SCENE) {
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
|
outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = scene->base.first; base; base = base->next) {
|
|
|
|
|
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
|
|
|
|
ten->directdata = base;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&soops->tree);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_VISIBLE) {
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = scene->base.first; base; base = base->next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (base->lay & scene->lay)
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
|
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&soops->tree);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_GROUPS) {
|
2011-07-11 10:59:53 +00:00
|
|
|
Group *group;
|
|
|
|
|
GroupObject *go;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (group = mainvar->group.first; group; group = group->id.next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (group->gobject.first) {
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (go = group->gobject.first; go; go = go->next) {
|
|
|
|
|
ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
|
|
|
|
|
ten->directdata = NULL; /* eh, why? */
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&te->subtree);
|
2011-07-11 10:59:53 +00:00
|
|
|
/* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_SAME_TYPE) {
|
2012-05-07 17:56:30 +00:00
|
|
|
Object *ob = OBACT;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob) {
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = scene->base.first; base; base = base->next) {
|
|
|
|
|
if (base->object->type == ob->type) {
|
|
|
|
|
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
|
|
|
|
ten->directdata = base;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&soops->tree);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (soops->outlinevis == SO_SELECTED) {
|
2012-05-07 17:56:30 +00:00
|
|
|
for (base = scene->base.first; base; base = base->next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (base->lay & scene->lay) {
|
2016-02-11 00:55:11 +11:00
|
|
|
if (base->flag & SELECT) {
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
|
|
|
|
|
ten->directdata = base;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-03 11:35:09 +00:00
|
|
|
outliner_make_hierarchy(&soops->tree);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (soops->outlinevis == SO_SEQUENCE) {
|
2011-07-11 10:59:53 +00:00
|
|
|
Sequence *seq;
|
2014-03-20 15:45:20 +06:00
|
|
|
Editing *ed = BKE_sequencer_editing_get(scene, false);
|
2011-07-11 10:59:53 +00:00
|
|
|
int op;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (ed == NULL)
|
2011-07-11 10:59:53 +00:00
|
|
|
return;
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
seq = ed->seqbasep->first;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!seq)
|
2011-07-11 10:59:53 +00:00
|
|
|
return;
|
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
while (seq) {
|
2012-05-07 17:56:30 +00:00
|
|
|
op = need_add_seq_dup(seq);
|
|
|
|
|
if (op == 1) {
|
2012-10-26 04:14:10 +00:00
|
|
|
/* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0);
|
2011-09-22 14:42:29 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (op == 0) {
|
|
|
|
|
ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_add_seq_dup(soops, seq, ten, 0);
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
seq = seq->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (soops->outlinevis == SO_DATABLOCKS) {
|
2011-07-11 10:59:53 +00:00
|
|
|
PointerRNA mainptr;
|
|
|
|
|
|
|
|
|
|
RNA_main_pointer_create(mainvar, &mainptr);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (show_opened) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(ten);
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (soops->outlinevis == SO_USERDEF) {
|
2011-07-11 10:59:53 +00:00
|
|
|
PointerRNA userdefptr;
|
|
|
|
|
|
|
|
|
|
RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
|
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (show_opened) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(ten);
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-15 21:55:49 +13:00
|
|
|
else if (soops->outlinevis == SO_ID_ORPHANS) {
|
|
|
|
|
outliner_add_orphaned_datablocks(mainvar, soops);
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
else {
|
2012-05-07 17:56:30 +00:00
|
|
|
ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
|
|
|
|
|
if (ten) ten->directdata = BASACT;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-16 15:19:18 +02:00
|
|
|
if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
|
|
|
|
|
outliner_sort(&soops->tree);
|
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_filter_tree(soops, &soops->tree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|