Merge branch 'master' into blender2.8

This commit is contained in:
Campbell Barton 2017-08-27 00:51:54 +10:00
commit 79111f9246
11 changed files with 176 additions and 125 deletions

View File

@ -64,6 +64,8 @@ inline void face_split_tri_indices(const int face_flag,
tri_b[2] = 1;
}
else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ {
assert(face_flag & FACE_FLAG_DIVIDE_13);
tri_a[0] = 0;
tri_a[1] = 1;
tri_a[2] = 2;
@ -77,15 +79,17 @@ inline void face_split_tri_indices(const int face_flag,
/* Tangent Space */
struct MikkUserData {
MikkUserData(const BL::Mesh& mesh_,
BL::MeshTextureFaceLayer *layer_,
int num_faces_)
: mesh(mesh_), layer(layer_), num_faces(num_faces_)
MikkUserData(const BL::Mesh& b_mesh,
BL::MeshTextureFaceLayer *layer,
int num_faces)
: b_mesh(b_mesh),
layer(layer),
num_faces(num_faces)
{
tangent.resize(num_faces*4);
}
BL::Mesh mesh;
BL::Mesh b_mesh;
BL::MeshTextureFaceLayer *layer;
int num_faces;
vector<float4> tangent;
@ -100,7 +104,7 @@ static int mikk_get_num_faces(const SMikkTSpaceContext *context)
static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num)
{
MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num];
int4 vi = get_int4(f.vertices_raw());
return (vi[3] == 0)? 3: 4;
@ -109,9 +113,9 @@ static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const i
static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], const int face_num, const int vert_num)
{
MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num];
int4 vi = get_int4(f.vertices_raw());
BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
BL::MeshVertex v = userdata->b_mesh.vertices[vi[vert_num]];
float3 vP = get_float3(v.co());
P[0] = vP.x;
@ -145,9 +149,9 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float
uv[1] = tfuv.y;
}
else {
int vert_idx = userdata->mesh.tessfaces[face_num].vertices()[vert_num];
int vert_idx = userdata->b_mesh.tessfaces[face_num].vertices()[vert_num];
float3 orco =
get_float3(userdata->mesh.vertices[vert_idx].undeformed_co());
get_float3(userdata->b_mesh.vertices[vert_idx].undeformed_co());
float2 tmp = map_to_sphere(make_float3(orco[0], orco[1], orco[2]));
uv[0] = tmp.x;
uv[1] = tmp.y;
@ -157,12 +161,12 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float
static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], const int face_num, const int vert_num)
{
MikkUserData *userdata = (MikkUserData*)context->m_pUserData;
BL::MeshTessFace f = userdata->mesh.tessfaces[face_num];
BL::MeshTessFace f = userdata->b_mesh.tessfaces[face_num];
float3 vN;
if(f.use_smooth()) {
int4 vi = get_int4(f.vertices_raw());
BL::MeshVertex v = userdata->mesh.vertices[vi[vert_num]];
BL::MeshVertex v = userdata->b_mesh.vertices[vi[vert_num]];
vN = get_float3(v.normal());
}
else {

View File

@ -242,21 +242,21 @@ void BVH4::pack_unaligned_node(int idx,
* so kernel might safely assume there are always 4 child nodes.
*/
data[1][i] = 1.0f;
data[2][i] = 0.0f;
data[3][i] = 0.0f;
data[1][i] = NAN;
data[2][i] = NAN;
data[3][i] = NAN;
data[4][i] = 0.0f;
data[5][i] = 0.0f;
data[6][i] = 0.0f;
data[4][i] = NAN;
data[5][i] = NAN;
data[6][i] = NAN;
data[7][i] = 0.0f;
data[8][i] = 0.0f;
data[9][i] = 0.0f;
data[7][i] = NAN;
data[8][i] = NAN;
data[9][i] = NAN;
data[10][i] = -FLT_MAX;
data[11][i] = -FLT_MAX;
data[12][i] = -FLT_MAX;
data[10][i] = NAN;
data[11][i] = NAN;
data[12][i] = NAN;
data[13][i] = __int_as_float(0);
}

View File

@ -120,7 +120,7 @@ public:
}
#endif
if(strstr(architecture_name, logged_architecture) != 0) {
if(strcmp(architecture_name, logged_architecture) != 0) {
VLOG(1) << "Will be using " << architecture_name << " kernels.";
logged_architecture = architecture_name;
}

View File

@ -120,49 +120,56 @@ ccl_device void kernel_filter_detect_outliers(int x, int y,
{
int buffer_w = align_up(rect.z - rect.x, 4);
int n = 0;
float values[25];
for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) {
for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) {
int idx = (y1-rect.y)*buffer_w + (x1-rect.x);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
/* Find the position of L. */
int i;
for(i = 0; i < n; i++) {
if(values[i] > L) break;
}
/* Make space for L by shifting all following values to the right. */
for(int j = n; j > i; j--) {
values[j] = values[j-1];
}
/* Insert L. */
values[i] = L;
n++;
}
}
int idx = (y-rect.y)*buffer_w + (x-rect.x);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]);
float ref = 2.0f*values[(int)(n*0.75f)];
float fac = 1.0f;
if(L > ref) {
/* The pixel appears to be an outlier.
* However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel
* should actually be at the reference value:
* If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier.
* Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight.
*/
float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride])));
if(L - 3*stddev < ref) {
/* The pixel is an outlier, so negate the depth value to mark it as one.
* Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */
depth[idx] = -depth[idx];
fac = ref/L;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
if(color.x < 0.0f || color.y < 0.0f || color.z < 0.0f) {
depth[idx] = -depth[idx];
fac = 0.0f;
}
else {
float L = average(color);
int n = 0;
float values[25];
for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) {
for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) {
int idx = (y1-rect.y)*buffer_w + (x1-rect.x);
float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]));
/* Find the position of L. */
int i;
for(i = 0; i < n; i++) {
if(values[i] > L) break;
}
/* Make space for L by shifting all following values to the right. */
for(int j = n; j > i; j--) {
values[j] = values[j-1];
}
/* Insert L. */
values[i] = L;
n++;
}
}
float ref = 2.0f*values[(int)(n*0.75f)];
if(L > ref) {
/* The pixel appears to be an outlier.
* However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel
* should actually be at the reference value:
* If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier.
* Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight.
*/
float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride])));
if(L - 3*stddev < ref) {
/* The pixel is an outlier, so negate the depth value to mark it as one.
* Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */
depth[idx] = -depth[idx];
fac = ref/L;
variance[idx ] *= fac*fac;
variance[idx + pass_stride] *= fac*fac;
variance[idx+2*pass_stride] *= fac*fac;
}
}
}
out[idx ] = fac*image[idx];

View File

@ -37,7 +37,7 @@ public:
~scoped_timer()
{
if(value_ != NULL) {
*value_ = time_dt() - time_start_;
*value_ = get_time();
}
}
@ -46,6 +46,11 @@ public:
return time_start_;
}
double get_time() const
{
return time_dt() - time_start_;
}
protected:
double *value_;
double time_start_;

View File

@ -39,17 +39,23 @@
#define INTERNAL_RND_SORT_SEED 39871946
#ifdef _MSC_VER
# define MIKK_INLINE static __forceinline
#else
# define MIKK_INLINE static inline __attribute__((always_inline)) __attribute__((unused))
#endif
// internal structure
typedef struct {
float x, y, z;
} SVec3;
static tbool veq( const SVec3 v1, const SVec3 v2 )
MIKK_INLINE tbool veq( const SVec3 v1, const SVec3 v2 )
{
return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
}
static SVec3 vadd( const SVec3 v1, const SVec3 v2 )
MIKK_INLINE SVec3 vadd( const SVec3 v1, const SVec3 v2 )
{
SVec3 vRes;
@ -61,7 +67,7 @@ static SVec3 vadd( const SVec3 v1, const SVec3 v2 )
}
static SVec3 vsub( const SVec3 v1, const SVec3 v2 )
MIKK_INLINE SVec3 vsub( const SVec3 v1, const SVec3 v2 )
{
SVec3 vRes;
@ -72,7 +78,7 @@ static SVec3 vsub( const SVec3 v1, const SVec3 v2 )
return vRes;
}
static SVec3 vscale(const float fS, const SVec3 v)
MIKK_INLINE SVec3 vscale(const float fS, const SVec3 v)
{
SVec3 vRes;
@ -83,24 +89,24 @@ static SVec3 vscale(const float fS, const SVec3 v)
return vRes;
}
static float LengthSquared( const SVec3 v )
MIKK_INLINE float LengthSquared( const SVec3 v )
{
return v.x*v.x + v.y*v.y + v.z*v.z;
}
static float Length( const SVec3 v )
MIKK_INLINE float Length( const SVec3 v )
{
return sqrtf(LengthSquared(v));
}
#if 0 // UNUSED
static SVec3 Normalize( const SVec3 v )
MIKK_INLINE SVec3 Normalize( const SVec3 v )
{
return vscale(1.0f / Length(v), v);
}
#endif
static SVec3 NormalizeSafe( const SVec3 v )
MIKK_INLINE SVec3 NormalizeSafe( const SVec3 v )
{
const float len = Length(v);
if (len != 0.0f) {
@ -112,20 +118,20 @@ static SVec3 NormalizeSafe( const SVec3 v )
}
}
static float vdot( const SVec3 v1, const SVec3 v2)
MIKK_INLINE float vdot( const SVec3 v1, const SVec3 v2)
{
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}
static tbool NotZero(const float fX)
MIKK_INLINE tbool NotZero(const float fX)
{
// could possibly use FLT_EPSILON instead
return fabsf(fX) > FLT_MIN;
}
#if 0 // UNUSED
static tbool VNotZero(const SVec3 v)
MIKK_INLINE tbool VNotZero(const SVec3 v)
{
// might change this to an epsilon based test
return NotZero(v.x) || NotZero(v.y) || NotZero(v.z);
@ -184,13 +190,13 @@ static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], con
const int iNrActiveGroups, const int piTriListIn[], const float fThresCos,
const SMikkTSpaceContext * pContext);
static int MakeIndex(const int iFace, const int iVert)
MIKK_INLINE int MakeIndex(const int iFace, const int iVert)
{
assert(iVert>=0 && iVert<4 && iFace>=0);
return (iFace<<2) | (iVert&0x3);
}
static void IndexToData(int * piFace, int * piVert, const int iIndexIn)
MIKK_INLINE void IndexToData(int * piFace, int * piVert, const int iIndexIn)
{
piVert[0] = iIndexIn&0x3;
piFace[0] = iIndexIn>>2;
@ -226,9 +232,9 @@ static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1)
static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index);
static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index);
static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index);
MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index);
MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index);
MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index);
// degen triangles
@ -896,7 +902,7 @@ static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_
return iTSpacesOffs;
}
static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index)
MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index)
{
int iF, iI;
SVec3 res; float pos[3];
@ -906,7 +912,7 @@ static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index)
return res;
}
static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index)
MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index)
{
int iF, iI;
SVec3 res; float norm[3];
@ -916,7 +922,7 @@ static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index)
return res;
}
static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index)
MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index)
{
int iF, iI;
SVec3 res; float texc[2];
@ -1080,7 +1086,7 @@ static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMi
/////////////////////////////////////////////////////////////////////////////////////////////////////
static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup);
static void AddTriToGroup(SGroup * pGroup, const int iTriIndex);
MIKK_INLINE void AddTriToGroup(SGroup * pGroup, const int iTriIndex);
static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn)
{
@ -1146,7 +1152,7 @@ static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupT
return iNrActiveGroups;
}
static void AddTriToGroup(SGroup * pGroup, const int iTriIndex)
MIKK_INLINE void AddTriToGroup(SGroup * pGroup, const int iTriIndex)
{
pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex;
++pGroup->iNrFaces;
@ -1671,6 +1677,20 @@ static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int
}
return;
}
else if(iElems < 16) {
int i, j;
for (i = 0; i < iElems - 1; i++) {
for (j = 0; j < iElems - i - 1; j++) {
int index = iLeft + j;
if (pSortBuffer[index].array[channel] > pSortBuffer[index + 1].array[channel]) {
sTmp = pSortBuffer[index];
pSortBuffer[index] = pSortBuffer[index + 1];
pSortBuffer[index + 1] = sTmp;
}
}
}
return;
}
// Random
t=uSeed&31;

View File

@ -193,8 +193,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n",
id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect);
printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n",
id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect);
#endif
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
@ -208,6 +208,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
if (is_obj) {
Object *ob = (Object *)id;
if (ob->data == *id_p && ob->proxy != NULL) {
/* And another 'Proudly brought to you by Proxy Hell' hack!
* This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
id_remap_data->skipped_direct++;
}
}
}
else if (is_never_null || is_obj_editmode) {
id_remap_data->skipped_direct++;

View File

@ -152,6 +152,9 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) {
return;
}
TIMEIT_BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6), bvhtree_verts);
if (treeData.tree == NULL) {
@ -376,6 +379,9 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return;
if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) {
return;
}
/* Prepare data to retrieve the direction in which we should project each vertex */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
@ -432,7 +438,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if (targ_tree) {
BVHTree *aux_tree = NULL;
void *aux_callback = NULL;
if (auxMesh != NULL) {
if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) {
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
@ -560,6 +566,10 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
if (calc->target->getNumPolys(calc->target) == 0) {
return;
}
/* Create a bvh-tree of the given target */
bvhtree_from_mesh_looptri(&treeData, calc->target, 0.0, 2, 6);
if (treeData.tree == NULL) {

View File

@ -197,7 +197,7 @@ void BM_mesh_bm_from_me(
KeyBlock *actkey, *block;
BMVert *v, **vtable = NULL;
BMEdge *e, **etable = NULL;
BMFace *f;
BMFace *f, **ftable = NULL;
float (*keyco)[3] = NULL;
int totloops, i, j;
@ -223,7 +223,7 @@ void BM_mesh_bm_from_me(
return; /* sanity check */
}
vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable");
vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
@ -325,12 +325,7 @@ void BM_mesh_bm_from_me(
bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
if (!me->totedge) {
MEM_freeN(vtable);
return;
}
etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable");
etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
medge = me->medge;
for (i = 0; i < me->totedge; i++, medge++) {
@ -405,51 +400,50 @@ void BM_mesh_bm_from_me(
bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
/* -------------------------------------------------------------------- */
/* MSelect clears the array elements (avoid adding multiple times).
*
* Take care to keep this last and not use (v/e/ftable) after this.
*/
if (me->mselect && me->totselect != 0) {
BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv");
BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv");
BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv");
MSelect *msel;
#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
{
#pragma omp section
{ BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); }
#pragma omp section
{ BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); }
#pragma omp section
{ BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); }
if (ftable == NULL) {
ftable = MEM_mallocN(sizeof(BMFace **) * bm->totface, __func__);
BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)ftable, bm->totface);
}
MSelect *msel;
for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
BMElem **ele_p;
switch (msel->type) {
case ME_VSEL:
BM_select_history_store(bm, (BMElem *)vert_array[msel->index]);
ele_p = (BMElem **)&vtable[msel->index];
break;
case ME_ESEL:
BM_select_history_store(bm, (BMElem *)edge_array[msel->index]);
ele_p = (BMElem **)&etable[msel->index];
break;
case ME_FSEL:
BM_select_history_store(bm, (BMElem *)face_array[msel->index]);
ele_p = (BMElem **)&ftable[msel->index];
break;
default:
continue;
}
if (*ele_p != NULL) {
BM_select_history_store_notest(bm, *ele_p);
*ele_p = NULL;
}
}
MEM_freeN(vert_array);
MEM_freeN(edge_array);
MEM_freeN(face_array);
}
else {
me->totselect = 0;
if (me->mselect) {
MEM_freeN(me->mselect);
me->mselect = NULL;
}
BM_select_history_clear(bm);
}
MEM_freeN(vtable);
MEM_freeN(etable);
if (ftable) {
MEM_freeN(ftable);
}
}

View File

@ -994,7 +994,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
te = outliner_find_id(so, &so->tree, &obact->id);
if (obact->type == OB_ARMATURE) {
if (te != NULL && obact->type == OB_ARMATURE) {
/* traverse down the bone hierarchy in case of armature */
TreeElement *te_obact = te;

View File

@ -154,6 +154,9 @@ class Report:
def output(self):
# write intermediate data for single test
outdir = os.path.join(OUTDIR, self.testname)
if not os.path.exists(outdir):
os.makedirs(outdir)
f = open(os.path.join(outdir, "failed.data"), "w")
f.write(self.failed_tests)
f.close()