2003-12-08 13:30:04 +00:00
|
|
|
/** mball.c
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
2003-12-08 13:30:04 +00:00
|
|
|
* MetaBalls are created from a single Object (with a name without number in it),
|
|
|
|
* here the DispList and BoundBox also is located.
|
|
|
|
* All objects with the same name (but with a number in it) are added to this.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
2003-12-08 13:30:04 +00:00
|
|
|
* texture coordinates are patched within the displist
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* ***** BEGIN GPL/BL DUAL 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. The Blender
|
|
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
|
|
* about this.
|
|
|
|
*
|
|
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2003-12-08 13:30:04 +00:00
|
|
|
* Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
2003-12-08 13:48:20 +00:00
|
|
|
#include <ctype.h>
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_material_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_meta_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BKE_bad_level_calls.h"
|
|
|
|
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
|
|
|
|
/* #include "BKE_object.h" */
|
|
|
|
#include "BKE_scene.h"
|
|
|
|
#include "BKE_blender.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_displist.h"
|
|
|
|
#include "BKE_mball.h"
|
2005-07-18 19:59:51 +00:00
|
|
|
#include "BKE_object.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2002-11-25 12:02:15 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
/* Global variables */
|
|
|
|
|
|
|
|
float thresh= 0.6f;
|
|
|
|
int totelem=0;
|
|
|
|
MetaElem **mainb;
|
|
|
|
octal_tree *metaball_tree;
|
2002-10-12 11:37:38 +00:00
|
|
|
/* Functions */
|
|
|
|
|
|
|
|
void unlink_mball(MetaBall *mb)
|
|
|
|
{
|
|
|
|
int a;
|
|
|
|
|
|
|
|
for(a=0; a<mb->totcol; a++) {
|
|
|
|
if(mb->mat[a]) mb->mat[a]->id.us--;
|
|
|
|
mb->mat[a]= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* do not free mball itself */
|
2002-10-12 11:37:38 +00:00
|
|
|
void free_mball(MetaBall *mb)
|
|
|
|
{
|
|
|
|
unlink_mball(mb);
|
|
|
|
|
|
|
|
if(mb->mat) MEM_freeN(mb->mat);
|
|
|
|
if(mb->bb) MEM_freeN(mb->bb);
|
|
|
|
BLI_freelistN(&mb->elems);
|
|
|
|
if(mb->disp.first) freedisplist(&mb->disp);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaBall *add_mball()
|
|
|
|
{
|
|
|
|
MetaBall *mb;
|
|
|
|
|
|
|
|
mb= alloc_libblock(&G.main->mball, ID_MB, "Meta");
|
|
|
|
|
|
|
|
mb->size[0]= mb->size[1]= mb->size[2]= 1.0;
|
2004-03-14 16:59:48 +00:00
|
|
|
mb->texflag= MB_AUTOSPACE;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
mb->wiresize= 0.4f;
|
|
|
|
mb->rendersize= 0.2f;
|
|
|
|
mb->thresh= 0.6f;
|
|
|
|
|
|
|
|
return mb;
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaBall *copy_mball(MetaBall *mb)
|
|
|
|
{
|
|
|
|
MetaBall *mbn;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
mbn= copy_libblock(mb);
|
|
|
|
|
|
|
|
duplicatelist(&mbn->elems, &mb->elems);
|
|
|
|
|
|
|
|
mbn->mat= MEM_dupallocN(mb->mat);
|
|
|
|
for(a=0; a<mbn->totcol; a++) {
|
|
|
|
id_us_plus((ID *)mbn->mat[a]);
|
|
|
|
}
|
|
|
|
mbn->bb= MEM_dupallocN(mb->bb);
|
|
|
|
|
|
|
|
return mbn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void make_local_mball(MetaBall *mb)
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
MetaBall *mbn;
|
|
|
|
int local=0, lib=0;
|
2003-04-26 13:07:59 +00:00
|
|
|
|
|
|
|
/* - only lib users: do nothing
|
|
|
|
* - only local users: set flag
|
|
|
|
* - mixed: make copy
|
2002-10-12 11:37:38 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
if(mb->id.lib==0) return;
|
|
|
|
if(mb->id.us==1) {
|
|
|
|
mb->id.lib= 0;
|
|
|
|
mb->id.flag= LIB_LOCAL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ob= G.main->object.first;
|
|
|
|
while(ob) {
|
|
|
|
if(ob->data==mb) {
|
|
|
|
if(ob->id.lib) lib= 1;
|
|
|
|
else local= 1;
|
|
|
|
}
|
|
|
|
ob= ob->id.next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(local && lib==0) {
|
|
|
|
mb->id.lib= 0;
|
|
|
|
mb->id.flag= LIB_LOCAL;
|
|
|
|
}
|
|
|
|
else if(local && lib) {
|
|
|
|
mbn= copy_mball(mb);
|
|
|
|
mbn->id.us= 0;
|
|
|
|
|
|
|
|
ob= G.main->object.first;
|
|
|
|
while(ob) {
|
|
|
|
if(ob->data==mb) {
|
|
|
|
|
|
|
|
if(ob->id.lib==0) {
|
|
|
|
ob->data= mbn;
|
|
|
|
mbn->id.us++;
|
|
|
|
mb->id.us--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ob= ob->id.next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-12-08 13:30:04 +00:00
|
|
|
/** Compute bounding box of all MetaElems/MetaBalls.
|
|
|
|
*
|
|
|
|
* Bounding box is computed from polygonized surface. Object *ob is
|
|
|
|
* basic MetaBall (usaualy with name Meta). All other MetaBalls (whith
|
|
|
|
* names Meta.001, Meta.002, etc) are included in this Bounding Box.
|
|
|
|
*/
|
2002-10-12 11:37:38 +00:00
|
|
|
void tex_space_mball(Object *ob)
|
|
|
|
{
|
|
|
|
DispList *dl;
|
|
|
|
BoundBox *bb;
|
|
|
|
float *data, min[3], max[3], loc[3], size[3];
|
|
|
|
int tot, doit=0;
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if(ob->bb==0) ob->bb= MEM_callocN(sizeof(BoundBox), "mb boundbox");
|
|
|
|
bb= ob->bb;
|
|
|
|
|
|
|
|
/* Weird one, this. */
|
|
|
|
/* INIT_MINMAX(min, max); */
|
|
|
|
(min)[0]= (min)[1]= (min)[2]= 1.0e30f;
|
|
|
|
(max)[0]= (max)[1]= (max)[2]= -1.0e30f;
|
|
|
|
|
|
|
|
dl= ob->disp.first;
|
|
|
|
while(dl) {
|
|
|
|
tot= dl->nr;
|
|
|
|
if(tot) doit= 1;
|
|
|
|
data= dl->verts;
|
|
|
|
while(tot--) {
|
|
|
|
/* Also weird... but longer. From utildefines. */
|
|
|
|
DO_MINMAX(data, min, max);
|
|
|
|
data+= 3;
|
|
|
|
}
|
|
|
|
dl= dl->next;
|
|
|
|
}
|
|
|
|
|
2005-07-18 17:33:51 +00:00
|
|
|
if(!doit) {
|
|
|
|
min[0] = min[1] = min[2] = -1.0f;
|
|
|
|
max[0] = max[1] = max[2] = 1.0f;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2005-07-18 17:33:51 +00:00
|
|
|
loc[0]= (min[0]+max[0])/2.0f;
|
|
|
|
loc[1]= (min[1]+max[1])/2.0f;
|
|
|
|
loc[2]= (min[2]+max[2])/2.0f;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2005-07-18 17:33:51 +00:00
|
|
|
size[0]= (max[0]-min[0])/2.0f;
|
|
|
|
size[1]= (max[1]-min[1])/2.0f;
|
|
|
|
size[2]= (max[2]-min[2])/2.0f;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2005-07-18 17:33:51 +00:00
|
|
|
boundbox_set_from_min_max(bb, min, max);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void make_orco_mball(Object *ob)
|
|
|
|
{
|
|
|
|
BoundBox *bb;
|
|
|
|
DispList *dl;
|
|
|
|
float *data;
|
|
|
|
float loc[3], size[3];
|
|
|
|
int a;
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* restore size and loc */
|
2002-10-12 11:37:38 +00:00
|
|
|
bb= ob->bb;
|
|
|
|
loc[0]= (bb->vec[0][0]+bb->vec[4][0])/2.0f;
|
|
|
|
size[0]= bb->vec[4][0]-loc[0];
|
|
|
|
loc[1]= (bb->vec[0][1]+bb->vec[2][1])/2.0f;
|
|
|
|
size[1]= bb->vec[2][1]-loc[1];
|
|
|
|
loc[2]= (bb->vec[0][2]+bb->vec[1][2])/2.0f;
|
|
|
|
size[2]= bb->vec[1][2]-loc[2];
|
|
|
|
|
|
|
|
dl= ob->disp.first;
|
|
|
|
data= dl->verts;
|
|
|
|
a= dl->nr;
|
|
|
|
while(a--) {
|
|
|
|
data[0]= (data[0]-loc[0])/size[0];
|
|
|
|
data[1]= (data[1]-loc[1])/size[1];
|
|
|
|
data[2]= (data[2]-loc[2])/size[2];
|
|
|
|
|
|
|
|
data+= 3;
|
|
|
|
}
|
|
|
|
}
|
2003-12-08 13:30:04 +00:00
|
|
|
/** \brief Test, if Object *ob is basic MetaBall.
|
|
|
|
*
|
|
|
|
* It test last character of Object ID name. If last character
|
|
|
|
* is digit it return 0, else it return 1.
|
|
|
|
*/
|
2003-11-21 12:30:15 +00:00
|
|
|
int is_basis_mball(Object *ob)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
/* just a quick test */
|
|
|
|
len= strlen(ob->id.name);
|
|
|
|
if( isdigit(ob->id.name[len-1]) ) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-12-08 13:30:04 +00:00
|
|
|
/** \brief This function finds basic MetaBall.
|
|
|
|
*
|
|
|
|
* Basic MetaBall doesn't include any number at the end of
|
|
|
|
* its name. All MetaBalls with same base of name can be
|
|
|
|
* blended. MetaBalls with different basic name can't be
|
|
|
|
* blended.
|
|
|
|
*/
|
2002-10-12 11:37:38 +00:00
|
|
|
Object *find_basis_mball(Object *basis)
|
|
|
|
{
|
|
|
|
Base *base;
|
2004-11-10 13:20:13 +00:00
|
|
|
Object *ob,*bob= basis;
|
|
|
|
MetaElem *ml=NULL;
|
|
|
|
int basisnr, obnr;
|
|
|
|
char basisname[32], obname[32];
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
splitIDname(basis->id.name+2, basisname, &basisnr);
|
2004-11-10 13:20:13 +00:00
|
|
|
totelem= 0;
|
|
|
|
|
|
|
|
next_object(0, 0, 0);
|
|
|
|
while(next_object(1, &base, &ob)) {
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if (ob->type==OB_MBALL) {
|
|
|
|
if(ob==bob){
|
|
|
|
/* if bob object is in edit mode, then dynamic list of all MetaElems
|
|
|
|
* is stored in editelems */
|
|
|
|
if(ob==G.obedit) ml= editelems.first;
|
2006-08-09 08:53:21 +00:00
|
|
|
/* keep track of linked data too! */
|
|
|
|
else if(G.obedit && G.obedit->data==ob->data) ml= editelems.first;
|
2004-11-10 13:20:13 +00:00
|
|
|
/* if bob object is in object mode */
|
|
|
|
else ml= ((MetaBall*)ob->data)->elems.first;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
splitIDname(ob->id.name+2, obname, &obnr);
|
|
|
|
|
|
|
|
/* object ob has to be in same "group" ... it means, that it has to have
|
|
|
|
* same base of its name */
|
|
|
|
if(strcmp(obname, basisname)==0){
|
|
|
|
/* if object is in edit mode, then dynamic list of all MetaElems
|
|
|
|
* is stored in editelems */
|
|
|
|
if(ob==G.obedit) ml= editelems.first;
|
|
|
|
/* keep track of linked data too! */
|
|
|
|
else if(bob==G.obedit && bob->data==ob->data) ml= editelems.first;
|
|
|
|
/* object is in object mode */
|
|
|
|
else ml= ((MetaBall*)ob->data)->elems.first;
|
|
|
|
|
|
|
|
if(obnr<basisnr){
|
2004-11-20 11:59:44 +00:00
|
|
|
if(!(ob->flag & OB_FROMDUPLI)){
|
|
|
|
basis= ob;
|
|
|
|
basisnr= obnr;
|
|
|
|
}
|
2004-11-10 13:20:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
while(ml){
|
2005-02-21 10:40:30 +00:00
|
|
|
if(!(ml->flag & MB_HIDE)) totelem++;
|
2004-11-10 13:20:13 +00:00
|
|
|
ml= ml->next;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return basis;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ******************** ARITH ************************* */
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* BASED AT CODE (but mostly rewritten) :
|
2002-10-12 11:37:38 +00:00
|
|
|
* C code from the article
|
|
|
|
* "An Implicit Surface Polygonizer"
|
|
|
|
* by Jules Bloomenthal, jbloom@beauty.gmu.edu
|
|
|
|
* in "Graphics Gems IV", Academic Press, 1994
|
|
|
|
|
|
|
|
* Authored by Jules Bloomenthal, Xerox PARC.
|
|
|
|
* Copyright (c) Xerox Corporation, 1991. All rights reserved.
|
|
|
|
* Permission is granted to reproduce, use and distribute this code for
|
|
|
|
* any and all purposes, provided that this notice appears in all copies. */
|
|
|
|
|
|
|
|
#define RES 12 /* # converge iterations */
|
|
|
|
|
|
|
|
#define L 0 /* left direction: -x, -i */
|
|
|
|
#define R 1 /* right direction: +x, +i */
|
|
|
|
#define B 2 /* bottom direction: -y, -j */
|
|
|
|
#define T 3 /* top direction: +y, +j */
|
|
|
|
#define N 4 /* near direction: -z, -k */
|
|
|
|
#define F 5 /* far direction: +z, +k */
|
|
|
|
#define LBN 0 /* left bottom near corner */
|
|
|
|
#define LBF 1 /* left bottom far corner */
|
|
|
|
#define LTN 2 /* left top near corner */
|
|
|
|
#define LTF 3 /* left top far corner */
|
|
|
|
#define RBN 4 /* right bottom near corner */
|
|
|
|
#define RBF 5 /* right bottom far corner */
|
|
|
|
#define RTN 6 /* right top near corner */
|
|
|
|
#define RTF 7 /* right top far corner */
|
|
|
|
|
|
|
|
/* the LBN corner of cube (i, j, k), corresponds with location
|
|
|
|
* (start.x+(i-0.5)*size, start.y+(j-0.5)*size, start.z+(k-0.5)*size) */
|
|
|
|
|
|
|
|
#define HASHBIT (5)
|
2003-12-08 13:30:04 +00:00
|
|
|
#define HASHSIZE (size_t)(1<<(3*HASHBIT)) /*! < hash table size (32768) */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
#define HASH(i,j,k) ((((( (i) & 31)<<5) | ( (j) & 31))<<5 ) | ( (k) & 31) )
|
|
|
|
|
|
|
|
#define MB_BIT(i, bit) (((i)>>(bit))&1)
|
|
|
|
#define FLIP(i,bit) ((i)^1<<(bit)) /* flip the given bit of i */
|
|
|
|
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
/* **************** POLYGONIZATION ************************ */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
void calc_mballco(MetaElem *ml, float *vec)
|
|
|
|
{
|
|
|
|
if(ml->mat) {
|
2005-03-09 19:45:59 +00:00
|
|
|
Mat4MulVecfl((float ( * )[4])ml->mat, vec);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float densfunc(MetaElem *ball, float x, float y, float z)
|
|
|
|
{
|
|
|
|
float dist2 = 0.0, dx, dy, dz;
|
|
|
|
float vec[3];
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
vec[0]= x;
|
|
|
|
vec[1]= y;
|
|
|
|
vec[2]= z;
|
2005-03-09 19:45:59 +00:00
|
|
|
Mat4MulVecfl((float ( * )[4])ball->imat, vec);
|
2004-06-29 17:10:13 +00:00
|
|
|
dx= vec[0];
|
|
|
|
dy= vec[1];
|
|
|
|
dz= vec[2];
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if(ball->type==MB_BALL) {
|
|
|
|
}
|
2003-09-05 13:54:22 +00:00
|
|
|
else if(ball->type==MB_TUBEX) {
|
|
|
|
if( dx > ball->len) dx-= ball->len;
|
|
|
|
else if(dx< -ball->len) dx+= ball->len;
|
|
|
|
else dx= 0.0;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2003-09-05 13:54:22 +00:00
|
|
|
else if(ball->type==MB_TUBEY) {
|
|
|
|
if( dy > ball->len) dy-= ball->len;
|
|
|
|
else if(dy< -ball->len) dy+= ball->len;
|
|
|
|
else dy= 0.0;
|
|
|
|
}
|
|
|
|
else if(ball->type==MB_TUBEZ) {
|
|
|
|
if( dz > ball->len) dz-= ball->len;
|
|
|
|
else if(dz< -ball->len) dz+= ball->len;
|
|
|
|
else dz= 0.0;
|
|
|
|
}
|
|
|
|
else if(ball->type==MB_TUBE) {
|
|
|
|
if( dx > ball->expx) dx-= ball->expx;
|
|
|
|
else if(dx< -ball->expx) dx+= ball->expx;
|
|
|
|
else dx= 0.0;
|
|
|
|
}
|
|
|
|
else if(ball->type==MB_PLANE) {
|
|
|
|
if( dx > ball->expx) dx-= ball->expx;
|
|
|
|
else if(dx< -ball->expx) dx+= ball->expx;
|
|
|
|
else dx= 0.0;
|
|
|
|
if( dy > ball->expy) dy-= ball->expy;
|
|
|
|
else if(dy< -ball->expy) dy+= ball->expy;
|
|
|
|
else dy= 0.0;
|
|
|
|
}
|
|
|
|
else if(ball->type==MB_ELIPSOID) {
|
|
|
|
dx *= 1/ball->expx;
|
|
|
|
dy *= 1/ball->expy;
|
|
|
|
dz *= 1/ball->expz;
|
|
|
|
}
|
|
|
|
else if(ball->type==MB_CUBE) {
|
|
|
|
if( dx > ball->expx) dx-= ball->expx;
|
|
|
|
else if(dx< -ball->expx) dx+= ball->expx;
|
|
|
|
else dx= 0.0;
|
|
|
|
if( dy > ball->expy) dy-= ball->expy;
|
|
|
|
else if(dy< -ball->expy) dy+= ball->expy;
|
|
|
|
else dy= 0.0;
|
|
|
|
if( dz > ball->expz) dz-= ball->expz;
|
|
|
|
else if(dz< -ball->expz) dz+= ball->expz;
|
|
|
|
else dz= 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dist2= (dx*dx + dy*dy + dz*dz);
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if(ball->flag & MB_NEGATIVE) {
|
|
|
|
dist2= 1.0f-(dist2/ball->rad2);
|
|
|
|
if(dist2 < 0.0) return 0.5f;
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return 0.5f-ball->s*dist2*dist2*dist2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dist2= 1.0f-(dist2/ball->rad2);
|
|
|
|
if(dist2 < 0.0) return -0.5f;
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return ball->s*dist2*dist2*dist2 -0.5f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
octal_node* find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth)
|
|
|
|
{
|
|
|
|
if(!depth) return node;
|
|
|
|
|
|
|
|
if(z < node->z){
|
|
|
|
if(y < node->y){
|
|
|
|
if(x < node->x){
|
|
|
|
if(node->nodes[0])
|
|
|
|
return find_metaball_octal_node(node->nodes[0],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(node->nodes[1])
|
|
|
|
return find_metaball_octal_node(node->nodes[1],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(x < node->x){
|
|
|
|
if(node->nodes[3])
|
|
|
|
return find_metaball_octal_node(node->nodes[3],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(node->nodes[2])
|
|
|
|
return find_metaball_octal_node(node->nodes[2],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(y < node->y){
|
|
|
|
if(x < node->x){
|
|
|
|
if(node->nodes[4])
|
|
|
|
return find_metaball_octal_node(node->nodes[4],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(node->nodes[5])
|
|
|
|
return find_metaball_octal_node(node->nodes[5],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(x < node->x){
|
|
|
|
if(node->nodes[7])
|
|
|
|
return find_metaball_octal_node(node->nodes[7],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(node->nodes[6])
|
|
|
|
return find_metaball_octal_node(node->nodes[6],x,y,z,depth--);
|
|
|
|
else
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
float metaball(float x, float y, float z)
|
|
|
|
/* float x, y, z; */
|
|
|
|
{
|
2004-06-29 17:10:13 +00:00
|
|
|
struct octal_node *node;
|
|
|
|
struct ml_pointer *ml_p;
|
2002-10-12 11:37:38 +00:00
|
|
|
float dens=0;
|
|
|
|
int a;
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
if(totelem > 1){
|
|
|
|
node= find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth);
|
|
|
|
if(node){
|
|
|
|
ml_p= node->elems.first;
|
|
|
|
|
|
|
|
while(ml_p){
|
|
|
|
dens+=densfunc(ml_p->ml, x, y, z);
|
|
|
|
ml_p= ml_p->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
dens+= -0.5*(metaball_tree->pos - node->pos);
|
|
|
|
dens+= 0.5*(metaball_tree->neg - node->neg);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
for(a=0; a<totelem; a++) {
|
|
|
|
dens+= densfunc( mainb[a], x, y, z);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
dens+= densfunc( mainb[0], x, y, z);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return thresh - dens;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************************************** */
|
|
|
|
|
2006-11-20 21:25:02 +00:00
|
|
|
int *indices=NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
int totindex, curindex;
|
|
|
|
|
|
|
|
|
|
|
|
void accum_mballfaces(int i1, int i2, int i3, int i4)
|
|
|
|
{
|
|
|
|
int *newi, *cur;
|
|
|
|
/* static int i=0; I would like to delete altogether, but I don't dare to, yet */
|
|
|
|
|
|
|
|
if(totindex==curindex) {
|
|
|
|
totindex+= 256;
|
|
|
|
newi= MEM_mallocN(4*sizeof(int)*totindex, "vertindex");
|
|
|
|
|
|
|
|
if(indices) {
|
|
|
|
memcpy(newi, indices, 4*sizeof(int)*(totindex-256));
|
|
|
|
MEM_freeN(indices);
|
|
|
|
}
|
|
|
|
indices= newi;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur= indices+4*curindex;
|
|
|
|
|
2006-11-20 21:25:02 +00:00
|
|
|
/* diplists now support array drawing, we treat trias as fake quad */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
cur[0]= i1;
|
|
|
|
cur[1]= i2;
|
|
|
|
cur[2]= i3;
|
2006-11-20 21:25:02 +00:00
|
|
|
if(i4==0)
|
|
|
|
cur[3]= i3;
|
|
|
|
else
|
|
|
|
cur[3]= i4;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
curindex++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************* MEMORY MANAGEMENT *********************** */
|
|
|
|
void *new_pgn_element(int size)
|
|
|
|
{
|
2003-04-26 13:07:59 +00:00
|
|
|
/* during polygonize 1000s of elements are allocated
|
|
|
|
* and never freed inbetween. Freeing only done at the end.
|
2002-10-12 11:37:38 +00:00
|
|
|
*/
|
|
|
|
int blocksize= 16384;
|
2003-04-26 13:07:59 +00:00
|
|
|
static int offs= 0; /* the current free address */
|
2002-10-12 11:37:38 +00:00
|
|
|
static struct pgn_elements *cur= 0;
|
|
|
|
static ListBase lb= {0, 0};
|
|
|
|
void *adr;
|
|
|
|
|
|
|
|
if(size>10000 || size==0) {
|
|
|
|
printf("incorrect use of new_pgn_element\n");
|
|
|
|
}
|
|
|
|
else if(size== -1) {
|
|
|
|
cur= lb.first;
|
|
|
|
while(cur) {
|
|
|
|
MEM_freeN(cur->data);
|
|
|
|
cur= cur->next;
|
|
|
|
}
|
|
|
|
BLI_freelistN(&lb);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
size= 4*( (size+3)/4 );
|
|
|
|
|
|
|
|
if(cur) {
|
|
|
|
if(size+offs < blocksize) {
|
|
|
|
adr= (void *) (cur->data+offs);
|
|
|
|
offs+= size;
|
|
|
|
return adr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cur= MEM_callocN( sizeof(struct pgn_elements), "newpgn");
|
|
|
|
cur->data= MEM_callocN(blocksize, "newpgn");
|
|
|
|
BLI_addtail(&lb, cur);
|
|
|
|
|
|
|
|
offs= size;
|
|
|
|
return cur->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freepolygonize(PROCESS *p)
|
|
|
|
{
|
|
|
|
MEM_freeN(p->corners);
|
|
|
|
MEM_freeN(p->edges);
|
|
|
|
MEM_freeN(p->centers);
|
|
|
|
|
|
|
|
new_pgn_element(-1);
|
|
|
|
|
|
|
|
if(p->vertices.ptr) MEM_freeN(p->vertices.ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Cubical Polygonization (optional) ****/
|
|
|
|
|
|
|
|
#define LB 0 /* left bottom edge */
|
|
|
|
#define LT 1 /* left top edge */
|
|
|
|
#define LN 2 /* left near edge */
|
|
|
|
#define LF 3 /* left far edge */
|
|
|
|
#define RB 4 /* right bottom edge */
|
|
|
|
#define RT 5 /* right top edge */
|
|
|
|
#define RN 6 /* right near edge */
|
|
|
|
#define RF 7 /* right far edge */
|
|
|
|
#define BN 8 /* bottom near edge */
|
|
|
|
#define BF 9 /* bottom far edge */
|
|
|
|
#define TN 10 /* top near edge */
|
|
|
|
#define TF 11 /* top far edge */
|
|
|
|
|
|
|
|
static INTLISTS *cubetable[256];
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
|
2002-10-12 11:37:38 +00:00
|
|
|
static int corner1[12] = {
|
|
|
|
LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF};
|
|
|
|
static int corner2[12] = {
|
|
|
|
LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF};
|
|
|
|
static int leftface[12] = {
|
|
|
|
B, L, L, F, R, T, N, R, N, B, T, F};
|
|
|
|
/* face on left when going corner1 to corner2 */
|
|
|
|
static int rightface[12] = {
|
|
|
|
L, T, N, L, B, R, R, F, B, F, N, T};
|
|
|
|
/* face on right when going corner1 to corner2 */
|
|
|
|
|
|
|
|
|
|
|
|
/* docube: triangulate the cube directly, without decomposition */
|
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
void docube(CUBE *cube, PROCESS *p, MetaBall *mb)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
INTLISTS *polys;
|
|
|
|
CORNER *c1, *c2;
|
|
|
|
int i, index = 0, count, indexar[8];
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<<i);
|
|
|
|
|
|
|
|
for (polys = cubetable[index]; polys; polys = polys->next) {
|
|
|
|
INTLIST *edges;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (edges = polys->list; edges; edges = edges->next) {
|
|
|
|
c1 = cube->corners[corner1[edges->i]];
|
|
|
|
c2 = cube->corners[corner2[edges->i]];
|
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
indexar[count] = vertid(c1, c2, p, mb);
|
2002-10-12 11:37:38 +00:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if(count>2) {
|
|
|
|
switch(count) {
|
|
|
|
case 3:
|
|
|
|
accum_mballfaces(indexar[2], indexar[1], indexar[0], 0);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
|
|
|
|
else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
|
|
|
|
else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
|
|
|
|
|
|
|
|
accum_mballfaces(indexar[4], indexar[3], indexar[0], 0);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if(indexar[0]==0) {
|
|
|
|
accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
|
|
|
|
accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
|
|
|
|
accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
if(indexar[0]==0) {
|
|
|
|
accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
|
|
|
|
accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
|
|
|
|
accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
accum_mballfaces(indexar[6], indexar[5], indexar[0], 0);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* testface: given cube at lattice (i, j, k), and four corners of face,
|
|
|
|
* if surface crosses face, compute other four corners of adjacent cube
|
|
|
|
* and add new cube to cube stack */
|
|
|
|
|
|
|
|
void testface(int i, int j, int k, CUBE* old, int bit, int c1, int c2, int c3, int c4, PROCESS *p)
|
|
|
|
{
|
|
|
|
CUBE newc;
|
|
|
|
CUBES *oldcubes = p->cubes;
|
|
|
|
CORNER *corn1, *corn2, *corn3, *corn4;
|
|
|
|
int n, pos;
|
|
|
|
|
|
|
|
corn1= old->corners[c1];
|
|
|
|
corn2= old->corners[c2];
|
|
|
|
corn3= old->corners[c3];
|
|
|
|
corn4= old->corners[c4];
|
|
|
|
|
|
|
|
pos = corn1->value > 0.0 ? 1 : 0;
|
|
|
|
|
|
|
|
/* test if no surface crossing */
|
|
|
|
if( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return;
|
|
|
|
/* test if cube out of bounds */
|
2003-08-09 17:09:11 +00:00
|
|
|
/*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/
|
2002-10-12 11:37:38 +00:00
|
|
|
/* test if already visited (always as last) */
|
|
|
|
if (setcenter(p->centers, i, j, k)) return;
|
|
|
|
|
|
|
|
|
|
|
|
/* create new cube and add cube to top of stack: */
|
|
|
|
p->cubes = (CUBES *) new_pgn_element(sizeof(CUBES));
|
|
|
|
p->cubes->next = oldcubes;
|
|
|
|
|
|
|
|
newc.i = i;
|
|
|
|
newc.j = j;
|
|
|
|
newc.k = k;
|
|
|
|
for (n = 0; n < 8; n++) newc.corners[n] = NULL;
|
|
|
|
|
|
|
|
newc.corners[FLIP(c1, bit)] = corn1;
|
|
|
|
newc.corners[FLIP(c2, bit)] = corn2;
|
|
|
|
newc.corners[FLIP(c3, bit)] = corn3;
|
|
|
|
newc.corners[FLIP(c4, bit)] = corn4;
|
|
|
|
|
|
|
|
if(newc.corners[0]==0) newc.corners[0] = setcorner(p, i, j, k);
|
|
|
|
if(newc.corners[1]==0) newc.corners[1] = setcorner(p, i, j, k+1);
|
|
|
|
if(newc.corners[2]==0) newc.corners[2] = setcorner(p, i, j+1, k);
|
|
|
|
if(newc.corners[3]==0) newc.corners[3] = setcorner(p, i, j+1, k+1);
|
|
|
|
if(newc.corners[4]==0) newc.corners[4] = setcorner(p, i+1, j, k);
|
|
|
|
if(newc.corners[5]==0) newc.corners[5] = setcorner(p, i+1, j, k+1);
|
|
|
|
if(newc.corners[6]==0) newc.corners[6] = setcorner(p, i+1, j+1, k);
|
|
|
|
if(newc.corners[7]==0) newc.corners[7] = setcorner(p, i+1, j+1, k+1);
|
|
|
|
|
|
|
|
p->cubes->cube= newc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setcorner: return corner with the given lattice location
|
|
|
|
set (and cache) its function value */
|
|
|
|
|
|
|
|
CORNER *setcorner (PROCESS* p, int i, int j, int k)
|
|
|
|
{
|
|
|
|
/* for speed, do corner value caching here */
|
|
|
|
CORNER *c;
|
|
|
|
int index;
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* does corner exist? */
|
2002-10-12 11:37:38 +00:00
|
|
|
index = HASH(i, j, k);
|
|
|
|
c = p->corners[index];
|
|
|
|
|
|
|
|
for (; c != NULL; c = c->next) {
|
|
|
|
if (c->i == i && c->j == j && c->k == k) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c = (CORNER *) new_pgn_element(sizeof(CORNER));
|
|
|
|
|
|
|
|
c->i = i;
|
|
|
|
c->x = p->start.x+((float)i-0.5f)*p->size;
|
|
|
|
c->j = j;
|
|
|
|
c->y = p->start.y+((float)j-0.5f)*p->size;
|
|
|
|
c->k = k;
|
|
|
|
c->z = p->start.z+((float)k-0.5f)*p->size;
|
|
|
|
c->value = p->function(c->x, c->y, c->z);
|
|
|
|
|
|
|
|
c->next = p->corners[index];
|
|
|
|
p->corners[index] = c;
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* nextcwedge: return next clockwise edge from given edge around given face */
|
|
|
|
|
|
|
|
int nextcwedge (int edge, int face)
|
|
|
|
{
|
|
|
|
switch (edge) {
|
|
|
|
case LB:
|
|
|
|
return (face == L)? LF : BN;
|
|
|
|
case LT:
|
|
|
|
return (face == L)? LN : TF;
|
|
|
|
case LN:
|
|
|
|
return (face == L)? LB : TN;
|
|
|
|
case LF:
|
|
|
|
return (face == L)? LT : BF;
|
|
|
|
case RB:
|
|
|
|
return (face == R)? RN : BF;
|
|
|
|
case RT:
|
|
|
|
return (face == R)? RF : TN;
|
|
|
|
case RN:
|
|
|
|
return (face == R)? RT : BN;
|
|
|
|
case RF:
|
|
|
|
return (face == R)? RB : TF;
|
|
|
|
case BN:
|
|
|
|
return (face == B)? RB : LN;
|
|
|
|
case BF:
|
|
|
|
return (face == B)? LB : RF;
|
|
|
|
case TN:
|
|
|
|
return (face == T)? LT : RN;
|
|
|
|
case TF:
|
|
|
|
return (face == T)? RT : LF;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* otherface: return face adjoining edge that is not the given face */
|
|
|
|
|
|
|
|
int otherface (int edge, int face)
|
|
|
|
{
|
|
|
|
int other = leftface[edge];
|
|
|
|
return face == other? rightface[edge] : other;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* makecubetable: create the 256 entry table for cubical polygonization */
|
|
|
|
|
|
|
|
void makecubetable (void)
|
|
|
|
{
|
|
|
|
static int isdone= 0;
|
|
|
|
int i, e, c, done[12], pos[8];
|
|
|
|
|
|
|
|
if(isdone) return;
|
|
|
|
isdone= 1;
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
for (e = 0; e < 12; e++) done[e] = 0;
|
|
|
|
for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
|
|
|
|
for (e = 0; e < 12; e++)
|
|
|
|
if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
|
|
|
|
INTLIST *ints = 0;
|
|
|
|
INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist");
|
|
|
|
int start = e, edge = e;
|
|
|
|
|
|
|
|
/* get face that is to right of edge from pos to neg corner: */
|
|
|
|
int face = pos[corner1[e]]? rightface[e] : leftface[e];
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
edge = nextcwedge(edge, face);
|
|
|
|
done[edge] = 1;
|
|
|
|
if (pos[corner1[edge]] != pos[corner2[edge]]) {
|
|
|
|
INTLIST *tmp = ints;
|
|
|
|
|
|
|
|
ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist");
|
|
|
|
ints->i = edge;
|
|
|
|
ints->next = tmp; /* add edge to head of list */
|
|
|
|
|
|
|
|
if (edge == start) break;
|
|
|
|
face = otherface(edge, face);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lists->list = ints; /* add ints to head of table entry */
|
|
|
|
lists->next = cubetable[i];
|
|
|
|
cubetable[i] = lists;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_freecubetable(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
INTLISTS *lists, *nlists;
|
|
|
|
INTLIST *ints, *nints;
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
lists= cubetable[i];
|
|
|
|
while(lists) {
|
|
|
|
nlists= lists->next;
|
|
|
|
|
|
|
|
ints= lists->list;
|
|
|
|
while(ints) {
|
|
|
|
nints= ints->next;
|
|
|
|
MEM_freeN(ints);
|
|
|
|
ints= nints;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(lists);
|
|
|
|
lists= nlists;
|
|
|
|
}
|
|
|
|
cubetable[i]= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Storage ****/
|
|
|
|
|
|
|
|
/* setcenter: set (i,j,k) entry of table[]
|
|
|
|
* return 1 if already set; otherwise, set and return 0 */
|
|
|
|
|
|
|
|
int setcenter(CENTERLIST *table[], int i, int j, int k)
|
|
|
|
{
|
|
|
|
int index;
|
|
|
|
CENTERLIST *newc, *l, *q;
|
|
|
|
|
|
|
|
index= HASH(i, j, k);
|
|
|
|
q= table[index];
|
|
|
|
|
|
|
|
for (l = q; l != NULL; l = l->next) {
|
|
|
|
if (l->i == i && l->j == j && l->k == k) return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
newc = (CENTERLIST *) new_pgn_element(sizeof(CENTERLIST));
|
|
|
|
newc->i = i;
|
|
|
|
newc->j = j;
|
|
|
|
newc->k = k;
|
|
|
|
newc->next = q;
|
|
|
|
table[index] = newc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* setedge: set vertex id for edge */
|
|
|
|
|
|
|
|
void setedge (EDGELIST *table[],
|
|
|
|
int i1, int j1,
|
|
|
|
int k1, int i2,
|
|
|
|
int j2, int k2,
|
|
|
|
int vid)
|
|
|
|
{
|
|
|
|
unsigned int index;
|
|
|
|
EDGELIST *newe;
|
|
|
|
|
|
|
|
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
|
|
|
|
int t=i1;
|
|
|
|
i1=i2;
|
|
|
|
i2=t;
|
|
|
|
t=j1;
|
|
|
|
j1=j2;
|
|
|
|
j2=t;
|
|
|
|
t=k1;
|
|
|
|
k1=k2;
|
|
|
|
k2=t;
|
|
|
|
}
|
|
|
|
index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
|
|
|
|
newe = (EDGELIST *) new_pgn_element(sizeof(EDGELIST));
|
|
|
|
newe->i1 = i1;
|
|
|
|
newe->j1 = j1;
|
|
|
|
newe->k1 = k1;
|
|
|
|
newe->i2 = i2;
|
|
|
|
newe->j2 = j2;
|
|
|
|
newe->k2 = k2;
|
|
|
|
newe->vid = vid;
|
|
|
|
newe->next = table[index];
|
|
|
|
table[index] = newe;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* getedge: return vertex id for edge; return -1 if not set */
|
|
|
|
|
|
|
|
int getedge (EDGELIST *table[],
|
|
|
|
int i1, int j1, int k1,
|
|
|
|
int i2, int j2, int k2)
|
|
|
|
{
|
|
|
|
EDGELIST *q;
|
|
|
|
|
|
|
|
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
|
|
|
|
int t=i1;
|
|
|
|
i1=i2;
|
|
|
|
i2=t;
|
|
|
|
t=j1;
|
|
|
|
j1=j2;
|
|
|
|
j2=t;
|
|
|
|
t=k1;
|
|
|
|
k1=k2;
|
|
|
|
k2=t;
|
|
|
|
}
|
|
|
|
q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)];
|
|
|
|
for (; q != NULL; q = q->next)
|
|
|
|
if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
|
|
|
|
q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
|
|
|
|
return q->vid;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**** Vertices ****/
|
|
|
|
|
|
|
|
#undef R
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* vertid: return index for vertex on edge:
|
|
|
|
* c1->value and c2->value are presumed of different sign
|
|
|
|
* return saved index if any; else compute vertex and save */
|
|
|
|
|
|
|
|
/* addtovertices: add v to sequence of vertices */
|
|
|
|
|
|
|
|
void addtovertices (VERTICES *vertices, VERTEX v)
|
|
|
|
{
|
|
|
|
if (vertices->count == vertices->max) {
|
|
|
|
int i;
|
|
|
|
VERTEX *newv;
|
|
|
|
vertices->max = vertices->count == 0 ? 10 : 2*vertices->count;
|
|
|
|
newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices");
|
|
|
|
|
|
|
|
for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i];
|
|
|
|
|
|
|
|
if (vertices->ptr != NULL) MEM_freeN(vertices->ptr);
|
|
|
|
vertices->ptr = newv;
|
|
|
|
}
|
|
|
|
vertices->ptr[vertices->count++] = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vnormal: compute unit length surface normal at point */
|
|
|
|
|
|
|
|
void vnormal (MB_POINT *point, PROCESS *p, MB_POINT *v)
|
|
|
|
{
|
|
|
|
float delta= 0.2f*p->delta;
|
|
|
|
float f = p->function(point->x, point->y, point->z);
|
|
|
|
|
|
|
|
v->x = p->function(point->x+delta, point->y, point->z)-f;
|
|
|
|
v->y = p->function(point->x, point->y+delta, point->z)-f;
|
|
|
|
v->z = p->function(point->x, point->y, point->z+delta)-f;
|
|
|
|
f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
|
|
|
|
|
|
|
|
if (f != 0.0) {
|
|
|
|
v->x /= f;
|
|
|
|
v->y /= f;
|
|
|
|
v->z /= f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(FALSE) {
|
|
|
|
MB_POINT temp;
|
|
|
|
|
|
|
|
delta*= 2.0;
|
|
|
|
|
|
|
|
f = p->function(point->x, point->y, point->z);
|
|
|
|
|
|
|
|
temp.x = p->function(point->x+delta, point->y, point->z)-f;
|
|
|
|
temp.y = p->function(point->x, point->y+delta, point->z)-f;
|
|
|
|
temp.z = p->function(point->x, point->y, point->z+delta)-f;
|
|
|
|
f = (float)sqrt(temp.x*temp.x + temp.y*temp.y + temp.z*temp.z);
|
|
|
|
|
|
|
|
if (f != 0.0) {
|
|
|
|
temp.x /= f;
|
|
|
|
temp.y /= f;
|
|
|
|
temp.z /= f;
|
|
|
|
|
|
|
|
v->x+= temp.x;
|
|
|
|
v->y+= temp.y;
|
|
|
|
v->z+= temp.z;
|
|
|
|
|
|
|
|
f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
|
|
|
|
|
|
|
|
if (f != 0.0) {
|
|
|
|
v->x /= f;
|
|
|
|
v->y /= f;
|
|
|
|
v->z /= f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
int vertid (CORNER *c1, CORNER *c2, PROCESS *p, MetaBall *mb)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
VERTEX v;
|
|
|
|
MB_POINT a, b;
|
|
|
|
int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
|
|
|
|
|
|
|
|
if (vid != -1) return vid; /* previously computed */
|
|
|
|
a.x = c1->x;
|
|
|
|
a.y = c1->y;
|
|
|
|
a.z = c1->z;
|
|
|
|
b.x = c2->x;
|
|
|
|
b.y = c2->y;
|
|
|
|
b.z = c2->z;
|
|
|
|
|
2003-12-08 13:30:04 +00:00
|
|
|
converge(&a, &b, c1->value, c2->value, p->function, &v.position, mb, 1); /* position */
|
2002-10-12 11:37:38 +00:00
|
|
|
vnormal(&v.position, p, &v.normal);
|
|
|
|
|
|
|
|
addtovertices(&p->vertices, v); /* save vertex */
|
|
|
|
vid = p->vertices.count-1;
|
|
|
|
setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
|
|
|
|
|
|
|
|
return vid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* converge: from two points of differing sign, converge to zero crossing */
|
|
|
|
/* watch it: p1 and p2 are used to calculate */
|
2003-09-05 13:54:22 +00:00
|
|
|
void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2,
|
2003-12-08 13:30:04 +00:00
|
|
|
float (*function)(float, float, float), MB_POINT *p, MetaBall *mb, int f)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
2003-12-08 13:30:04 +00:00
|
|
|
MB_POINT pos, neg;
|
2003-09-05 13:54:22 +00:00
|
|
|
float positive = 0.0f, negative = 0.0f;
|
|
|
|
float dx = 0.0f ,dy = 0.0f ,dz = 0.0f;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
if (v1 < 0) {
|
2003-12-08 13:30:04 +00:00
|
|
|
pos= *p2;
|
|
|
|
neg= *p1;
|
2003-09-05 13:54:22 +00:00
|
|
|
positive = v2;
|
|
|
|
negative = v1;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-12-08 13:30:04 +00:00
|
|
|
pos= *p1;
|
|
|
|
neg= *p2;
|
2003-09-05 13:54:22 +00:00
|
|
|
positive = v1;
|
|
|
|
negative = v2;
|
|
|
|
}
|
|
|
|
|
2003-12-08 13:30:04 +00:00
|
|
|
dx = pos.x - neg.x;
|
|
|
|
dy = pos.y - neg.y;
|
|
|
|
dz = pos.z - neg.z;
|
2003-09-05 13:54:22 +00:00
|
|
|
|
|
|
|
/* Aproximation by linear interpolation is faster then binary subdivision,
|
|
|
|
* but it results sometimes (mb->thresh < 0.2) into the strange results */
|
2003-12-08 13:30:04 +00:00
|
|
|
if((mb->thresh >0.2) && (f==1)){
|
2003-09-05 13:54:22 +00:00
|
|
|
if((dy == 0.0f) && (dz == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = neg.x - negative*dx/(positive-negative);
|
|
|
|
p->y = neg.y;
|
|
|
|
p->z = neg.z;
|
2003-09-05 13:54:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if((dx == 0.0f) && (dz == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = neg.x;
|
|
|
|
p->y = neg.y - negative*dy/(positive-negative);
|
|
|
|
p->z = neg.z;
|
2003-09-05 13:54:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if((dx == 0.0f) && (dy == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = neg.x;
|
|
|
|
p->y = neg.y;
|
|
|
|
p->z = neg.z - negative*dz/(positive-negative);
|
2003-09-05 13:54:22 +00:00
|
|
|
return;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2003-09-05 13:54:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if((dy == 0.0f) && (dz == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->y = neg.y;
|
|
|
|
p->z = neg.z;
|
2003-09-05 13:54:22 +00:00
|
|
|
while (1) {
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = 0.5f*(pos.x + neg.x);
|
2003-09-05 13:54:22 +00:00
|
|
|
if (i++ == RES) return;
|
2003-12-08 13:30:04 +00:00
|
|
|
if ((function(p->x,p->y,p->z)) > 0.0) pos.x = p->x; else neg.x = p->x;
|
2003-09-05 13:54:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((dx == 0.0f) && (dz == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = neg.x;
|
|
|
|
p->z = neg.z;
|
2003-09-05 13:54:22 +00:00
|
|
|
while (1) {
|
2003-12-08 13:30:04 +00:00
|
|
|
p->y = 0.5f*(pos.y + neg.y);
|
2003-09-05 13:54:22 +00:00
|
|
|
if (i++ == RES) return;
|
2003-12-08 13:30:04 +00:00
|
|
|
if ((function(p->x,p->y,p->z)) > 0.0) pos.y = p->y; else neg.y = p->y;
|
2003-09-05 13:54:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((dx == 0.0f) && (dy == 0.0f)){
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = neg.x;
|
|
|
|
p->y = neg.y;
|
2003-09-05 13:54:22 +00:00
|
|
|
while (1) {
|
2003-12-08 13:30:04 +00:00
|
|
|
p->z = 0.5f*(pos.z + neg.z);
|
2003-09-05 13:54:22 +00:00
|
|
|
if (i++ == RES) return;
|
2003-12-08 13:30:04 +00:00
|
|
|
if ((function(p->x,p->y,p->z)) > 0.0) pos.z = p->z; else neg.z = p->z;
|
2003-09-05 13:54:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is necessary to find start point */
|
2002-10-12 11:37:38 +00:00
|
|
|
while (1) {
|
2003-12-08 13:30:04 +00:00
|
|
|
p->x = 0.5f*(pos.x + neg.x);
|
|
|
|
p->y = 0.5f*(pos.y + neg.y);
|
|
|
|
p->z = 0.5f*(pos.z + neg.z);
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if (i++ == RES) return;
|
2003-09-05 13:54:22 +00:00
|
|
|
|
|
|
|
if ((function(p->x, p->y, p->z)) > 0.0){
|
2003-12-08 13:30:04 +00:00
|
|
|
pos.x = p->x;
|
|
|
|
pos.y = p->y;
|
|
|
|
pos.z = p->z;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2003-09-05 13:54:22 +00:00
|
|
|
else{
|
2003-12-08 13:30:04 +00:00
|
|
|
neg.x = p->x;
|
|
|
|
neg.y = p->y;
|
|
|
|
neg.z = p->z;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-12-08 13:30:04 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
/* ************************************** */
|
2003-12-08 13:30:04 +00:00
|
|
|
void add_cube(PROCESS *mbproc, int i, int j, int k, int count)
|
|
|
|
{
|
|
|
|
CUBES *ncube;
|
|
|
|
int n;
|
|
|
|
int a, b, c;
|
|
|
|
|
|
|
|
/* hmmm, not only one, but eight cube will be added on the stack
|
|
|
|
* ... */
|
|
|
|
for(a=i-1; a<i+count; a++)
|
|
|
|
for(b=j-1; b<j+count; b++)
|
|
|
|
for(c=k-1; c<k+count; c++) {
|
|
|
|
/* test if cube has been found before */
|
|
|
|
if( setcenter(mbproc->centers, a, b, c)==0 ) {
|
|
|
|
/* push cube on stack: */
|
|
|
|
ncube= (CUBES *) new_pgn_element(sizeof(CUBES));
|
|
|
|
ncube->next= mbproc->cubes;
|
|
|
|
mbproc->cubes= ncube;
|
|
|
|
|
|
|
|
ncube->cube.i= a;
|
|
|
|
ncube->cube.j= b;
|
|
|
|
ncube->cube.k= c;
|
|
|
|
|
|
|
|
/* set corners of initial cube: */
|
|
|
|
for (n = 0; n < 8; n++)
|
|
|
|
ncube->cube.corners[n] = setcorner(mbproc, a+MB_BIT(n,2), b+MB_BIT(n,1), c+MB_BIT(n,0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void find_first_points(PROCESS *mbproc, MetaBall *mb, int a)
|
|
|
|
{
|
|
|
|
MB_POINT IN, in, OUT, out; /*point;*/
|
|
|
|
MetaElem *ml;
|
|
|
|
int i, j, k, c_i, c_j, c_k;
|
|
|
|
int index[3]={1,0,-1};
|
|
|
|
float f =0.0f;
|
|
|
|
float in_v, out_v;
|
|
|
|
|
|
|
|
ml = mainb[a];
|
|
|
|
|
|
|
|
f = 1-(mb->thresh/ml->s);
|
|
|
|
|
|
|
|
/* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be
|
|
|
|
* visible alone ... but still can influence others MetaElements :-) */
|
|
|
|
if(f > 0.0) {
|
2005-04-27 11:52:50 +00:00
|
|
|
OUT.x = IN.x = in.x= 0.0;
|
|
|
|
OUT.y = IN.y = in.y= 0.0;
|
|
|
|
OUT.z = IN.z = in.z= 0.0;
|
2003-12-08 13:30:04 +00:00
|
|
|
|
|
|
|
calc_mballco(ml, (float *)&in);
|
|
|
|
in_v = mbproc->function(in.x, in.y, in.z);
|
|
|
|
|
|
|
|
for(i=0;i<3;i++){
|
|
|
|
switch (ml->type) {
|
|
|
|
case MB_BALL:
|
|
|
|
OUT.x = out.x= IN.x + index[i]*ml->rad;
|
|
|
|
break;
|
|
|
|
case MB_TUBE:
|
|
|
|
case MB_PLANE:
|
|
|
|
case MB_ELIPSOID:
|
|
|
|
case MB_CUBE:
|
|
|
|
OUT.x = out.x= IN.x + index[i]*(ml->expx + ml->rad);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(j=0;j<3;j++) {
|
|
|
|
switch (ml->type) {
|
|
|
|
case MB_BALL:
|
|
|
|
OUT.y = out.y= IN.y + index[j]*ml->rad;
|
|
|
|
break;
|
|
|
|
case MB_TUBE:
|
|
|
|
case MB_PLANE:
|
|
|
|
case MB_ELIPSOID:
|
|
|
|
case MB_CUBE:
|
|
|
|
OUT.y = out.y= IN.y + index[j]*(ml->expy + ml->rad);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(k=0;k<3;k++) {
|
|
|
|
out.x = OUT.x;
|
|
|
|
out.y = OUT.y;
|
|
|
|
switch (ml->type) {
|
|
|
|
case MB_BALL:
|
|
|
|
case MB_TUBE:
|
|
|
|
case MB_PLANE:
|
|
|
|
out.z= IN.z + index[k]*ml->rad;
|
|
|
|
break;
|
|
|
|
case MB_ELIPSOID:
|
|
|
|
case MB_CUBE:
|
|
|
|
out.z= IN.z + index[k]*(ml->expz + ml->rad);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
calc_mballco(ml, (float *)&out);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-12-08 13:30:04 +00:00
|
|
|
out_v = mbproc->function(out.x, out.y, out.z);
|
|
|
|
|
|
|
|
/* find "first point" on Implicit Surface of MetaElemnt ml */
|
|
|
|
converge(&in, &out, in_v, out_v, mbproc->function, &mbproc->start, mb, 0);
|
|
|
|
|
|
|
|
/* indexes of CUBE, which includes "first point" */
|
|
|
|
c_i= (int)floor(mbproc->start.x/mbproc->size );
|
|
|
|
c_j= (int)floor(mbproc->start.y/mbproc->size );
|
|
|
|
c_k= (int)floor(mbproc->start.z/mbproc->size );
|
|
|
|
|
|
|
|
mbproc->start.x= mbproc->start.y= mbproc->start.z= 0.0;
|
|
|
|
|
|
|
|
/* add CUBE (with indexes c_i, c_j, c_k) to the stack,
|
|
|
|
* this cube includes found point of Implicit Surface */
|
|
|
|
if (ml->flag & MB_NEGATIVE)
|
|
|
|
add_cube(mbproc, c_i, c_j, c_k, 2);
|
|
|
|
else
|
|
|
|
add_cube(mbproc, c_i, c_j, c_k, 1);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
void polygonize(PROCESS *mbproc, MetaBall *mb)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
CUBE c;
|
2003-12-08 13:30:04 +00:00
|
|
|
int a;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
mbproc->vertices.count = mbproc->vertices.max = 0;
|
|
|
|
mbproc->vertices.ptr = NULL;
|
|
|
|
|
|
|
|
/* allocate hash tables and build cube polygon table: */
|
|
|
|
mbproc->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
|
|
|
|
mbproc->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
|
|
|
|
mbproc->edges = MEM_callocN(2*HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
|
|
|
|
makecubetable();
|
|
|
|
|
|
|
|
for(a=0; a<totelem; a++) {
|
|
|
|
|
2003-12-08 13:30:04 +00:00
|
|
|
/* try to find 8 points on the surface for each MetaElem */
|
|
|
|
find_first_points(mbproc, mb, a);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2003-12-08 13:30:04 +00:00
|
|
|
|
|
|
|
/* polygonize all MetaElems of current MetaBall */
|
2002-10-12 11:37:38 +00:00
|
|
|
while (mbproc->cubes != NULL) { /* process active cubes till none left */
|
|
|
|
c = mbproc->cubes->cube;
|
|
|
|
|
|
|
|
/* polygonize the cube directly: */
|
2003-09-05 13:54:22 +00:00
|
|
|
docube(&c, mbproc, mb);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
/* pop current cube from stack */
|
|
|
|
mbproc->cubes = mbproc->cubes->next;
|
|
|
|
|
|
|
|
/* test six face directions, maybe add to stack: */
|
|
|
|
testface(c.i-1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF, mbproc);
|
|
|
|
testface(c.i+1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF, mbproc);
|
|
|
|
testface(c.i, c.j-1, c.k, &c, 1, LBN, LBF, RBN, RBF, mbproc);
|
|
|
|
testface(c.i, c.j+1, c.k, &c, 1, LTN, LTF, RTN, RTF, mbproc);
|
|
|
|
testface(c.i, c.j, c.k-1, &c, 0, LBN, LTN, RBN, RTN, mbproc);
|
|
|
|
testface(c.i, c.j, c.k+1, &c, 0, LBF, LTF, RBF, RTF, mbproc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float init_meta(Object *ob) /* return totsize */
|
|
|
|
{
|
|
|
|
Base *base;
|
|
|
|
Object *bob;
|
|
|
|
MetaBall *mb;
|
|
|
|
MetaElem *ml;
|
Big commit with work on Groups & Libraries:
-> Any Group Duplicate now can get local timing and local NLA override. This
enables to control the entire animation system of the Group.
Two methods for this have been implemented.
1) The quick way: just give the duplicator a "Startframe" offset.
2) Advanced: in the NLA Editor you can add ActionStrips to the duplicator
to override NLA/action of any Grouped Object.
For "Group NLA" to work, an ActionStrip needs to know which Object in a
group it controls. On adding a strip, the code checks if an Action was
already used by an Object in the Group, and assigns it automatic to that
Object.
You can also set this in the Nkey "Properties" panel for the strip.
Change in NLA: the SHIFT+A "Add strip" command now always adds strips to
the active Object. (It used to check where mouse was). This allows to add
NLA strips to Objects that didn't have actions/nla yet.
Important note: In Blender, duplicates are fully procedural and generated
on the fly for each redraw. This means that redraw speed equals to stepping
through frames, when using animated Duplicated Groups.
-> Recoded entire duplicator system
The old method was antique and clumsy, using globals and full temporal
copies of Object. The new system is nicer in control, faster, and since it
doesn't use temporal object copies anymore, it works better with Derived
Mesh and DisplayList and rendering.
By centralizing the code for duplicating, more options can be easier added.
Features to note:
- Duplicates now draw selected/unselected based on its Duplicator setting.
- Same goes for the drawtype (wire, solid, selection outline, etc)
- Duplicated Groups can be normally selected too
Bonus goodie: SHIFT+A (Toolbox) now has entry "Add group" too, with a
listing of all groups, allowing to add Group instances immediate.
-> Library System
- SHIFT+F4 data browse now shows the entire path for linked data
- Outliner draws Library Icons to denote linked data
- Outliner operation added: "Make Local" for library data.
- Outliner now also draws Groups in regular view, allowing to unlink too.
-> Fixes
- depsgraph missed signal update for bone-parented Objects
- on reading file, the entire database was tagged to "recalc" fully,
causing unnecessary slowdown on reading.
Might have missed stuff... :)
2005-12-11 13:23:30 +00:00
|
|
|
float size, totsize, (*mat)[4] = NULL, (*imat)[4] = NULL, obinv[4][4], obmat[4][4], vec[3];
|
2005-06-04 16:22:50 +00:00
|
|
|
float temp1[4][4], temp2[4][4], temp3[4][4]; //max=0.0;
|
2005-11-17 23:26:45 +00:00
|
|
|
int a, obnr, zero_size=0;
|
2002-10-12 11:37:38 +00:00
|
|
|
char obname[32];
|
|
|
|
|
Big commit with work on Groups & Libraries:
-> Any Group Duplicate now can get local timing and local NLA override. This
enables to control the entire animation system of the Group.
Two methods for this have been implemented.
1) The quick way: just give the duplicator a "Startframe" offset.
2) Advanced: in the NLA Editor you can add ActionStrips to the duplicator
to override NLA/action of any Grouped Object.
For "Group NLA" to work, an ActionStrip needs to know which Object in a
group it controls. On adding a strip, the code checks if an Action was
already used by an Object in the Group, and assigns it automatic to that
Object.
You can also set this in the Nkey "Properties" panel for the strip.
Change in NLA: the SHIFT+A "Add strip" command now always adds strips to
the active Object. (It used to check where mouse was). This allows to add
NLA strips to Objects that didn't have actions/nla yet.
Important note: In Blender, duplicates are fully procedural and generated
on the fly for each redraw. This means that redraw speed equals to stepping
through frames, when using animated Duplicated Groups.
-> Recoded entire duplicator system
The old method was antique and clumsy, using globals and full temporal
copies of Object. The new system is nicer in control, faster, and since it
doesn't use temporal object copies anymore, it works better with Derived
Mesh and DisplayList and rendering.
By centralizing the code for duplicating, more options can be easier added.
Features to note:
- Duplicates now draw selected/unselected based on its Duplicator setting.
- Same goes for the drawtype (wire, solid, selection outline, etc)
- Duplicated Groups can be normally selected too
Bonus goodie: SHIFT+A (Toolbox) now has entry "Add group" too, with a
listing of all groups, allowing to add Group instances immediate.
-> Library System
- SHIFT+F4 data browse now shows the entire path for linked data
- Outliner draws Library Icons to denote linked data
- Outliner operation added: "Make Local" for library data.
- Outliner now also draws Groups in regular view, allowing to unlink too.
-> Fixes
- depsgraph missed signal update for bone-parented Objects
- on reading file, the entire database was tagged to "recalc" fully,
causing unnecessary slowdown on reading.
Might have missed stuff... :)
2005-12-11 13:23:30 +00:00
|
|
|
Mat4CpyMat4(obmat, ob->obmat); /* to cope with duplicators from next_object */
|
2002-10-12 11:37:38 +00:00
|
|
|
Mat4Invert(obinv, ob->obmat);
|
2004-04-06 13:51:59 +00:00
|
|
|
a= 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
splitIDname(ob->id.name+2, obname, &obnr);
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* make main array */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
next_object(0, 0, 0);
|
|
|
|
while(next_object(1, &base, &bob)) {
|
|
|
|
|
|
|
|
if(bob->type==OB_MBALL) {
|
2005-11-17 23:26:45 +00:00
|
|
|
zero_size= 0;
|
|
|
|
ml= NULL;
|
|
|
|
|
Big commit with work on Groups & Libraries:
-> Any Group Duplicate now can get local timing and local NLA override. This
enables to control the entire animation system of the Group.
Two methods for this have been implemented.
1) The quick way: just give the duplicator a "Startframe" offset.
2) Advanced: in the NLA Editor you can add ActionStrips to the duplicator
to override NLA/action of any Grouped Object.
For "Group NLA" to work, an ActionStrip needs to know which Object in a
group it controls. On adding a strip, the code checks if an Action was
already used by an Object in the Group, and assigns it automatic to that
Object.
You can also set this in the Nkey "Properties" panel for the strip.
Change in NLA: the SHIFT+A "Add strip" command now always adds strips to
the active Object. (It used to check where mouse was). This allows to add
NLA strips to Objects that didn't have actions/nla yet.
Important note: In Blender, duplicates are fully procedural and generated
on the fly for each redraw. This means that redraw speed equals to stepping
through frames, when using animated Duplicated Groups.
-> Recoded entire duplicator system
The old method was antique and clumsy, using globals and full temporal
copies of Object. The new system is nicer in control, faster, and since it
doesn't use temporal object copies anymore, it works better with Derived
Mesh and DisplayList and rendering.
By centralizing the code for duplicating, more options can be easier added.
Features to note:
- Duplicates now draw selected/unselected based on its Duplicator setting.
- Same goes for the drawtype (wire, solid, selection outline, etc)
- Duplicated Groups can be normally selected too
Bonus goodie: SHIFT+A (Toolbox) now has entry "Add group" too, with a
listing of all groups, allowing to add Group instances immediate.
-> Library System
- SHIFT+F4 data browse now shows the entire path for linked data
- Outliner draws Library Icons to denote linked data
- Outliner operation added: "Make Local" for library data.
- Outliner now also draws Groups in regular view, allowing to unlink too.
-> Fixes
- depsgraph missed signal update for bone-parented Objects
- on reading file, the entire database was tagged to "recalc" fully,
causing unnecessary slowdown on reading.
Might have missed stuff... :)
2005-12-11 13:23:30 +00:00
|
|
|
if(bob==ob && (base->flag & OB_FROMDUPLI)==0) {
|
2002-10-12 11:37:38 +00:00
|
|
|
mat= imat= 0;
|
|
|
|
mb= ob->data;
|
|
|
|
|
|
|
|
if(ob==G.obedit) ml= editelems.first;
|
|
|
|
else if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) ml= editelems.first;
|
|
|
|
else ml= mb->elems.first;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char name[32];
|
|
|
|
int nr;
|
|
|
|
|
|
|
|
splitIDname(bob->id.name+2, name, &nr);
|
|
|
|
if( strcmp(obname, name)==0 ) {
|
|
|
|
mb= bob->data;
|
|
|
|
if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb)
|
|
|
|
ml= editelems.first;
|
|
|
|
else ml= mb->elems.first;
|
|
|
|
}
|
|
|
|
}
|
2005-11-17 23:26:45 +00:00
|
|
|
|
|
|
|
/* when metaball object hase zero scale, then MetaElem ot this MetaBall
|
|
|
|
* will not be put to mainb array */
|
|
|
|
if(bob->size[0]==0.0 || bob->size[1]==0.0 || bob->size[2]==0.0) {
|
|
|
|
zero_size= 1;
|
|
|
|
}
|
|
|
|
else if(bob->parent) {
|
|
|
|
struct Object *pob=bob->parent;
|
|
|
|
while(pob) {
|
|
|
|
if(pob->size[0]==0.0 || pob->size[1]==0.0 || pob->size[2]==0.0) {
|
|
|
|
zero_size= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pob= pob->parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zero_size) {
|
|
|
|
unsigned int ml_count=0;
|
|
|
|
while(ml) {
|
|
|
|
ml_count++;
|
|
|
|
ml= ml->next;
|
|
|
|
}
|
|
|
|
totelem -= ml_count;
|
|
|
|
}
|
|
|
|
else {
|
2004-04-06 13:51:59 +00:00
|
|
|
while(ml) {
|
2005-02-21 10:40:30 +00:00
|
|
|
if(!(ml->flag & MB_HIDE)) {
|
2005-05-30 06:37:33 +00:00
|
|
|
int i;
|
|
|
|
float max_x, max_y, max_z, min_x, min_y, min_z;
|
|
|
|
|
|
|
|
max_x = max_y = max_z = -3.4e38;
|
|
|
|
min_x = min_y = min_z = 3.4e38;
|
|
|
|
|
|
|
|
/* too big stiffness seems only ugly due to linear interpolation
|
|
|
|
* no need to have possibility for too big stiffness */
|
|
|
|
if(ml->s > 10.0) ml->s = 10.0;
|
|
|
|
|
2005-03-29 10:03:30 +00:00
|
|
|
/* Rotation of MetaElem is stored in quat */
|
|
|
|
QuatToMat4(ml->quat, temp3);
|
|
|
|
|
|
|
|
/* Translation of MetaElem */
|
2005-02-21 10:40:30 +00:00
|
|
|
Mat4One(temp2);
|
|
|
|
temp2[3][0]= ml->x;
|
|
|
|
temp2[3][1]= ml->y;
|
|
|
|
temp2[3][2]= ml->z;
|
2005-03-29 10:03:30 +00:00
|
|
|
|
|
|
|
Mat4MulMat4(temp1, temp3, temp2);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2005-02-21 10:40:30 +00:00
|
|
|
/* make a copy because of duplicates */
|
|
|
|
mainb[a]= new_pgn_element(sizeof(MetaElem));
|
|
|
|
*(mainb[a])= *ml;
|
|
|
|
mainb[a]->bb = new_pgn_element(sizeof(BoundBox));
|
2005-05-30 06:37:33 +00:00
|
|
|
|
2005-02-21 10:40:30 +00:00
|
|
|
mat= new_pgn_element(4*4*sizeof(float));
|
|
|
|
imat= new_pgn_element(4*4*sizeof(float));
|
|
|
|
|
|
|
|
/* mat is the matrix to transform from mball into the basis-mball */
|
Big commit with work on Groups & Libraries:
-> Any Group Duplicate now can get local timing and local NLA override. This
enables to control the entire animation system of the Group.
Two methods for this have been implemented.
1) The quick way: just give the duplicator a "Startframe" offset.
2) Advanced: in the NLA Editor you can add ActionStrips to the duplicator
to override NLA/action of any Grouped Object.
For "Group NLA" to work, an ActionStrip needs to know which Object in a
group it controls. On adding a strip, the code checks if an Action was
already used by an Object in the Group, and assigns it automatic to that
Object.
You can also set this in the Nkey "Properties" panel for the strip.
Change in NLA: the SHIFT+A "Add strip" command now always adds strips to
the active Object. (It used to check where mouse was). This allows to add
NLA strips to Objects that didn't have actions/nla yet.
Important note: In Blender, duplicates are fully procedural and generated
on the fly for each redraw. This means that redraw speed equals to stepping
through frames, when using animated Duplicated Groups.
-> Recoded entire duplicator system
The old method was antique and clumsy, using globals and full temporal
copies of Object. The new system is nicer in control, faster, and since it
doesn't use temporal object copies anymore, it works better with Derived
Mesh and DisplayList and rendering.
By centralizing the code for duplicating, more options can be easier added.
Features to note:
- Duplicates now draw selected/unselected based on its Duplicator setting.
- Same goes for the drawtype (wire, solid, selection outline, etc)
- Duplicated Groups can be normally selected too
Bonus goodie: SHIFT+A (Toolbox) now has entry "Add group" too, with a
listing of all groups, allowing to add Group instances immediate.
-> Library System
- SHIFT+F4 data browse now shows the entire path for linked data
- Outliner draws Library Icons to denote linked data
- Outliner operation added: "Make Local" for library data.
- Outliner now also draws Groups in regular view, allowing to unlink too.
-> Fixes
- depsgraph missed signal update for bone-parented Objects
- on reading file, the entire database was tagged to "recalc" fully,
causing unnecessary slowdown on reading.
Might have missed stuff... :)
2005-12-11 13:23:30 +00:00
|
|
|
Mat4Invert(obinv, obmat);
|
2005-03-29 10:03:30 +00:00
|
|
|
Mat4MulMat4(temp2, bob->obmat, obinv);
|
2005-02-21 10:40:30 +00:00
|
|
|
/* MetaBall transformation */
|
2005-03-29 10:03:30 +00:00
|
|
|
Mat4MulMat4(mat, temp1, temp2);
|
2005-02-21 10:40:30 +00:00
|
|
|
|
|
|
|
Mat4Invert(imat,mat);
|
|
|
|
|
|
|
|
mainb[a]->rad2= ml->rad*ml->rad;
|
|
|
|
|
|
|
|
mainb[a]->mat= (float*) mat;
|
|
|
|
mainb[a]->imat= (float*) imat;
|
2005-05-30 06:37:33 +00:00
|
|
|
|
|
|
|
/* untransformed Bounding Box of MetaElem */
|
|
|
|
/* 0 */
|
|
|
|
mainb[a]->bb->vec[0][0]= -ml->expx;
|
|
|
|
mainb[a]->bb->vec[0][1]= -ml->expy;
|
|
|
|
mainb[a]->bb->vec[0][2]= -ml->expz;
|
|
|
|
/* 1 */
|
|
|
|
mainb[a]->bb->vec[1][0]= ml->expx;
|
|
|
|
mainb[a]->bb->vec[1][1]= -ml->expy;
|
|
|
|
mainb[a]->bb->vec[1][2]= -ml->expz;
|
|
|
|
/* 2 */
|
|
|
|
mainb[a]->bb->vec[2][0]= ml->expx;
|
|
|
|
mainb[a]->bb->vec[2][1]= ml->expy;
|
|
|
|
mainb[a]->bb->vec[2][2]= -ml->expz;
|
|
|
|
/* 3 */
|
|
|
|
mainb[a]->bb->vec[3][0]= -ml->expx;
|
|
|
|
mainb[a]->bb->vec[3][1]= ml->expy;
|
|
|
|
mainb[a]->bb->vec[3][2]= -ml->expz;
|
|
|
|
/* 4 */
|
|
|
|
mainb[a]->bb->vec[4][0]= -ml->expx;
|
|
|
|
mainb[a]->bb->vec[4][1]= -ml->expy;
|
|
|
|
mainb[a]->bb->vec[4][2]= ml->expz;
|
|
|
|
/* 5 */
|
|
|
|
mainb[a]->bb->vec[5][0]= ml->expx;
|
|
|
|
mainb[a]->bb->vec[5][1]= -ml->expy;
|
|
|
|
mainb[a]->bb->vec[5][2]= ml->expz;
|
|
|
|
/* 6 */
|
|
|
|
mainb[a]->bb->vec[6][0]= ml->expx;
|
|
|
|
mainb[a]->bb->vec[6][1]= ml->expy;
|
|
|
|
mainb[a]->bb->vec[6][2]= ml->expz;
|
|
|
|
/* 7 */
|
|
|
|
mainb[a]->bb->vec[7][0]= -ml->expx;
|
|
|
|
mainb[a]->bb->vec[7][1]= ml->expy;
|
|
|
|
mainb[a]->bb->vec[7][2]= ml->expz;
|
|
|
|
|
|
|
|
/* transformation of Metalem bb */
|
|
|
|
for(i=0; i<8; i++)
|
|
|
|
Mat4MulVecfl((float ( * )[4])mat, mainb[a]->bb->vec[i]);
|
|
|
|
|
|
|
|
/* find max and min of transformed bb */
|
|
|
|
for(i=0; i<8; i++){
|
|
|
|
/* find maximums */
|
|
|
|
if(mainb[a]->bb->vec[i][0] > max_x) max_x = mainb[a]->bb->vec[i][0];
|
|
|
|
if(mainb[a]->bb->vec[i][1] > max_y) max_y = mainb[a]->bb->vec[i][1];
|
|
|
|
if(mainb[a]->bb->vec[i][2] > max_z) max_z = mainb[a]->bb->vec[i][2];
|
|
|
|
/* find minimums */
|
|
|
|
if(mainb[a]->bb->vec[i][0] < min_x) min_x = mainb[a]->bb->vec[i][0];
|
|
|
|
if(mainb[a]->bb->vec[i][1] < min_y) min_y = mainb[a]->bb->vec[i][1];
|
|
|
|
if(mainb[a]->bb->vec[i][2] < min_z) min_z = mainb[a]->bb->vec[i][2];
|
2005-02-21 10:40:30 +00:00
|
|
|
}
|
2005-05-30 06:37:33 +00:00
|
|
|
|
|
|
|
/* create "new" bb, only point 0 and 6, which are
|
|
|
|
* neccesary for octal tree filling */
|
|
|
|
mainb[a]->bb->vec[0][0] = min_x - ml->rad;
|
|
|
|
mainb[a]->bb->vec[0][1] = min_y - ml->rad;
|
|
|
|
mainb[a]->bb->vec[0][2] = min_z - ml->rad;
|
|
|
|
|
|
|
|
mainb[a]->bb->vec[6][0] = max_x + ml->rad;
|
|
|
|
mainb[a]->bb->vec[6][1] = max_y + ml->rad;
|
|
|
|
mainb[a]->bb->vec[6][2] = max_z + ml->rad;
|
2005-02-21 10:40:30 +00:00
|
|
|
|
|
|
|
a++;
|
2004-06-29 17:10:13 +00:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
ml= ml->next;
|
|
|
|
}
|
2005-11-17 23:26:45 +00:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
2003-09-05 13:54:22 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* totsize (= 'manhattan' radius) */
|
2002-10-12 11:37:38 +00:00
|
|
|
totsize= 0.0;
|
|
|
|
for(a=0; a<totelem; a++) {
|
|
|
|
|
2006-06-27 09:37:12 +00:00
|
|
|
vec[0]= mainb[a]->x + mainb[a]->rad + mainb[a]->expx;
|
|
|
|
vec[1]= mainb[a]->y + mainb[a]->rad + mainb[a]->expy;
|
|
|
|
vec[2]= mainb[a]->z + mainb[a]->rad + mainb[a]->expz;
|
2004-06-29 17:10:13 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
calc_mballco(mainb[a], vec);
|
|
|
|
|
|
|
|
size= (float)fabs( vec[0] );
|
|
|
|
if( size > totsize ) totsize= size;
|
|
|
|
size= (float)fabs( vec[1] );
|
|
|
|
if( size > totsize ) totsize= size;
|
|
|
|
size= (float)fabs( vec[2] );
|
|
|
|
if( size > totsize ) totsize= size;
|
2004-06-29 17:10:13 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
vec[0]= mainb[a]->x - mainb[a]->rad;
|
|
|
|
vec[1]= mainb[a]->y - mainb[a]->rad;
|
|
|
|
vec[2]= mainb[a]->z - mainb[a]->rad;
|
2004-06-29 17:10:13 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
calc_mballco(mainb[a], vec);
|
|
|
|
|
|
|
|
size= (float)fabs( vec[0] );
|
|
|
|
if( size > totsize ) totsize= size;
|
|
|
|
size= (float)fabs( vec[1] );
|
|
|
|
if( size > totsize ) totsize= size;
|
|
|
|
size= (float)fabs( vec[2] );
|
|
|
|
if( size > totsize ) totsize= size;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(a=0; a<totelem; a++) {
|
|
|
|
thresh+= densfunc( mainb[a], 2.0f*totsize, 2.0f*totsize, 2.0f*totsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return totsize;
|
|
|
|
}
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
/* if MetaElem lies in node, then node includes MetaElem pointer (ml_p)
|
|
|
|
* pointing at MetaElem (ml)
|
|
|
|
*/
|
|
|
|
void fill_metaball_octal_node(octal_node *node, MetaElem *ml, short i)
|
|
|
|
{
|
|
|
|
ml_pointer *ml_p;
|
|
|
|
|
|
|
|
ml_p= MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
|
|
|
|
ml_p->ml= ml;
|
|
|
|
BLI_addtail(&(node->nodes[i]->elems), ml_p);
|
|
|
|
node->count++;
|
|
|
|
|
|
|
|
if(ml->flag & MB_NEGATIVE) {
|
|
|
|
node->nodes[i]->neg++;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
node->nodes[i]->pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Node is subdivided as is ilustrated on the following figure:
|
|
|
|
*
|
|
|
|
* +------+------+
|
|
|
|
* / / /|
|
|
|
|
* +------+------+ |
|
|
|
|
* / / /| +
|
|
|
|
* +------+------+ |/|
|
|
|
|
* | | | + |
|
|
|
|
* | | |/| +
|
|
|
|
* +------+------+ |/
|
|
|
|
* | | | +
|
|
|
|
* | | |/
|
|
|
|
* +------+------+
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void subdivide_metaball_octal_node(octal_node *node, float *size, short depth)
|
|
|
|
{
|
|
|
|
MetaElem *ml;
|
|
|
|
ml_pointer *ml_p;
|
|
|
|
float x,y,z;
|
|
|
|
int a,i;
|
|
|
|
|
|
|
|
if(depth==0) return;
|
|
|
|
|
|
|
|
/* create new nodes */
|
|
|
|
for(a=0;a<8;a++){
|
|
|
|
node->nodes[a]= MEM_mallocN(sizeof(octal_node),"octal_node");
|
|
|
|
for(i=0;i<8;i++)
|
|
|
|
node->nodes[a]->nodes[i]= NULL;
|
|
|
|
node->nodes[a]->parent= node;
|
|
|
|
node->nodes[a]->elems.first= NULL;
|
|
|
|
node->nodes[a]->elems.last= NULL;
|
|
|
|
node->nodes[a]->count= 0;
|
|
|
|
node->nodes[a]->neg= 0;
|
|
|
|
node->nodes[a]->pos= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size[0]/=2; size[1]/=2; size[2]/=2;
|
|
|
|
|
|
|
|
/* center of node */
|
|
|
|
node->x= x= node->x_min + size[0];
|
|
|
|
node->y= y= node->y_min + size[1];
|
|
|
|
node->z= z= node->z_min + size[2];
|
|
|
|
|
|
|
|
/* setting up of border points of new nodes */
|
|
|
|
node->nodes[0]->x_min= node->x_min;
|
|
|
|
node->nodes[0]->y_min= node->y_min;
|
|
|
|
node->nodes[0]->z_min= node->z_min;
|
|
|
|
|
|
|
|
node->nodes[1]->x_min= x;
|
|
|
|
node->nodes[1]->y_min= node->y_min;
|
|
|
|
node->nodes[1]->z_min= node->z_min;
|
|
|
|
|
|
|
|
node->nodes[2]->x_min= x;
|
|
|
|
node->nodes[2]->y_min= y;
|
|
|
|
node->nodes[2]->z_min= node->z_min;
|
|
|
|
|
|
|
|
node->nodes[3]->x_min= node->x_min;
|
|
|
|
node->nodes[3]->y_min= y;
|
|
|
|
node->nodes[3]->z_min= node->z_min;
|
|
|
|
|
|
|
|
node->nodes[4]->x_min= node->x_min;
|
|
|
|
node->nodes[4]->y_min= node->y_min;
|
|
|
|
node->nodes[4]->z_min= z;
|
|
|
|
|
|
|
|
node->nodes[5]->x_min= x;
|
|
|
|
node->nodes[5]->y_min= node->y_min;
|
|
|
|
node->nodes[5]->z_min= z;
|
|
|
|
|
|
|
|
node->nodes[6]->x_min= x;
|
|
|
|
node->nodes[6]->y_min= y;
|
|
|
|
node->nodes[6]->z_min= z;
|
|
|
|
|
|
|
|
node->nodes[7]->x_min= node->x_min;
|
|
|
|
node->nodes[7]->y_min= y;
|
|
|
|
node->nodes[7]->z_min= z;
|
|
|
|
|
|
|
|
ml_p= node->elems.first;
|
|
|
|
|
|
|
|
/* setting up references of MetaElems for new nodes */
|
|
|
|
while(ml_p){
|
|
|
|
ml= ml_p->ml;
|
|
|
|
if(ml->bb->vec[0][2] < z){
|
|
|
|
if(ml->bb->vec[0][1] < y){
|
|
|
|
/* vec[0][0] lies in first octant */
|
|
|
|
if(ml->bb->vec[0][0] < x){
|
|
|
|
/* ml belongs to the (0)1st node */
|
|
|
|
fill_metaball_octal_node(node, ml, 0);
|
|
|
|
|
|
|
|
/* ml belongs to the (3)4th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][1] >= y){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 3);
|
|
|
|
|
|
|
|
/* ml belongs to the (7)8th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ml belongs to the (1)2nd node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][0] >= x){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 1);
|
|
|
|
|
|
|
|
/* ml belongs to the (5)6th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ml belongs to the (2)3th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 2);
|
|
|
|
|
|
|
|
/* ml belong to the (6)7th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ml belongs to the (4)5th node too */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
/* vec[0][0] is in the (1)second octant */
|
|
|
|
else{
|
|
|
|
/* ml belong to the (1)2nd node */
|
|
|
|
fill_metaball_octal_node(node, ml, 1);
|
|
|
|
|
|
|
|
/* ml belongs to the (2)3th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][1] >= y){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 2);
|
|
|
|
|
|
|
|
/* ml belongs to the (6)7th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ml belongs to the (5)6th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/* vec[0][0] is in the (3)4th octant */
|
|
|
|
if(ml->bb->vec[0][0] < x){
|
|
|
|
/* ml belongs to the (3)4nd node */
|
|
|
|
fill_metaball_octal_node(node, ml, 3);
|
|
|
|
|
|
|
|
/* ml belongs to the (7)8th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ml belongs to the (2)3th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][0] >= x){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 2);
|
|
|
|
|
|
|
|
/* ml belongs to the (6)7th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vec[0][0] is in the (2)3th octant */
|
2004-11-10 13:20:13 +00:00
|
|
|
if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){
|
2004-06-29 17:10:13 +00:00
|
|
|
/* ml belongs to the (2)3th node */
|
|
|
|
fill_metaball_octal_node(node, ml, 2);
|
|
|
|
|
|
|
|
/* ml belongs to the (6)7th node */
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][2] >= z){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(ml->bb->vec[0][1] < y){
|
|
|
|
/* vec[0][0] lies in (4)5th octant */
|
|
|
|
if(ml->bb->vec[0][0] < x){
|
|
|
|
/* ml belongs to the (4)5th node */
|
|
|
|
fill_metaball_octal_node(node, ml, 4);
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][0] >= x){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 5);
|
|
|
|
}
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][1] >= y){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 7);
|
|
|
|
}
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* vec[0][0] lies in (5)6th octant */
|
|
|
|
else{
|
|
|
|
fill_metaball_octal_node(node, ml, 5);
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][1] >= y){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/* vec[0][0] lies in (7)8th octant */
|
|
|
|
if(ml->bb->vec[0][0] < x){
|
|
|
|
fill_metaball_octal_node(node, ml, 7);
|
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
if(ml->bb->vec[6][0] >= x){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vec[0][0] lies in (6)7th octant */
|
2004-11-10 13:20:13 +00:00
|
|
|
if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){
|
2004-06-29 17:10:13 +00:00
|
|
|
fill_metaball_octal_node(node, ml, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ml_p= ml_p->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free references of MetaElems for curent node (it is not needed anymore) */
|
|
|
|
BLI_freelistN(&node->elems);
|
|
|
|
|
|
|
|
depth--;
|
|
|
|
|
|
|
|
if(depth>0){
|
|
|
|
for(a=0;a<8;a++){
|
|
|
|
if(node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */
|
|
|
|
subdivide_metaball_octal_node(node->nodes[a], size, depth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free all octal nodes recursively */
|
|
|
|
void free_metaball_octal_node(octal_node *node)
|
|
|
|
{
|
|
|
|
int a;
|
|
|
|
for(a=0;a<8;a++){
|
|
|
|
if(node->nodes[a]!=NULL) free_metaball_octal_node(node->nodes[a]);
|
|
|
|
}
|
|
|
|
BLI_freelistN(&node->elems);
|
|
|
|
if(node) MEM_freeN(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If scene include more then one MetaElem, then octree is used */
|
|
|
|
void init_metaball_octal_tree(int depth)
|
|
|
|
{
|
|
|
|
struct octal_node *node;
|
|
|
|
ml_pointer *ml_p;
|
|
|
|
float size[3];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
metaball_tree= MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree");
|
|
|
|
metaball_tree->first= node= MEM_mallocN(sizeof(octal_node), "metaball_octal_node");
|
|
|
|
/* maximal depth of octree */
|
|
|
|
metaball_tree->depth= depth;
|
|
|
|
|
|
|
|
metaball_tree->neg= node->neg=0;
|
|
|
|
metaball_tree->pos= node->pos=0;
|
|
|
|
|
|
|
|
node->elems.first= NULL;
|
|
|
|
node->elems.last= NULL;
|
|
|
|
node->count=0;
|
|
|
|
|
|
|
|
for(a=0;a<8;a++)
|
|
|
|
node->nodes[a]=NULL;
|
|
|
|
|
|
|
|
node->x_min= node->y_min= node->z_min= 10000000.0;
|
|
|
|
node->x_max= node->y_max= node->z_max= -10000000.0;
|
|
|
|
|
|
|
|
/* size of octal tree scene */
|
|
|
|
for(a=0;a<totelem;a++) {
|
|
|
|
if(mainb[a]->bb->vec[0][0] < node->x_min) node->x_min= mainb[a]->bb->vec[0][0];
|
|
|
|
if(mainb[a]->bb->vec[0][1] < node->y_min) node->y_min= mainb[a]->bb->vec[0][1];
|
|
|
|
if(mainb[a]->bb->vec[0][2] < node->z_min) node->z_min= mainb[a]->bb->vec[0][2];
|
|
|
|
|
|
|
|
if(mainb[a]->bb->vec[6][0] > node->x_max) node->x_max= mainb[a]->bb->vec[6][0];
|
|
|
|
if(mainb[a]->bb->vec[6][1] > node->y_max) node->y_max= mainb[a]->bb->vec[6][1];
|
|
|
|
if(mainb[a]->bb->vec[6][2] > node->z_max) node->z_max= mainb[a]->bb->vec[6][2];
|
|
|
|
|
|
|
|
ml_p= MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
|
|
|
|
ml_p->ml= mainb[a];
|
|
|
|
BLI_addtail(&node->elems, ml_p);
|
|
|
|
|
|
|
|
if(mainb[a]->flag & MB_NEGATIVE) {
|
|
|
|
/* number of negative MetaElem in scene */
|
|
|
|
metaball_tree->neg++;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/* number of positive MetaElem in scene */
|
|
|
|
metaball_tree->pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* size of first node */
|
|
|
|
size[0]= node->x_max - node->x_min;
|
|
|
|
size[1]= node->y_max - node->y_min;
|
|
|
|
size[2]= node->z_max - node->z_min;
|
|
|
|
|
|
|
|
/* first node is subdivided recursively */
|
|
|
|
subdivide_metaball_octal_node(node, size, metaball_tree->depth);
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
void metaball_polygonize(Object *ob)
|
|
|
|
{
|
|
|
|
PROCESS mbproc;
|
|
|
|
MetaBall *mb;
|
|
|
|
DispList *dl;
|
2004-11-10 13:20:13 +00:00
|
|
|
int a, nr_cubes;
|
2002-10-12 11:37:38 +00:00
|
|
|
float *ve, *no, totsize, width;
|
|
|
|
|
|
|
|
mb= ob->data;
|
2004-11-10 13:20:13 +00:00
|
|
|
|
2005-02-21 10:40:30 +00:00
|
|
|
if(totelem==0) return;
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
if(!(G.rendering) && (mb->flag==MB_UPDATE_NEVER)) return;
|
2004-05-29 17:00:51 +00:00
|
|
|
if(G.moving && mb->flag==MB_UPDATE_FAST) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
freedisplist(&ob->disp);
|
|
|
|
curindex= totindex= 0;
|
|
|
|
indices= 0;
|
|
|
|
thresh= mb->thresh;
|
2004-04-06 13:51:59 +00:00
|
|
|
|
2004-11-10 13:20:13 +00:00
|
|
|
/* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */
|
2004-04-06 13:51:59 +00:00
|
|
|
mainb= MEM_mallocN(sizeof(void *)*totelem, "mainb");
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
/* initialize all mainb (MetaElems) */
|
2002-10-12 11:37:38 +00:00
|
|
|
totsize= init_meta(ob);
|
2004-06-29 17:10:13 +00:00
|
|
|
|
|
|
|
if(metaball_tree){
|
|
|
|
free_metaball_octal_node(metaball_tree->first);
|
|
|
|
MEM_freeN(metaball_tree);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if scene includes more then one MetaElem, then octal tree optimalisation is used */
|
2004-11-10 13:20:13 +00:00
|
|
|
if((totelem > 1) && (totelem <= 64)) init_metaball_octal_tree(1);
|
|
|
|
if((totelem > 64) && (totelem <= 128)) init_metaball_octal_tree(2);
|
|
|
|
if((totelem > 128) && (totelem <= 512)) init_metaball_octal_tree(3);
|
2006-07-07 11:10:53 +00:00
|
|
|
if((totelem > 512) && (totelem <= 1024)) init_metaball_octal_tree(4);
|
2004-11-10 13:20:13 +00:00
|
|
|
if(totelem > 1024) init_metaball_octal_tree(5);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2006-07-07 11:10:53 +00:00
|
|
|
/* don't polygonize metaballs with too high resolution (base mball to small) */
|
|
|
|
if(metaball_tree) {
|
|
|
|
if(ob->size[0]<=0.0001f*(metaball_tree->first->x_max - metaball_tree->first->x_min) ||
|
|
|
|
ob->size[1]<=0.0001f*(metaball_tree->first->y_max - metaball_tree->first->y_min) ||
|
|
|
|
ob->size[2]<=0.0001f*(metaball_tree->first->z_max - metaball_tree->first->z_min))
|
|
|
|
{
|
|
|
|
MEM_freeN(mainb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* width is size per polygonize cube */
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
if(G.rendering) width= mb->rendersize;
|
2002-10-12 11:37:38 +00:00
|
|
|
else {
|
|
|
|
width= mb->wiresize;
|
|
|
|
if(G.moving && mb->flag==MB_UPDATE_HALFRES) width*= 2;
|
|
|
|
}
|
2003-04-26 13:07:59 +00:00
|
|
|
/* nr_cubes is just for safety, minimum is totsize */
|
2002-10-12 11:37:38 +00:00
|
|
|
nr_cubes= (int)(0.5+totsize/width);
|
|
|
|
|
|
|
|
/* init process */
|
|
|
|
mbproc.function = metaball;
|
|
|
|
mbproc.size = width;
|
|
|
|
mbproc.bounds = nr_cubes;
|
|
|
|
mbproc.cubes= 0;
|
|
|
|
mbproc.delta = width/(float)(RES*RES);
|
|
|
|
|
2003-09-05 13:54:22 +00:00
|
|
|
polygonize(&mbproc, mb);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
MEM_freeN(mainb);
|
|
|
|
|
2004-06-29 17:10:13 +00:00
|
|
|
/* free octal tree */
|
|
|
|
if(totelem > 1){
|
|
|
|
free_metaball_octal_node(metaball_tree->first);
|
|
|
|
MEM_freeN(metaball_tree);
|
|
|
|
metaball_tree= NULL;
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if(curindex) {
|
|
|
|
|
|
|
|
dl= MEM_callocN(sizeof(DispList), "mbaldisp");
|
|
|
|
BLI_addtail(&ob->disp, dl);
|
|
|
|
dl->type= DL_INDEX4;
|
|
|
|
dl->nr= mbproc.vertices.count;
|
|
|
|
dl->parts= curindex;
|
|
|
|
|
|
|
|
dl->index= indices;
|
|
|
|
indices= 0;
|
|
|
|
|
|
|
|
a= mbproc.vertices.count;
|
|
|
|
dl->verts= ve= MEM_mallocN(sizeof(float)*3*a, "mballverts");
|
|
|
|
dl->nors= no= MEM_mallocN(sizeof(float)*3*a, "mballnors");
|
|
|
|
|
|
|
|
for(a=0; a<mbproc.vertices.count; a++, no+=3, ve+=3) {
|
|
|
|
ve[0]= mbproc.vertices.ptr[a].position.x;
|
|
|
|
ve[1]= mbproc.vertices.ptr[a].position.y;
|
|
|
|
ve[2]= mbproc.vertices.ptr[a].position.z;
|
|
|
|
|
|
|
|
no[0]= mbproc.vertices.ptr[a].normal.x;
|
|
|
|
no[1]= mbproc.vertices.ptr[a].normal.y;
|
|
|
|
no[2]= mbproc.vertices.ptr[a].normal.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
freepolygonize(&mbproc);
|
|
|
|
}
|
|
|
|
|