示例#1
0
文件: mball.c 项目: mcgrathd/blender
/* do not free mball itself */
void BKE_mball_free(MetaBall *mb)
{
    BKE_mball_unlink(mb);

    if (mb->adt) {
        BKE_animdata_free((ID *)mb);
        mb->adt = NULL;
    }
    if (mb->mat) MEM_freeN(mb->mat);
    BLI_freelistN(&mb->elems);
    if (mb->disp.first) BKE_displist_free(&mb->disp);
}
示例#2
0
static DerivedMesh *create_orco_dm(Scene *scene, Object *ob)
{
	DerivedMesh *dm;
	ListBase disp = {NULL, NULL};

	/* OrcoDM should be created from underformed disp lists */
	BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
	dm = CDDM_from_curve_displist(ob, &disp);

	BKE_displist_free(&disp);

	return dm;
}
void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
{
	Lattice *lt = ob->data;
	VirtualModifierData virtualModifierData;
	ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
	float (*vertexCos)[3] = NULL;
	int numVerts, editmode = (lt->editlatt != NULL);

	if (ob->curve_cache) {
		BKE_displist_free(&ob->curve_cache->disp);
	}
	else {
		ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
	}

	for (; md; md = md->next) {
		const ModifierTypeInfo *mti = modifierType_getInfo(md->type);

		md->scene = scene;
		
		if (!(md->mode & eModifierMode_Realtime)) continue;
		if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
		if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
		if (mti->type != eModifierTypeType_OnlyDeform) continue;

		if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
		mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0);
	}

	/* always displist to make this work like derivedmesh */
	if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
	
	{
		DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
		dl->type = DL_VERTS;
		dl->parts = 1;
		dl->nr = numVerts;
		dl->verts = (float *) vertexCos;
		
		BLI_addtail(&ob->curve_cache->disp, dl);
	}
}
示例#4
0
void BKE_displist_copy(ListBase *lbn, ListBase *lb)
{
	DispList *dln, *dl;

	BKE_displist_free(lbn);

	dl = lb->first;
	while (dl) {
		dln = MEM_dupallocN(dl);
		BLI_addtail(lbn, dln);
		dln->verts = MEM_dupallocN(dl->verts);
		dln->nors = MEM_dupallocN(dl->nors);
		dln->index = MEM_dupallocN(dl->index);

		if (dl->bevel_split) {
			dln->bevel_split = MEM_dupallocN(dl->bevel_split);
		}

		dl = dl->next;
	}
}
示例#5
0
void BKE_displist_make_mball(EvaluationContext *eval_ctx, Scene *scene, Object *ob)
{
	if (!ob || ob->type != OB_MBALL)
		return;

	if (ob == BKE_mball_basis_find(scene, ob)) {
		if (ob->curve_cache) {
			BKE_displist_free(&(ob->curve_cache->disp));
		}
		else {
			ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
		}

		BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp);
		BKE_mball_texspace_calc(ob);

		object_deform_mball(ob, &ob->curve_cache->disp);

		/* NOP for MBALLs anyway... */
		boundbox_displist_object(ob);
	}
}
示例#6
0
void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
{
	BPoint *bp;
	int i, u, v, w;
	float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0;
	float *co, (*vertexCos)[3] = NULL;
	
	/* vertex weight groups are just freed all for now */
	if (lt->dvert) {
		free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
		lt->dvert = NULL;
	}
	
	while (uNew * vNew * wNew > 32000) {
		if (uNew >= vNew && uNew >= wNew) uNew--;
		else if (vNew >= uNew && vNew >= wNew) vNew--;
		else wNew--;
	}

	vertexCos = MEM_mallocN(sizeof(*vertexCos) * uNew * vNew * wNew, "tmp_vcos");

	calc_lat_fudu(lt->flag, uNew, &fu, &du);
	calc_lat_fudu(lt->flag, vNew, &fv, &dv);
	calc_lat_fudu(lt->flag, wNew, &fw, &dw);

	/* If old size is different then resolution changed in interface,
	 * try to do clever reinit of points. Pretty simply idea, we just
	 * deform new verts by old lattice, but scaling them to match old
	 * size first.
	 */
	if (ltOb) {
		if (uNew != 1 && lt->pntsu != 1) {
			fu = lt->fu;
			du = (lt->pntsu - 1) * lt->du / (uNew - 1);
		}

		if (vNew != 1 && lt->pntsv != 1) {
			fv = lt->fv;
			dv = (lt->pntsv - 1) * lt->dv / (vNew - 1);
		}

		if (wNew != 1 && lt->pntsw != 1) {
			fw = lt->fw;
			dw = (lt->pntsw - 1) * lt->dw / (wNew - 1);
		}
	}

	co = vertexCos[0];
	for (w = 0, wc = fw; w < wNew; w++, wc += dw) {
		for (v = 0, vc = fv; v < vNew; v++, vc += dv) {
			for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) {
				co[0] = uc;
				co[1] = vc;
				co[2] = wc;
			}
		}
	}
	
	if (ltOb) {
		float mat[4][4];
		int typeu = lt->typeu, typev = lt->typev, typew = lt->typew;

		/* works best if we force to linear type (endpoints match) */
		lt->typeu = lt->typev = lt->typew = KEY_LINEAR;

		/* prevent using deformed locations */
		BKE_displist_free(&ltOb->disp);

		copy_m4_m4(mat, ltOb->obmat);
		unit_m4(ltOb->obmat);
		lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew * vNew * wNew, NULL, 1.0f);
		copy_m4_m4(ltOb->obmat, mat);

		lt->typeu = typeu;
		lt->typev = typev;
		lt->typew = typew;
	}

	lt->fu = fu;
	lt->fv = fv;
	lt->fw = fw;
	lt->du = du;
	lt->dv = dv;
	lt->dw = dw;

	lt->pntsu = uNew;
	lt->pntsv = vNew;
	lt->pntsw = wNew;

	MEM_freeN(lt->def);
	lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp");
	
	bp = lt->def;
	
	for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) {
		copy_v3_v3(bp->vec, vertexCos[i]);
	}

	MEM_freeN(vertexCos);
}
示例#7
0
static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
{
	const float z_up[3] = {0.0f, 0.0f, 1.0f};
	ListBase front, back;
	DispList *dl, *dlnew;
	float *fp, *fp1;
	int a, dpoly;

	BLI_listbase_clear(&front);
	BLI_listbase_clear(&back);

	dl = dispbase->first;
	while (dl) {
		if (dl->type == DL_SURF) {
			if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
				if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
					dlnew = MEM_callocN(sizeof(DispList), "filldisp");
					BLI_addtail(&front, dlnew);
					dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
					dlnew->nr = dl->parts;
					dlnew->parts = 1;
					dlnew->type = DL_POLY;
					dlnew->flag = DL_BACK_CURVE;
					dlnew->col = dl->col;
					dlnew->charidx = dl->charidx;

					fp = dl->verts;
					dpoly = 3 * dl->nr;

					a = dl->parts;
					while (a--) {
						copy_v3_v3(fp1, fp);
						fp1 += 3;
						fp += dpoly;
					}
				}
				if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
					dlnew = MEM_callocN(sizeof(DispList), "filldisp");
					BLI_addtail(&back, dlnew);
					dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
					dlnew->nr = dl->parts;
					dlnew->parts = 1;
					dlnew->type = DL_POLY;
					dlnew->flag = DL_FRONT_CURVE;
					dlnew->col = dl->col;
					dlnew->charidx = dl->charidx;

					fp = dl->verts + 3 * (dl->nr - 1);
					dpoly = 3 * dl->nr;

					a = dl->parts;
					while (a--) {
						copy_v3_v3(fp1, fp);
						fp1 += 3;
						fp += dpoly;
					}
				}
			}
		}
		dl = dl->next;
	}

	BKE_displist_fill(&front, dispbase, z_up, true);
	BKE_displist_fill(&back, dispbase, z_up, false);

	BKE_displist_free(&front);
	BKE_displist_free(&back);

	BKE_displist_fill(dispbase, dispbase, z_up, false);
}
示例#8
0
/* settings: 1 - preview, 2 - render
 *
 * The convention goes as following:
 *
 * - Passing original object with apply_modifiers=false will give a
 *   non-modified non-deformed mesh.
 *   The result mesh will point to datablocks from the original "domain". For
 *   example, materials will be original.
 *
 * - Passing original object with apply_modifiers=true will give a mesh which
 *   has all modifiers applied.
 *   The result mesh will point to datablocks from the original "domain". For
 *   example, materials will be original.
 *
 * - Passing evaluated object will ignore apply_modifiers argument, and the
 *   result always contains all modifiers applied.
 *   The result mesh will point to an evaluated datablocks. For example,
 *   materials will be an evaluated IDs from the dependency graph.
 */
Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
                               Main *bmain,
                               Scene *sce,
                               Object *ob,
                               const bool apply_modifiers,
                               const bool calc_undeformed)
{
  Mesh *tmpmesh;
  Curve *tmpcu = NULL, *copycu;
  int i;
  const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
  bool effective_apply_modifiers = apply_modifiers;
  bool do_mat_id_data_us = true;

  Object *object_input = ob;
  Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input);
  Object object_for_eval;

  if (object_eval == object_input) {
    /* Evaluated mesh contains all modifiers applied already.
     * The other types of object has them applied, but are stored in other
     * data structures than a mesh. So need to apply modifiers again on a
     * temporary copy before converting result to mesh. */
    if (object_input->type == OB_MESH) {
      effective_apply_modifiers = false;
    }
    else {
      effective_apply_modifiers = true;
    }
    object_for_eval = *object_eval;
  }
  else {
    if (apply_modifiers) {
      object_for_eval = *object_eval;
      if (object_for_eval.runtime.mesh_orig != NULL) {
        object_for_eval.data = object_for_eval.runtime.mesh_orig;
      }
    }
    else {
      object_for_eval = *object_input;
    }
  }

  const bool cage = !effective_apply_modifiers;

  /* perform the mesh extraction based on type */
  switch (object_for_eval.type) {
    case OB_FONT:
    case OB_CURVE:
    case OB_SURF: {
      ListBase dispbase = {NULL, NULL};
      Mesh *me_eval_final = NULL;
      int uv_from_orco;

      /* copies object and modifiers (but not the data) */
      Object *tmpobj;
      BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
      tmpcu = (Curve *)tmpobj->data;

      /* Copy cached display list, it might be needed by the stack evaluation.
       * Ideally stack should be able to use render-time display list, but doing
       * so is quite tricky and not safe so close to the release.
       *
       * TODO(sergey): Look into more proper solution.
       */
      if (object_for_eval.runtime.curve_cache != NULL) {
        if (tmpobj->runtime.curve_cache == NULL) {
          tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache),
                                                    "CurveCache for curve types");
        }
        BKE_displist_copy(&tmpobj->runtime.curve_cache->disp,
                          &object_for_eval.runtime.curve_cache->disp);
      }

      /* if getting the original caged mesh, delete object modifiers */
      if (cage) {
        BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
      }

      /* copies the data, but *not* the shapekeys. */
      BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
      tmpobj->data = copycu;

      /* make sure texture space is calculated for a copy of curve,
       * it will be used for the final result.
       */
      BKE_curve_texspace_calc(copycu);

      /* temporarily set edit so we get updates from edit mode, but
       * also because for text datablocks copying it while in edit
       * mode gives invalid data structures */
      copycu->editfont = tmpcu->editfont;
      copycu->editnurb = tmpcu->editnurb;

      /* get updated display list, and convert to a mesh */
      BKE_displist_make_curveTypes_forRender(
          depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, NULL);

      copycu->editfont = NULL;
      copycu->editnurb = NULL;

      tmpobj->runtime.mesh_eval = me_eval_final;

      /* convert object type to mesh */
      uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
      BKE_mesh_from_nurbs_displist(
          bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
      /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */
      copycu = NULL;

      tmpmesh = tmpobj->data;
      id_us_min(
          &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */

      BKE_displist_free(&dispbase);

      /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked.
       * if it didn't the curve did not have any segments or otherwise
       * would have generated an empty mesh */
      if (tmpobj->type != OB_MESH) {
        BKE_id_free(NULL, tmpobj);
        return NULL;
      }

      BKE_id_free(NULL, tmpobj);

      /* XXX The curve to mesh conversion is convoluted...
       *     But essentially, BKE_mesh_from_nurbs_displist()
       *     already transfers the ownership of materials from the temp copy of the Curve ID to the
       *     new Mesh ID, so we do not want to increase materials' usercount later. */
      do_mat_id_data_us = false;

      break;
    }

    case OB_MBALL: {
      /* metaballs don't have modifiers, so just convert to mesh */
      Object *basis_ob = BKE_mball_basis_find(sce, object_input);
      /* todo, re-generatre for render-res */
      /* metaball_polygonize(scene, ob) */

      if (basis_ob != object_input) {
        /* Only do basis metaball. */
        return NULL;
      }

      tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
      /* BKE_mesh_add gives us a user count we don't need */
      id_us_min(&tmpmesh->id);

      if (render) {
        ListBase disp = {NULL, NULL};
        BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp);
        BKE_mesh_from_metaball(&disp, tmpmesh);
        BKE_displist_free(&disp);
      }
      else {
        ListBase disp = {NULL, NULL};
        if (object_for_eval.runtime.curve_cache) {
          disp = object_for_eval.runtime.curve_cache->disp;
        }
        BKE_mesh_from_metaball(&disp, tmpmesh);
      }

      BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval);

      break;
    }
    case OB_MESH:
      /* copies object and modifiers (but not the data) */
      if (cage) {
        /* copies the data (but *not* the shapekeys). */
        Mesh *mesh = object_for_eval.data;
        BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
        /* XXX BKE_mesh_copy() already handles materials usercount. */
        do_mat_id_data_us = false;
      }
      /* if not getting the original caged mesh, get final derived mesh */
      else {
        /* Make a dummy mesh, saves copying */
        Mesh *me_eval;
        CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
                                                   * for example, needs CD_MASK_MDEFORMVERT */

        if (calc_undeformed) {
          mask.vmask |= CD_MASK_ORCO;
        }

        if (render) {
          me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask);
        }
        else {
          me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask);
        }

        tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
        BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true);

        /* Copy autosmooth settings from original mesh. */
        Mesh *me = (Mesh *)object_for_eval.data;
        tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
        tmpmesh->smoothresh = me->smoothresh;
      }

      /* BKE_mesh_add/copy gives us a user count we don't need */
      id_us_min(&tmpmesh->id);

      break;
    default:
      /* "Object does not have geometry data") */
      return NULL;
  }

  /* Copy materials to new mesh */
  switch (object_for_eval.type) {
    case OB_SURF:
    case OB_FONT:
    case OB_CURVE:
      tmpmesh->totcol = tmpcu->totcol;

      /* free old material list (if it exists) and adjust user counts */
      if (tmpcu->mat) {
        for (i = tmpcu->totcol; i-- > 0;) {
          /* are we an object material or data based? */
          tmpmesh->mat[i] = give_current_material(object_input, i + 1);

          if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
              tmpmesh->mat[i]) {
            id_us_plus(&tmpmesh->mat[i]->id);
          }
        }
      }
      break;

    case OB_MBALL: {
      MetaBall *tmpmb = (MetaBall *)object_for_eval.data;
      tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
      tmpmesh->totcol = tmpmb->totcol;

      /* free old material list (if it exists) and adjust user counts */
      if (tmpmb->mat) {
        for (i = tmpmb->totcol; i-- > 0;) {
          /* are we an object material or data based? */
          tmpmesh->mat[i] = give_current_material(object_input, i + 1);

          if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
              tmpmesh->mat[i]) {
            id_us_plus(&tmpmesh->mat[i]->id);
          }
        }
      }
      break;
    }

    case OB_MESH:
      if (!cage) {
        Mesh *origmesh = object_for_eval.data;
        tmpmesh->flag = origmesh->flag;
        tmpmesh->mat = MEM_dupallocN(origmesh->mat);
        tmpmesh->totcol = origmesh->totcol;
        tmpmesh->smoothresh = origmesh->smoothresh;
        if (origmesh->mat) {
          for (i = origmesh->totcol; i-- > 0;) {
            /* are we an object material or data based? */
            tmpmesh->mat[i] = give_current_material(object_input, i + 1);

            if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
                tmpmesh->mat[i]) {
              id_us_plus(&tmpmesh->mat[i]->id);
            }
          }
        }
      }
      break;
  } /* end copy materials */

  return tmpmesh;
}
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq)
{
	PyObject *tri_list; /*return this list of tri's */
	PyObject *polyLine, *polyVec;
	int i, len_polylines, len_polypoints, ls_error = 0;

	/* display listbase */
	ListBase dispbase = {NULL, NULL};
	DispList *dl;
	float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
	int index, *dl_face, totpoints = 0;

	if (!PySequence_Check(polyLineSeq)) {
		PyErr_SetString(PyExc_TypeError,
		                "expected a sequence of poly lines");
		return NULL;
	}

	len_polylines = PySequence_Size(polyLineSeq);

	for (i = 0; i < len_polylines; i++) {
		polyLine = PySequence_GetItem(polyLineSeq, i);
		if (!PySequence_Check(polyLine)) {
			BKE_displist_free(&dispbase);
			Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
			PyErr_SetString(PyExc_TypeError,
			                "One or more of the polylines is not a sequence of mathutils.Vector's");
			return NULL;
		}

		len_polypoints = PySequence_Size(polyLine);
		if (len_polypoints > 0) { /* don't bother adding edges as polylines */
#if 0
			if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) {
				freedisplist(&dispbase);
				Py_DECREF(polyLine);
				PyErr_SetString(PyExc_TypeError,
				                "A point in one of the polylines is not a mathutils.Vector type");
				return NULL;
			}
#endif
			dl = MEM_callocN(sizeof(DispList), "poly disp");
			BLI_addtail(&dispbase, dl);
			dl->type = DL_INDEX3;
			dl->nr = len_polypoints;
			dl->type = DL_POLY;
			dl->parts = 1; /* no faces, 1 edge loop */
			dl->col = 0; /* no material */
			dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts");
			dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index");

			for (index = 0; index < len_polypoints; index++, fp += 3) {
				polyVec = PySequence_GetItem(polyLine, index);
				if (VectorObject_Check(polyVec)) {

					if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1)
						ls_error = 1;

					fp[0] = ((VectorObject *)polyVec)->vec[0];
					fp[1] = ((VectorObject *)polyVec)->vec[1];
					if (((VectorObject *)polyVec)->size > 2)
						fp[2] = ((VectorObject *)polyVec)->vec[2];
					else
						fp[2] = 0.0f;  /* if its a 2d vector then set the z to be zero */
				}
				else {
					ls_error = 1;
				}

				totpoints++;
				Py_DECREF(polyVec);
			}
		}
		Py_DECREF(polyLine);
	}

	if (ls_error) {
		BKE_displist_free(&dispbase); /* possible some dl was allocated */
		PyErr_SetString(PyExc_TypeError,
		                "A point in one of the polylines "
		                "is not a mathutils.Vector type");
		return NULL;
	}
	else if (totpoints) {
		/* now make the list to return */
		BKE_displist_fill(&dispbase, &dispbase, 0);

		/* The faces are stored in a new DisplayList
		 * thats added to the head of the listbase */
		dl = dispbase.first;

		tri_list = PyList_New(dl->parts);
		if (!tri_list) {
			BKE_displist_free(&dispbase);
			PyErr_SetString(PyExc_RuntimeError,
			                "failed to make a new list");
			return NULL;
		}

		index = 0;
		dl_face = dl->index;
		while (index < dl->parts) {
			PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]));
			dl_face += 3;
			index++;
		}
		BKE_displist_free(&dispbase);
	}
	else {
		/* no points, do this so scripts don't barf */
		BKE_displist_free(&dispbase); /* possible some dl was allocated */
		tri_list = PyList_New(0);
	}

	return tri_list;
}