diff options
44 files changed, 3651 insertions, 7468 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b58fe945663..19a03c35bfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# $Id$ +# $Id: CMakeLists.txt 12480 2007-11-05 16:46:48Z sirdude $ # ***** BEGIN GPL LICENSE BLOCK ***** # # This program is free software; you can redistribute it and/or diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt index c5495fdf92b..b5ae20253cc 100644 --- a/extern/bullet2/CMakeLists.txt +++ b/extern/bullet2/CMakeLists.txt @@ -1,4 +1,4 @@ -# $Id$ +# $Id: CMakeLists.txt 14444 2008-04-16 22:40:48Z hos $ # ***** BEGIN GPL LICENSE BLOCK ***** # # This program is free software; you can redistribute it and/or diff --git a/extern/bullet2/Makefile b/extern/bullet2/Makefile index e05d441a6be..2da1a5bcf85 100644 --- a/extern/bullet2/Makefile +++ b/extern/bullet2/Makefile @@ -1,5 +1,5 @@ # -# $Id$ +# $Id: Makefile 14444 2008-04-16 22:40:48Z hos $ # # ***** BEGIN GPL LICENSE BLOCK ***** # diff --git a/extern/bullet2/src/Makefile b/extern/bullet2/src/Makefile index 24f3ca9767d..d7bb6a5e427 100644 --- a/extern/bullet2/src/Makefile +++ b/extern/bullet2/src/Makefile @@ -1,5 +1,5 @@ # -# $Id$ +# $Id: Makefile 14444 2008-04-16 22:40:48Z hos $ # # ***** BEGIN GPL LICENSE BLOCK ***** # diff --git a/intern/elbeem/intern/isosurface.cpp b/intern/elbeem/intern/isosurface.cpp index 1b0ba13c707..f90621f3b73 100644 --- a/intern/elbeem/intern/isosurface.cpp +++ b/intern/elbeem/intern/isosurface.cpp @@ -22,6 +22,10 @@ #define round(x) (x) #endif +#if PARALLEL==1 +#include <omp.h> +#endif + /****************************************************************************** * Constructor *****************************************************************************/ @@ -160,13 +164,6 @@ void IsoSurface::triangulate( void ) mpEdgeVerticesZ[i] = -1; } - ntlVec3Gfx pos[8]; - float value[8]; - int cubeIndex; // index entry of the cube - int triIndices[12]; // vertex indices - int *eVert[12]; - IsoLevelVertex ilv; - // edges between which points? const int mcEdges[24] = { 0,1, 1,2, 2,3, 3,0, @@ -193,7 +190,12 @@ void IsoSurface::triangulate( void ) px = mStart[0]-gsx*0.5; for(int i=1;i<(mSizex-2);i++) { px += gsx; - + int cubeIndex; // index entry of the cube + float value[8]; + int triIndices[12]; // vertex indices + int *eVert[12]; + IsoLevelVertex ilv; + value[0] = *getData(i ,j ,k ); value[1] = *getData(i+1,j ,k ); value[2] = *getData(i+1,j+1,k ); @@ -239,6 +241,7 @@ void IsoSurface::triangulate( void ) eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ]; // grid positions + ntlVec3Gfx pos[8]; pos[0] = ntlVec3Gfx(px ,py ,pz); pos[1] = ntlVec3Gfx(px+gsx,py ,pz); pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); @@ -344,10 +347,7 @@ void IsoSurface::triangulate( void ) if(mUseFullEdgeArrays) { errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!"); } - - // subdiv local arrays - gfxReal orgval[8]; - gfxReal subdAr[2][11][11]; // max 10 subdivs! + ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex]; // construct pointers @@ -408,13 +408,25 @@ void IsoSurface::triangulate( void ) debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<<pInUse<<", Subdivs:"<<mSubdivs, 9); pz = mStart[2]-(double)(0.*gsz)-0.5*orgGsz; + for(int ok=1;ok<(mSizez-2)*mSubdivs;ok++) { pz += gsz; const int k = ok/mSubdivs; if(k<=0) continue; // skip zero plane +#if PARALLEL==1 +#pragma omp parallel for +#endif for(int j=1;j<(mSizey-2);j++) { for(int i=1;i<(mSizex-2);i++) { - + float value[8]; + ntlVec3Gfx pos[8]; + int cubeIndex; // index entry of the cube + int triIndices[12]; // vertex indices + int *eVert[12]; + IsoLevelVertex ilv; + gfxReal orgval[8]; + gfxReal subdAr[2][11][11]; // max 10 subdivs! + orgval[0] = *getData(i ,j ,k ); orgval[1] = *getData(i+1,j ,k ); orgval[2] = *getData(i+1,j+1,k ); // with subdivs @@ -426,6 +438,7 @@ void IsoSurface::triangulate( void ) // prebuild subsampled array slice const int sdkOffset = ok-k*mSubdivs; + for(int sdk=0; sdk<2; sdk++) for(int sdj=0; sdj<mSubdivs+1; sdj++) for(int sdi=0; sdi<mSubdivs+1; sdi++) { @@ -580,8 +593,13 @@ void IsoSurface::triangulate( void ) // init isolevel vertex ilv.v = p1 + (p2-p1)*mu; // with subdivs +#if PARALLEL==1 +#pragma omp critical +#endif + { mPoints.push_back( ilv ); triIndices[e] = (mPoints.size()-1); + } // store vertex *eVert[ e ] = triIndices[e]; } else { @@ -591,23 +609,27 @@ void IsoSurface::triangulate( void ) } // along all edges } // removed cutoff treatment... - + // Create the triangles... +#if PARALLEL==1 +#pragma omp critical +#endif + { for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) { mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] ); mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); // with subdivs mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] ); //errMsg("TTT"," i1"<<mIndices[mIndices.size()-3]<<" "<< " i2"<<mIndices[mIndices.size()-2]<<" "<< " i3"<<mIndices[mIndices.size()-1]<<" "<< mIndices.size() ); - } - } // triangles in edge table? + } + } }//si }// sj }//i }// j - + // copy edge arrays for(int j=0;j<(mSizey-0)*mSubdivs;j++) for(int i=0;i<(mSizex-0)*mSubdivs;i++) { diff --git a/intern/elbeem/intern/loop_tools.h b/intern/elbeem/intern/loop_tools.h index 70ecb9ce3e0..163965901e8 100644 --- a/intern/elbeem/intern/loop_tools.h +++ b/intern/elbeem/intern/loop_tools.h @@ -34,7 +34,7 @@ // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #define GRID_REGION_START() \ - { /* main_region */ \ +{ /* main_region */ \ int kstart=getForZMinBnd(), kend=getForZMaxBnd(mMaxRefine); \ if(gridLoopBound>0){ kstart=getForZMin1(), kend=getForZMax1(mMaxRefine); } \ int kdir = 1; \ @@ -49,7 +49,7 @@ kend = kstart-1; \ kstart = temp-1; \ temp = id; /* dummy remove warning */ \ - } \ +} \ @@ -74,13 +74,13 @@ // loop start #define GRID_REGION_START() \ - { \ +{ \ \ \ if(mSizez<2) { \ mPanic = 1; \ errFatal("ParaLoop::2D","Not valid...!", SIMWORLD_GENERICERROR); \ - } \ +} \ \ \ vector<LbmPoint> calcListFull; \ @@ -113,14 +113,14 @@ int temp = kend; \ kend = kstart-1; \ kstart = temp-1; \ - } \ +} \ \ const int Nj = mLevel[mMaxRefine].lSizey; \ int jstart = 0+( id * (Nj / Nthrds) ); \ int jend = 0+( (id+1) * (Nj / Nthrds) ); \ if( ((Nj/Nthrds) *Nthrds) != Nj) { \ errMsg("LbmFsgrSolver","Invalid domain size Nj="<<Nj<<" Nthrds="<<Nthrds); \ - } \ +} \ \ if(jstart<gridLoopBound) jstart = gridLoopBound; \ if(jend>mLevel[mMaxRefine].lSizey-gridLoopBound) jend = mLevel[mMaxRefine].lSizey-gridLoopBound; \ @@ -156,16 +156,16 @@ // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #define GRID_LOOPREG_END() \ \ - } /* i */ \ +} /* i */ \ int i=0; \ ADVANCE_POINTERS(2*gridLoopBound); \ - } /* j */ \ +} /* j */ \ /* COMPRESSGRIDS!=1 */ \ /* int i=0; */ \ /* ADVANCE_POINTERS(mLevel[lev].lSizex*2); */ \ - } /* all cell loop k,j,i */ \ +} /* all cell loop k,j,i */ \ if(doReduce) { } /* dummy remove warning */ \ - } /* main_region */ \ +} /* main_region */ \ \ diff --git a/intern/elbeem/intern/paraloopend.h b/intern/elbeem/intern/paraloopend.h index 6bb224b625a..de315c5a6e1 100644 --- a/intern/elbeem/intern/paraloopend.h +++ b/intern/elbeem/intern/paraloopend.h @@ -1,4 +1,3 @@ - // same as grid loop_end + barrier } // i @@ -22,9 +21,9 @@ { if(doReduce) { // synchronize global vars - for(int j=0; j<calcListFull.size() ; j++) mListFull.push_back( calcListFull[j] ); - for(int j=0; j<calcListEmpty.size(); j++) mListEmpty.push_back( calcListEmpty[j] ); - for(int j=0; j<calcListParts.size(); j++) mpParticles->addFullParticle( calcListParts[j] ); + for(unsigned int j=0; j<calcListFull.size() ; j++) mListFull.push_back( calcListFull[j] ); + for(unsigned int j=0; j<calcListEmpty.size(); j++) mListEmpty.push_back( calcListEmpty[j] ); + for(unsigned int j=0; j<calcListParts.size(); j++) mpParticles->addFullParticle( calcListParts[j] ); if(calcMaxVlen>mMaxVlen) { mMxvx = calcMxvx; mMxvy = calcMxvy; diff --git a/intern/elbeem/intern/solver_init.cpp b/intern/elbeem/intern/solver_init.cpp index c953d2f47da..105c8ff3094 100644 --- a/intern/elbeem/intern/solver_init.cpp +++ b/intern/elbeem/intern/solver_init.cpp @@ -706,8 +706,9 @@ bool LbmFsgrSolver::initializeSolverMemory() if(sizeof(void *)==4 && memEstFine>maxDefaultMemChunk) { // max memory chunk for 32bit systems 2gig memBlockAllocProblem = true; + } - + if(memEstFromFunc>memLimit || memBlockAllocProblem) { sizeReduction *= 0.9; mSizex = (int)(orgSx * sizeReduction); diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp index 13ebf91b696..7b91724a640 100644 --- a/intern/elbeem/intern/solver_main.cpp +++ b/intern/elbeem/intern/solver_main.cpp @@ -368,8 +368,7 @@ LbmFsgrSolver::mainLoop(int lev) const int cutMin = 1; const int cutConst = mCutoff+2; - - + # if LBM_INCLUDE_TESTSOLVERS==1 // 3d region off... quit if((mUseTestdata)&&(mpTest->mFarfMode>0)) { return; } diff --git a/intern/sph/SConscript b/intern/sph/SConscript new file mode 100644 index 00000000000..52243f767c3 --- /dev/null +++ b/intern/sph/SConscript @@ -0,0 +1,11 @@ +#!/usr/bin/python +import sys +import os +Import('env') + +sources = env.Glob('intern/*.cpp') + +incs = ' . extern intern' +defs = '' + +env.BlenderLib ('bf_sph', sources, Split(incs), Split(defs), libtype='blender', priority=0 ) diff --git a/intern/sph/extern/sph_extern.h b/intern/sph/extern/sph_extern.h new file mode 100644 index 00000000000..b4964739212 --- /dev/null +++ b/intern/sph/extern/sph_extern.h @@ -0,0 +1,51 @@ +/** + * ***** 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) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef PW_EXTERN_H +#define PW_EXTERN_H + + + +#ifdef __cplusplus +extern "C" { +#endif +/* +void sph_init_cpp(struct SphModifierData *sphmd); +void sph_free_cpp(struct SphModifierData *sphmd); +int sph_simulate_cpp(struct Object *ob, struct SphModifierData *sphmd, float frame, struct ListBase *effectors); +*/ +#ifdef __cplusplus +} +#endif + + +#endif //PW_EXTERN_H + + diff --git a/intern/sph/intern/sph.cpp b/intern/sph/intern/sph.cpp new file mode 100644 index 00000000000..f7afa3c34eb --- /dev/null +++ b/intern/sph/intern/sph.cpp @@ -0,0 +1,51 @@ +/* pw.c +* +* +* ***** 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) Blender Foundation +* All rights reserved. +* +* Contributor(s): Daniel Genrich +* +* ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include <iostream> + +#include "sph_extern.h" +/* +extern "C" void sph_init_cpp(struct SphModifierData *sphmd) +{ + +} +/* +extern "C" void sph_free_cpp(struct SphModifierData *sphmd) +{ + + +} + +extern "C" int sph_simulate_cpp(struct Object *ob, struct SphModifierData *sphmd, float frame, struct ListBase *effectors) +{ + + return 1; +} +*/ diff --git a/release/scripts/flt_defaultp.py b/release/scripts/flt_defaultp.py deleted file mode 100644 index 5c44fe29a6f..00000000000 --- a/release/scripts/flt_defaultp.py +++ /dev/null @@ -1 +0,0 @@ -pal = [-1,255,16711935,-16776961,-19529729,-19726337,-19922945,-20119553,-20316161,-20578305,-20840449,-21102593,-21364737,-21692417,-22020097,-22413313,-22806529,-23199745,-23658497,-24117249,-24641537,-25165825,-25755649,-26411009,-27066369,-27787265,-28573697,-29425665,-30343169,-31326209,-32374785,-33488897,-354549761,-371458049,-388366337,-405274625,-422182913,-439156737,-456130561,-473104385,-506855425,-540672001,-574488577,-608305153,-642121729,-676003841,-709885953,-760610817,-811335681,-862060545,-912850945,-980418561,-1048051713,-1115684865,-1183383553,-1267924993,-1352466433,-1453850625,-1555300353,-1656815617,-1775173633,-1893597185,-2028863489,2130771967,-1010376193,-1043996161,-1077681665,-1111367169,-1145052673,-1178738177,-1229200897,-1279663617,-1330126337,-1380654593,-1431182849,-1498488321,-1565793793,-1633164801,-1700535809,-1784684033,-1868832257,-1969823233,-2070814209,2123096575,2005262847,1887429119,1752752639,1601298943,1449779711,1281417727,1096278527,911073791,709026303,490201599,254534143,2023935,-1380857601,-1397700353,-1431320321,-1464940289,-1498560257,-1532180225,-1565865729,-1599551233,-1650013953,-1700476673,-1750939393,-1801402113,-1851864833,-1919170305,-1986475777,-2053781249,-2121086721,2089797887,2005649663,1904724223,1803798783,1686030591,1568262399,1450494207,1315883263,1164495103,1013041407,844810495,659736831,457885951,239192319,3655935,-1767919617,-1784762369,-1801605121,-1818447873,-1852067841,-1885687809,-1919307777,-1952927745,-1986547713,-2020167681,-2070564865,-2120962049,2123542527,2073079807,2022617087,1955377151,1888137215,1820897279,1736880127,1652797439,1568714751,1467854847,1366994943,1249357823,1131655167,997175295,862695423,711372799,560050175,391950335,207007743,5287935,2139657983,2122880767,2106103551,2089326335,2072549119,2055771903,2022217471,1988663039,1955108607,1921554175,1887934207,1854314239,1803917055,1753519871,1703122687,1652725503,1602328319,1535153919,1467979519,1400805119,1316853503,1232901887,1148950271,1048221439,947427071,846632703,729061119,611489535,477140735,326014719,174888703,6919935,1837268479,1820491263,1803714047,1786936831,1770159615,1753382399,1736605183,1719827967,1686273535,1652719103,1619164671,1585610239,1552055807,1518501375,1468169727,1417838079,1367506431,1317174783,1266843135,1199734271,1132625407,1065516543,998407679,914521599,830635519,729972223,629308927,528645631,411205119,293764607,159546879,8551935,-2086957569,-2103734785,-2120512001,-2137289217,2140900863,2107346431,2073791999,2040237311,2006682623,1973127935,1939573247,1906018559,1855686655,1805354751,1755022847,1704690943,1654359039,1587249919,1520140799,1453031679,1369145343,1285258751,1201372159,1100708351,1000044543,882603519,765162495,630943999,496725503,345729791,177956863,10183935,-1699437825,-1716215297,-1732992769,-1766547457,-1800102145,-1833656833,-1867211521,-1900766209,-1934320897,-1967875585,-2018207489,-2068539649,-2118871809,2125763327,2058653951,1991544575,1924435199,1857325823,1773438975,1689552127,1588888063,1488223999,1387559679,1270118143,1152676607,1018457855,884238847,733242623,565468927,397695231,213144319,11815935,-1311918593,-1345473281,-1379027969,-1412582657,-1446137345,-1479692289,-1513247233,-1546802177,-1597134337,-1647466497,-1697798657,-1748130817,-1798463233,-1865572865,-1932682497,-1999792129,-2083678977,2127401215,2043514111,1942849791,1842185215,1724743423,1607301631,1473082367,1338863103,1187866367,1020092415,852318207,667766783,466437887,248331519,13447935,-924398849,-957953793,-991508737,-1025063681,-1058618625,-1092173569,-1142505729,-1192837889,-1243170305,-1293502721,-1343835137,-1410944769,-1478054401,-1545164289,-1629051393,-1712938497,-1796825857,-1897490433,-1998155009,-2098819841,2078705407,1961263103,1827043583,1676046591,1525049599,1357275135,1172723199,971394047,753287423,518403327,283518975,15079935,-570434049,-603988993,-637543937,-671098881,-704653825,-754986241,-805318657,-855651073,-905983489,-973093377,-1040203265,-1107313153,-1174423041,-1258310401,-1342197761,-1442862593,-1543527425,-1644192257,-1761634561,-1879076865,-2013296641,2147450879,1996453631,1828678911,1660904191,1476351999,1275022335,1056915199,822030591,570368511,301928959,16711935,-503325185,-536880129,-570435073,-603990017,-637544961,-671100161,-721432577,-771764993,-822097409,-872430081,-922762753,-989872641,-1056982529,-1124092673,-1191202817,-1275090433,-1358978049,-1459642881,-1560307969,-1660973057,-1778415617,-1895858177,-2030078209,2113891583,1962894079,1795119103,1610566655,1426013951,1224683775,1006576127,771691007,520028415,-452993537,-469771265,-503326209,-536881153,-570436097,-603991297,-637546497,-671101697,-721434113,-771766785,-822099457,-872432129,-922764801,-989874945,-1056985089,-1124095489,-1191205889,-1275093505,-1358981377,-1459646465,-1560311809,-1677754369,-1795197185,-1912640257,-2046860545,2097108991,1946110975,1778335487,1593782527,1392452095,1174344191,939458815,-419439105,-436216833,-452994561,-469772289,-503327233,-536882433,-570437633,-603992833,-637548033,-671103489,-721436161,-771768833,-822101505,-872434433,-922767361,-989877761,-1056988161,-1124098561,-1207986433,-1291874305,-1375762433,-1476427777,-1577093377,-1694536449,-1811979521,-1946200065,-2080420865,2063548159,1912549631,1744773631,1560220159,1358889215,-385884673,-402662401,-419440129,-436217857,-452995585,-469773569,-503328769,-536883969,-570439169,-603994625,-637550081,-671105537,-721438209,-771771137,-822104065,-872437249,-922770433,-989880833,-1056991489,-1124102145,-1191213057,-1275101185,-1358989569,-1459655425,-1560321281,-1677764609,-1795208193,-1912652033,-2046873345,2097095167,1946096127,1778319615,-335553025,-352330753,-369108481,-385886209,-402663937,-419441921,-436219905,-452997889,-486553089,-520108545,-553664001,-587219457,-620774913,-654330625,-687886337,-738219521,-788552705,-838885889,-889219329,-939552769,-1006663681,-1073774593,-1140885761,-1224774401,-1308663041,-1392551937,-1493218305,-1593884929,-1711329025,-1828773377,-1962995201,-2097217281,-285221377,-301999105,-318776833,-335554561,-352332289,-369110273,-385888257,-402666241,-419444225,-436222465,-453000705,-469778945,-503334401,-536890113,-570445825,-604001793,-637557761,-671113729,-721447169,-771780609,-822114305,-872448001,-922781953,-989893377,-1057004801,-1124116481,-1191228417,-1275117825,-1359007489,-1459674625,-1560342017,-1677786881,-234889729,-234890241,-251667969,-268445697,-285223425,-302001409,-318779393,-335557377,-352335361,-369113601,-385891841,-402670081,-419448321,-436226817,-453005313,-469784065,-503340033,-536896001,-570452225,-604008449,-637564929,-671121409,-704678145,-755012353,-805346561,-855681025,-906015745,-973127937,-1040240385,-1107353089,-1174466049,-1258356481,-234889729,-234890241,-234890753,-234891265,-234891777,-234892545,-234893313,-234894081,-234894849,-251673089,-268451329,-285229569,-302007809,-318786305,-335564801,-352343553,-369122305,-385901057,-402680065,-419459073,-436238337,-453017601,-486574337,-520131329,-553688321,-587245569,-620803073,-654360833,-687918849,-738254337,-788590081,-838926081,-234889729,-234890241,-234890753,-234891265,-234891777,-234892545,-234893313,-234894081,-234894849,-234895873,-234896897,-234897921,-234898945,-234900225,-234901505,-234903041,-234904577,-234906113,-234907905,-234909697,-234911745,-251691009,-268470529,-285250305,-302030081,-318810113,-335590401,-352370945,-369151745,-385932801,-402714113,-419495681,-8705,-9217,-9729,-10241,-10753,-11521,-12289,-13057,-13825,-14849,-15873,-16897,-17921,-19201,-20481,-22017,-23553,-25089,-26881,-28673,-30721,-32769,-35073,-37633,-40193,-43009,-46081,-49409,-52993,-56833,-60929,-65281,-926209,-926721,-927233,-927745,-928257,-929025,-929793,-930561,-931329,-932353,-933377,-934401,-935425,-936705,-937985,-939521,-941057,-1008129,-1075457,-1142785,-1210369,-1277953,-1345793,-1413889,-1481985,-1550337,-1618945,-1687809,-1756929,-1826305,-1895937,-2031361,-926209,-926721,-927233,-927745,-928257,-929025,-929793,-996097,-1062401,-1128961,-1195521,-1262081,-1328641,-1395457,-1462273,-1529345,-1596417,-1663489,-1730817,-1798145,-1865729,-1998849,-2132225,-2265857,-2399489,-2533377,-2667521,-2867457,-3067649,-3268097,-3468801,-3669761,-926209,-992257,-1058305,-1124353,-1190401,-1256705,-1323009,-1389313,-1455617,-1522177,-1588737,-1655297,-1721857,-1788673,-1855489,-1988097,-2120705,-2253313,-2386177,-2519041,-2652161,-2785281,-2984193,-3183361,-3382529,-3581953,-3847169,-4112641,-4378369,-4644353,-4976129,-5308161,-1188353,-1254401,-1320449,-1386497,-1452545,-1518849,-1585153,-1651457,-1717761,-1784321,-1850881,-1982977,-2115073,-2247425,-2379777,-2512385,-2644993,-2777601,-2976001,-3174401,-3373057,-3571713,-3836161,-4100865,-4365569,-4630529,-4961281,-5292289,-5689089,-6086145,-6483457,-6946561,-1384961,-1451009,-1517057,-1583105,-1649153,-1715457,-1781761,-1848065,-1979905,-2112001,-2244097,-2376193,-2508289,-2640641,-2838529,-3036673,-3234817,-3432961,-3631361,-3895297,-4159489,-4423681,-4688129,-5018369,-5348609,-5744641,-6140929,-6537473,-6999809,-7462401,-7990785,-8584961,-1581569,-1647617,-1713665,-1779713,-1845761,-1977601,-2109441,-2241281,-2373121,-2505217,-2637313,-2769409,-2967041,-3164929,-3362817,-3560961,-3759105,-4022785,-4286721,-4550657,-4880385,-5210113,-5540097,-5935873,-6331649,-6793217,-7255041,-7782657,-8310529,-8904193,-9563649,-10223361,-1712641,-1778689,-1844737,-1976321,-2107905,-2239745,-2371585,-2503425,-2635265,-2767361,-2964993,-3162625,-3360257,-3558145,-3821569,-4085249,-4348929,-4612609,-4942081,-5271553,-5666817,-6062081,-6457601,-6918913,-7380225,-7907329,-8434689,-9027841,-9686785,-10345985,-11070977,-11861761,-1843713,-1975297,-2106881,-2238465,-2370049,-2501889,-2633729,-2765569,-2962945,-3160577,-3358209,-3555841,-3753473,-4016897,-4280321,-4544001,-4873217,-5202433,-5531905,-5926913,-6322177,-6782977,-7244033,-7770881,-8297729,-8890369,-9548801,-10207489,-10931969,-11722241,-12578305,-13500161,-1974785,-2106369,-2237953,-2369537,-2501121,-2632961,-2830337,-3027713,-3225089,-3422721,-3620353,-3883521,-4146689,-4410113,-4673537,-5002753,-5331969,-5726721,-6121729,-6582273,-7043073,-7503873,-8030465,-8622849,-9215233,-9873409,-10597377,-11387137,-12242689,-13164033,-14085633,-15138561,-2236929,-2368513,-2500097,-2631681,-2763265,-2960641,-3158017,-3355393,-3552769,-3815937,-4079105,-4342273,-4605441,-4934401,-5263361,-5658113,-6052865,-6447617,-6908161,-7368705,-7895041,-8421377,-9013505,-9671425,-10329345,-11053057,-11842561,-12697857,-13618945,-14605825,-15658497,-16776961]
\ No newline at end of file diff --git a/release/scripts/flt_palettemanager.py b/release/scripts/flt_palettemanager.py deleted file mode 100644 index 6edaf2974ab..00000000000 --- a/release/scripts/flt_palettemanager.py +++ /dev/null @@ -1,388 +0,0 @@ -#!BPY - -""" -Name: 'FLT Palette Manager' -Blender: 240 -Group: 'Misc' -Tooltip: 'Manage FLT colors' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/2007" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ - -This script manages colors in OpenFlight databases. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Todo: --Figure out whats causing the PC speaker to beep when initializing... - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - -import Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -import flt_defaultp as defaultp -from flt_properties import * - - -palette_size = 12 -palette_x = 0 -palette_y = 0 - -colors = list() -curint = 1.0 -curswatch = 0 -#make a default palette, not very useful. -cinc = 1.0 / 1024.0 -cstep = 0.0 -picker = None -ptt = "" -for i in xrange(1024): - colors.append([cstep,cstep,cstep]) - cstep = cstep + cinc -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.getCurrent() - state["activeObject"] = state["activeScene"].getActiveObject() - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - return state - -def pack_face_index(index, intensity): - return ((127*intensity)+(128*index)) -def unpack_face_index(face_index): - index = face_index / 128 - intensity = float(face_index - 128.0 * index) / 127.0 - return(index,intensity) - -def event(evt,val): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - - areas = Blender.Window.GetScreenInfo() - curarea = Blender.Window.GetAreaID() - curRect = None - editmode = 0 - - for area in areas: - if area['id'] == curarea: - curRect = area['vertices'] - break - - if evt == Draw.LEFTMOUSE: - mval = Blender.Window.GetMouseCoords() - rastx = mval[0] - curRect[0] - rasty = mval[1] - curRect[1] - - swatchx = (rastx -palette_x) / palette_size #+state["palette_x"] - swatchy = (rasty -palette_y) / palette_size #+state["palette_y"] - if rastx > palette_x and rastx < (palette_x + palette_size * 32) and rasty > palette_y and rasty < (palette_y+ palette_size* 32): - if swatchx < 32 and swatchy < 32: - curswatch = (swatchx * 32) + swatchy - Draw.Redraw(1) - - elif swatchy < 34 and swatchx < 32: - curint = 1.0 - (float(rastx-palette_x)/(palette_size*32.0)) - Draw.Redraw(1) - - #copy current color and intensity to selected faces. - elif evt == Draw.CKEY: - - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - #retrieve color from palette - color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) - actmesh = state["activeMesh"] - if actmesh: - if(Blender.Window.GetKeyQualifiers() != Blender.Window.Qual["CTRL"]): - selfaces = list() - for face in actmesh.faces: - if face.sel: - selfaces.append(face) - - if not "FLT_COL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) - for face in actmesh.faces: - face.setProperty("FLT_COL",127) #default - try: - actmesh.activeColorLayer = "FLT_Fcol" - except: - actmesh.addColorLayer("FLT_Fcol") - actmesh.activeColorLayer = "FLT_Fcol" - - - for face in selfaces: - #First append packed index + color and store in face property - face.setProperty("FLT_COL",int(pack_face_index(curswatch,curint))) - #Save baked color to face vertex colors - for col in face.col: - col.r = int(color[0] * curint) - col.g = int(color[1] * curint) - col.b = int(color[2] * curint) - col.a = int(color[3] * curint) - else: - if Blender.Mesh.Mode() == Blender.Mesh.SelectModes['VERTEX']: - if not 'FLT_VCOL' in actmesh.verts.properties: - actmesh.verts.addPropertyLayer("FLT_VCOL",Blender.Mesh.PropertyTypes["INT"]) - for vert in actmesh.verts: - vert.setProperty("FLT_VCOL",127) - else: - for vert in actmesh.verts: - if vert.sel: - vert.setProperty("FLT_VCOL",int(pack_face_index(curswatch,curint))) - - if editmode: - Blender.Window.EditMode(1) - - Blender.Window.RedrawAll() - - #grab color and intensity from active face - elif evt == Draw.VKEY: - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - - - if activeFace: - if not "FLT_COL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_COL",Blender.Mesh.PropertyTypes["INT"]) - for face in actmesh.faces: - face.setProperty("FLT_COL",127) #default - try: - actmesh.activeColorLayer = "FLT_Fcol" - except: - actmesh.addColorLayer("FLT_Fcol") - actmesh.activeColorLayer = "FLT_Fcol" - tcol = activeFace.getProperty("FLT_COL") - (index,intensity) = unpack_face_index(tcol) - curswatch = index - curint = intensity - - if editmode: - Blender.Window.EditMode(1) - - Blender.Window.RedrawAll() - - elif evt == Draw.ESCKEY: - Draw.Exit() - - if editmode: - Blender.Window.EditMode(1) - -def update_all(): - global colors - state = update_state() - #update the baked FLT colors for all meshes. - for object in state["activeScene"].objects: - if object.type == "Mesh": - mesh = object.getData(mesh=True) - if 'FLT_COL' in mesh.faces.properties: - mesh.activeColorLayer = "FLT_Fcol" - for face in mesh.faces: - (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) - color = struct.unpack('>BBBB',struct.pack('>I',colors[index])) - #update the vertex colors for this face - for col in face.col: - col.r = int(color[0] * intensity) - col.g = int(color[1] * intensity) - col.b = int(color[2] * intensity) - col.a = 255 - - -def but_event(evt): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - global picker - state = update_state() - - if evt == 1: - if picker.val: - rval = (int(picker.val[0]*255),int(picker.val[1]*255),int(picker.val[2]*255),255) - rval = struct.pack('>BBBB',rval[0],rval[1],rval[2],rval[3]) - rval = struct.unpack('>i',rval) - colors[curswatch] = rval[0] - #go cd through all meshes and update their FLT colors - update_all() - - Draw.Redraw(1) -def init_pal(): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - - state = update_state() - - if not state["activeScene"].properties.has_key('FLT'): - state["activeScene"].properties['FLT'] = dict() - - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - state["activeScene"].properties['FLT']['Color Palette'] = defaultp.pal - colors = state["activeScene"].properties['FLT']['Color Palette'] - -def draw_palette(): - global palette_size - global palette_x - global palette_y - global colors - global curint - global curswatch - global picker - - state = update_state() - init_pal() - - ssize = palette_size - xpos = palette_x - cid = 0 - - highlight = [(palette_x,palette_y),(palette_x+palette_size,palette_y),(palette_x+palette_size,palette_y+palette_size),(palette_x,palette_y+palette_size)] - for x in xrange(32): - ypos = palette_y - for y in xrange(32): - color = struct.unpack('>BBBB',struct.pack('>I',colors[cid])) - glColor3f(color[0]/255.0,color[1]/255.0,color[2]/255.0) - glBegin(GL_POLYGON) - glVertex2i(xpos,ypos) - glVertex2i(xpos+ssize,ypos) - glVertex2i(xpos+ssize,ypos+ssize) - glVertex2i(xpos,ypos+ssize) - glEnd() - - if curswatch == cid: - highlight[0] = (xpos,ypos) - highlight[1] = (xpos+ssize,ypos) - highlight[2] = (xpos+ssize,ypos+ssize) - highlight[3] = (xpos,ypos+ssize) - - glColor3f(0.0,0.0,0.0) - glBegin(GL_LINE_LOOP) - glVertex2i(xpos,ypos) - glVertex2i(xpos+ssize,ypos) - glVertex2i(xpos+ssize,ypos+ssize) - glVertex2i(xpos,ypos+ssize) - glVertex2i(xpos,ypos) - glEnd() - - - cid = cid + 1 - ypos = ypos + ssize - - xpos = xpos + ssize - - #draw intensity gradient - color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) - color = [color[0]/255.0,color[1]/255.0,color[2]/255.0] - colsteps = [color[0]/255.0,color[1]/255.0,color[2]/255.0] - stripwidth = (palette_size * 32.0) / 256 - strippad = palette_size / 2.0 - - xpos = palette_x - grady = (palette_y + (palette_size * 32.0)) + strippad - for x in xrange(256): - color[0] = color[0] - colsteps[0] - color[1] = color[1] - colsteps[1] - color[2] = color[2] - colsteps[2] - - glColor3f(color[0], color[1] ,color[2]) - glBegin(GL_POLYGON) - glVertex2f(xpos,grady) - glVertex2f(xpos+stripwidth,grady) - glVertex2f(xpos+stripwidth,grady+palette_size) - glVertex2f(xpos,grady+palette_size) - glEnd() - xpos = xpos + stripwidth - - #draw intensity slider bar - #xposition == 512 - ((curint) * 512) - xpos = ((palette_size*32) * (1.0 - curint)) + palette_x - glColor3f(1.0,1.0,1.0) - glBegin(GL_LINE_LOOP) - glVertex2i(xpos-6,grady-1) - glVertex2i(xpos+6,grady-1) - glVertex2i(xpos+6,grady+palette_size+1) - glVertex2i(xpos-6,grady+palette_size+1) - #glVertex2i(xpos-6,grady+7) - glEnd() - - #draw color picker - color = struct.unpack('>BBBB',struct.pack('>I',colors[curswatch])) - pickcol = (color[0]/255.0,color[1]/255.0,color[2]/255.0) - picker = Blender.Draw.ColorPicker(1,highlight[0][0]+1,highlight[0][1]+1,ssize-2,ssize-2,pickcol,ptt) - - #draw highlight swatch - glColor3f(1.0,1.0,1.0) - glBegin(GL_LINE_LOOP) - glVertex2i(highlight[0][0],highlight[0][1]) - glVertex2i(highlight[1][0],highlight[1][1]) - glVertex2i(highlight[2][0],highlight[2][1]) - glVertex2i(highlight[3][0],highlight[3][1]) - glVertex2i(highlight[0][0],highlight[0][1]) - glEnd() - -def gui(): - glClearColor(0.5,0.5,0.5,1.0) - glClear(GL_COLOR_BUFFER_BIT) - draw_palette() - - -init_pal() -Draw.Register(gui,event,but_event) - diff --git a/release/scripts/flt_properties.py b/release/scripts/flt_properties.py deleted file mode 100644 index bc7c972ca66..00000000000 --- a/release/scripts/flt_properties.py +++ /dev/null @@ -1,628 +0,0 @@ -#!BPY -# flt_properties.py. For setting default OpenFLight ID property types -# Copyright (C) 2007 Blender Foundation -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -__bpydoc__ ="""\ -Utility functions and data defintions used by OpenFlight I/O and tool scripts. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. -""" - - -import struct - -bitsLSB = [2147483648] -for i in xrange(31): - bitsLSB.append(bitsLSB[-1]/2) -bitsRSB = bitsLSB[:] -bitsRSB.reverse() - -def pack_color(col): - return struct.pack('>B',col[3]) + struct.pack('>B',col[2]) + struct.pack('>B',col[1]) + struct.pack('>B',col[0]) - -def unpack_color(col): - string = struct.pack('>I', col) - r = struct.unpack('>B',string[3:4]) - g = struct.unpack('>B',string[2:3]) - b = struct.unpack('>B',string[1:2]) - a = struct.unpack('>B',string[0:1]) - return [r,g,b,a] - -def reverse_bits(len,num): - bitbucket = list() - rval = 0 - - for i in xrange(len): - if num & bitsRSB[i]: - bitbucket.append(1) - else: - bitbucket.append(0) - - bitbucket.reverse() - - for i, bit in enumerate(bitbucket): - if bit: - rval |= bitsLSB[i] - - return rval - - -opcode_name = { 0: 'db', - 1: 'head', - 2: 'grp', - 4: 'obj', - 5: 'face', - 10: 'push', - 11: 'pop', - 14: 'dof', - 19: 'push sub', - 20: 'pop sub', - 21: 'push ext', - 22: 'pop ext', - 23: 'cont', - 31: 'comment', - 32: 'color pal', - 33: 'long id', - 49: 'matrix', - 50: 'vector', - 52: 'multi-tex', - 53: 'uv lst', - 55: 'bsp', - 60: 'rep', - 61: 'inst ref', - 62: 'inst def', - 63: 'ext ref', - 64: 'tex pal', - 67: 'vert pal', - 68: 'vert w col', - 69: 'vert w col & norm', - 70: 'vert w col, norm & uv', - 71: 'vert w col & uv', - 72: 'vert lst', - 73: 'lod', - 74: 'bndin box', - 76: 'rot edge', - 78: 'trans', - 79: 'scl', - 80: 'rot pnt', - 81: 'rot and/or scale pnt', - 82: 'put', - 83: 'eyepoint & trackplane pal', - 84: 'mesh', - 85: 'local vert pool', - 86: 'mesh prim', - 87: 'road seg', - 88: 'road zone', - 89: 'morph vert lst', - 90: 'link pal', - 91: 'snd', - 92: 'rd path', - 93: 'snd pal', - 94: 'gen matrix', - 95: 'txt', - 96: 'sw', - 97: 'line styl pal', - 98: 'clip reg', - 100: 'ext', - 101: 'light src', - 102: 'light src pal', - 103: 'reserved', - 104: 'reserved', - 105: 'bndin sph', - 106: 'bndin cyl', - 107: 'bndin hull', - 108: 'bndin vol cntr', - 109: 'bndin vol orient', - 110: 'rsrvd', - 111: 'light pnt', - 112: 'tex map pal', - 113: 'mat pal', - 114: 'name tab', - 115: 'cat', - 116: 'cat dat', - 117: 'rsrvd', - 118: 'rsrvd', - 119: 'bounding hist', - 120: 'rsrvd', - 121: 'rsrvd', - 122: 'push attrib', - 123: 'pop attrib', - 124: 'rsrvd', - 125: 'rsrvd', - 126: 'curv', - 127: 'road const', - 128: 'light pnt appear pal', - 129: 'light pnt anim pal', - 130: 'indexed lp', - 131: 'lp sys', - 132: 'indx str', - 133: 'shdr pal'} - - -typecodes = ['c','C','s','S','i','I','f','d','t'] - -FLT_GRP = 2 -FLT_OBJ = 4 -FLT_LOD = 73 -FLT_XRF = 63 -FLT_DOF = 14 -FLT_ILP = 111 -FLT_DB = 1 -FLT_FCE = 5 - -#not actual opcodes -FLT_NUL = 0 -FLT_EXP = -1 - -#valid childtypes for each FLT node type -FLT_CHILDTYPES = { - FLT_GRP : [111,2,73,4,14,63], - FLT_OBJ : [111], - FLT_LOD : [111,2,73,4,14,63], - FLT_XRF : [], - FLT_DOF : [111,2,73,4,14,63], - FLT_ILP : [] -} - -#List of nodes that can have faces as children -FLT_FACETYPES = [ - FLT_GRP, - FLT_OBJ, - FLT_LOD, - FLT_DOF -] - -def write_prop(fw,type,value,length): - if type == 'c': - fw.write_char(value) - elif type == 'C': - fw.write_uchar(value) - elif type == 's': - fw.write_short(value) - elif type == 'S': - fw.write_ushort(value) - elif type == 'i': - fw.write_int(value) - elif type == 'I': - fw.write_uint(value) - elif type == 'd': - fw.write_double(value) - elif type == 'f': - fw.write_float(value) - elif type == 't': - fw.write_string(value,length) - -def read_prop(fw,type,length): - rval = None - if type == 'c': - rval = fw.read_char() - elif type == 'C': - rval = fw.read_uchar() - elif type == 's': - rval = fw.read_short() - elif type == 'S': - rval = fw.read_ushort() - elif type == 'i': - rval = fw.read_int() - elif type == 'I': - rval = fw.read_uint() - elif type == 'd': - rval = fw.read_double() - elif type == 'f': - rval = fw.read_float() - elif type == 't': - rval = fw.read_string(length) - return rval - - -FLTExt = { - '3t8!id' : 'Ext', - '4t8!sid' : '', - '5c!reserved': 0, - '6c!revision' : 0, - '7S!recordcode' : 0 -} -FLTGroup = { - '3t8!id' : 'G', - '4s!priority' : 0, - '5s!reserved1' : 0, - '6i!flags' : 0, - '7s!special1' : 0, - '8s!special2' : 0, - '9s!significance' : 0, - '10c!layer code' : 0, - '11c!reserved2' : 0, - '12i!reserved3' : 0, - '13i!loop count' : 0, - '14f!loop duration' : 0, - '15f!last frame duration' : 0 -} -FLTGroupDisplay = [5,11,12] - -FLTObject = { - '3t8!id' : 'O', - '4I!flags' : 0, - '5s!priority' : 0, - '6S!transp' : 0, - '7s!SFX1' : 0, - '8s!SFX2' : 0, - '9s!significance' : 0, - '10s!reserved' : 0 -} -FLTObjectDisplay = [10] - -FLTLOD = { - '3t8!id' : 'L', - '4i!reserved' : 0, - '5d!switch in' : 0, - '6d!switch out' : 0, - '7s!sfx ID1' : 0, - '8s!sfx ID2' : 0, - '9I!flags' : 0, - '10d!X co' : 0, - '11d!Y co' : 0, - '12d!Z co' : 0, - '13d!Transition' : 0, - '14d!Sig Size' : 0 -} -FLTLODDisplay = [4] - -FLTInlineLP = { - '3t8!id' : 'Lp', - '4s!smc' : 0, - '5s!fid' : 0, - '6C!back color: a' : 255, - '7C!back color: b' : 255, - '8C!back color: g' : 255, - '9C!back color: r' : 255, - '10i!display mode' : 0, - '11f!intensity' : 1.0, - '12f!back intensity' : 0.0, - '13f!minimum defocus' : 0.0, - '14f!maximum defocus' : 1.0, - '15i!fading mode' : 0, - '16i!fog punch mode' : 0, - '17i!directional mode' : 1, - '18i!range mode' : 0, - '19f!min pixel size' : 1.0, - '20f!max pixel size' : 1024, - '21f!actual size' : 0.25, - '22f!trans falloff pixel size' : 0.25, - '23f!trans falloff exponent' : 1.0, - '24f!trans falloff scalar' : 1.0, - '25f!trans falloff clamp' : 1.0, - '26f!fog scalar' : 0.25, - '27f!fog intensity' : 1.0, - '28f!size threshold' : 0.1, - '29i!directionality' : 0, - '30f!horizontal lobe angle' : 180.0, - '31f!vertical lobe angle' : 180.0, - '32f!lobe roll angle' : 0.0, - '33f!dir falloff exponent' : 1.0, - '34f!dir ambient intensity' : 0.1, - '35f!anim period' : 2, - '36f!anim phase' : 0, - '37f!anim enabled' : 1.0, - '38f!significance' : 0.0, - '39i!draw order' : 0, - '40I!flags' : 277004288, - '41f!roti' : 0, - '42f!rotj' : 0, - '43f!rotk' : 1.0 -} - -FLTInlineLPDisplay = [35,36,37,41,42,43] - -FLTXRef = { - '3t200!filename' : '', #we dont actually use this value on export - '4i!reserved' : 0, - '5I!flag' : -478150656, - '6s!bbox' : 0, - '7s!reserved' : 0 -} - -FLTXRefDisplay = [4,7,3] - -FLTDOF = { - '3t8!id' : 'D', - '4i!reserved' : 0, - '5d!ORIGX' : 0.0, - '6d!ORIGY' : 0.0, - '7d!ORIGZ' : 0.0, - '8d!XAXIS-X' : 10.0, - '9d!XAXIS-Y' : 0.0, - '10d!XAXIS-Z' : 0.0, - '11d!XYPLANE-X' : 0.0, - '12d!XYPLANE-Y' : 10.0, - '13d!XZPLANE-Z' : 0.0, - '14d!ZMIN' : 0.0, - '15d!ZMAX' : 0.0, - '16d!ZCUR' : 0.0, - '17d!ZSTEP' : 0.0, - '18d!YMIN' : 0.0, - '19d!YMAX' : 0.0, - '20d!YCUR' : 0.0, - '21d!YSTEP' : 0.0, - '22d!XMIN' : 0.0, - '23d!XMAX' : 0.0, - '24d!XCUR' : 0.0, - '25d!XSTEP' : 0.0, - '26d!PITCH-MIN' : 0.0, - '27d!PITCH-MAX' : 0.0, - '28d!PITCH-CUR' : 0.0, - '29d!PITCH-STEP' : 0.0, - '30d!ROLL-MIN' : 0.0, - '31d!ROLL-MAX' : 0.0, - '32d!ROLL-CUR' : 0.0, - '33d!ROLL-STEP' : 0.0, - '34d!YAW-MIN' : 0.0, - '35d!YAW-MAX' : 0.0, - '36d!YAW-CUR' : 0.0, - '37d!YAW-STEP' : 0.0, - '38d!ZSIZE-MIN' : 0.0, - '39d!ZSIZE-MAX' : 0.0, - '40d!ZSIZE-CUR' : 1.0, - '41d!ZSIZE-STEP' : 0.0, - '42d!YSIZE-MIN' : 0.0, - '43d!YSIZE-MAX' : 0.0, - '44d!YSIZE-CUR' : 1.0, - '45d!YSIZE-STEP' : 0.0, - '46d!XSIZE-MIN' : 0.0, - '47d!XSIZE-MAX' : 0.0, - '48d!XSIZE-CUR' : 1.0, - '49d!XSIZE-STEP' : 0.0, - '50I!FLAG' : 1897582, - '51i!reserved2' : 0 -} - -FLTDOFDisplay = [4] - -FLTImage = { - '3i!RealU Direction' : 0, - '4i!RealV Direction' : 0, - '5i!UpX' : 0, - '6i!UpY' : 0, - '7i!File Format' : 0, - '8i!Min Filter' : 6, - '9i!Mag Filter' : 1, - '10i!Wrap' : 0, - '11i!WrapU' : 0, - '12i!WrapV' : 0, - '13i!Modified' : 0, - '14i!PivotX' : 0, - '15i!PivotY' : 0, - '16i!Enviorment' : 0, - '17i!WhiteAlpha' : 0, - '18i!reserved1' : 0, - '19i!reserved2' : 0, - '20i!reserved3' : 0, - '21i!reserved4' : 0, - '22i!reserved5' : 0, - '23i!reserved6' : 0, - '24i!reserved7' : 0, - '25i!reserved8' : 0, - '26i!reserved9' : 0, - '27d!RealU Direction' : 0, - '28d!RealV Direction' : 0, - '29i!Origin' : 0, - '30i!Kernel no.' : 0, - '31i!Internal Format' : 0, - '32i!External Format' : 0, - '33i!MipMap Filter?' : 0, - '34f!MMF1' : 0.0, - '35f!MMF2' : 0.0, - '36f!MMF3' : 0.0, - '37f!MMF4' : 0.0, - '38f!MMF5' : 0.0, - '39f!MMF6' : 0.0, - '40f!MMF7' : 0.0, - '41f!MMF8' : 0.0, - '42i!Tex CPs?' : 0, - '43f!LOD0 CP' : 0.0, - '44f!Scale0 CP' : 0.0, - '45f!LOD1 CP' : 0.0, - '46f!Scale1 CP' : 0.0, - '47f!LOD2 CP' : 0.0, - '48f!Scale2 CP' : 0.0, - '49f!LOD3 CP' : 0.0, - '50f!Scale3 CP' : 0.0, - '51f!LOD4 CP' : 0.0, - '52f!Scale4 CP' : 0.0, - '53f!LOD5 CP' : 0.0, - '54f!Scale5 CP' : 0.0, - '55f!LOD6 CP' : 0.0, - '56f!Scale6 CP' : 0.0, - '57f!LOD7 CP' : 0.0, - '58f!Scale7 CP' : 0.0, - '59f!Control Clamp' : 0.0, - '60i!Mag Alpha Filter' : 0, - '61i!Mag Color Filter' : 0, - '62f!reserved10' : 0, - '63f!reserved11' : 0, - '64f!reserved12' : 0, - '65f!reserved13' : 0, - '66f!reserved14' : 0, - '67f!reserved15' : 0, - '68f!reserved16' : 0, - '69f!reserved17' : 0, - '70f!reserved18' : 0, - '71d!Lambert Central' : 0.0, - '72d!Lambert Upper' : 0.0, - '73d!Lambert Lower' : 0.0, - '74d!reserved19' : 0, - '75f!reserved20' : 0, - '76f!reserved21' : 0, - '77f!reserved22' : 0, - '78f!reserved23' : 0, - '79f!reserved24' : 0, - '80i!Tex Detail?' : 0, - '81i!Tex J' : 0, - '82i!Tex K' : 0, - '83i!Tex M' : 0, - '84i!Tex N' : 0, - '85i!Tex Scramble' : 0, - '86i!Tex Tile?' : 0, - '87f!Tex Tile LLU' : 0.0, - '88f!Tex Tile LLV' : 0.0, - '89f!Tex Tile URU' : 0.0, - '90f!Tex Tile URV' : 0.0, - '91i!Projection' : 0, - '92i!Earth Model' : 0, - '93i!reserved25' : 0, - '94i!UTM Zone' : 0, - '95i!Image Origin' : 0, - '96i!GPU' : 0, - '97i!reserved26' : 0, - '98i!reserved27' : 0, - '99i!GPU Hemi' : 0, - '100i!reserved41' : 0, - '101i!reserved42' : 0, - '102i!reserved43' : 0, - '103i!Cubemap' : 0, - '104t588!reserved44' : '', - '105t512!Comments' : '', - '106i!reserved28' : 0, - '107i!reserved29' : 0, - '108i!reserved30' : 0, - '109i!reserved31' : 0, - '110i!reserved32' : 0, - '111i!reserved33' : 0, - '112i!reserved34' : 0, - '113i!reserved35' : 0, - '114i!reserved36' : 0, - '115i!reserved37' : 0, - '116i!reserved38' : 0, - '117i!reserved39' : 0, - '118i!reserved40' : 0, - '119i!reserved45' : 0, - '120i!Format Version' : 0, - '121i!GPU num' : 0, -} - -FLTImageDisplay = [18,19,29,21,22,23,24,25,26,62,63,64,65,66,67,68,69,70,74,75,76,77,78,79,93,97,98,102,114] - -FLTHeader = { - '3t8!id' : 'db', - '4i!version' : 1620, - '5i!editversion' : 0, - '6t32!date' : 0, - '7s!NGID' : 0, - '8s!NLID' : 0, - '9s!NOID' : 0, - '10s!NFID' : 0, - '11s!UMULT' : 1, - '12c!units' : 0, - '13c!set white' : 0, - '14I!flags' : 0x80000000, - '15i!reserved1' : 0, - '16i!reserved2' : 0, - '17i!reserved3' : 0, - '18i!reserved4' : 0, - '19i!reserved5' : 0, - '20i!reserved6' : 0, - '21i!projection type' : 0, - '22i!reserved7' : 0, - '23i!reserved8' : 0, - '24i!reserved9' : 0, - '25i!reserved10' : 0, - '26i!reserved11' : 0, - '27i!reserved12' : 0, - '28i!reserved13' : 0, - '29s!NDID' : 0, - '30s!vstore' : 1, - '31i!origin' : 0, - '32d!sw x' : 0, - '33d!sw y' : 0, - '34d!dx' : 0, - '35d!dy' : 0, - '36s!NSID' : 0, - '37s!NPID' : 0, - '38i!reserved14' : 0, - '39i!reserved15' : 0, - '40s!NCID' : 0, - '41s!NTID' : 0, - '42s!NBID' : 0, - '43s!NWID' : 0, - '44i!reserved14' : 0, - '45d!sw lat' : 0, - '46d!sw lon' : 0, - '47d!ne lat' : 0, - '48d!ne lon' : 0, - '49d!origin lat' : 0, - '50d!origin lon' : 0, - '51d!lambert lat1' : 0, - '52d!lambert lat2' : 0, - '53s!NLSID' : 0, - '54s!NLPID' : 0, - '55s!NRID' : 0, - '56s!NCATID' : 0, - '57s!reserved15' : 0, - '58s!reserved16' : 0, - '59s!reserved17' : 0, - '60s!reserved18' : 0, - '61i!ellipsoid model' : 1, - '62s!NAID' : 0, - '63s!NCVID' : 0, - '64s!utm zone' : 0, - '65t6!reserved19' : 0, - '66d!dz' : 0, - '67d!radius' : 0, - '68S!NMID' : 0, - '69S!NLPSID' : 0, - '70i!reserved20' : 0, - '71d!major axis' : 0, - '72d!minor axis' : 0, -} - -FLT_Records = { - 2 : FLTGroup, - 4 : FLTObject, - 73 : FLTLOD, - 63 : FLTXRef, - 14 : FLTDOF, - 1 : FLTHeader, - 111 : FLTInlineLP, - 100 : FLTExt, - 'Image' : FLTImage -} - -def process_recordDefs(): - records = dict() - for record in FLT_Records: - props = dict() - for prop in FLT_Records[record]: - position = '' - slice = 0 - (format,name) = prop.split('!') - for i in format: - if i not in typecodes: - position = position + i - slice = slice + 1 - else: - break - type = format[slice:] - length = type[1:] - if len(length) == 0: - length = 1 - else: - type = type[0] - length = int(length) - - props[int(position)] = (type,length,prop) - records[record] = props - return records - - diff --git a/release/scripts/flt_toolbar.py b/release/scripts/flt_toolbar.py deleted file mode 100644 index a707b87f846..00000000000 --- a/release/scripts/flt_toolbar.py +++ /dev/null @@ -1,809 +0,0 @@ -#!BPY - -""" -Name: 'FLT Toolbar' -Blender: 240 -Group: 'Misc' -Tooltip: 'Tools for working with FLT databases' -""" - -__author__ = "Geoffrey Bantle" -__version__ = "1.0 11/21/07" -__email__ = ('scripts', 'Author, ') -__url__ = ('blender', 'blenderartists.org') - -__bpydoc__ ="""\ -This script provides tools for working with OpenFlight databases in Blender. OpenFlight is a -registered trademark of MultiGen-Paradigm, Inc. - -Feature overview and more availible at: -http://wiki.blender.org/index.php/Scripts/Manual/FLTools -""" - -# -------------------------------------------------------------------------- -# flt_palettemanager.py version 0.1 2005/04/08 -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# Copyright (C) 2007: Blender Foundation -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - -import Blender.Draw as Draw -from Blender.BGL import * -import Blender -import flt_properties -reload(flt_properties) -from flt_properties import * - -xrefprefix = "" -xrefstack = list() -vofsstack = list() -vquatstack = list() -prop_w = 256 -prop_h = 256 - - -#event codes -evcode = { - "XREF_MAKE" : 100, - "XREF_EDIT" : 101, - "XREF_FILE" : 102, - "XREF_PICK" : 103, - "XREF_SELECT" : 104, - "XREF_POP" : 105, - "XREF_PREFIX" : 106, - "FACE_NAME" : 200, - "FACE_MAKESUB" : 201, - "FACE_KILLSUB" : 202, - "FACE_SELSUB" : 203, - "SCENE_UPDATE" : 303, - "IDPROP_COPY" : 501, - "IDPROP_KILL" : 502, - "CLIGHT_MAKE" : 700, - "DFROMACT" : 701, - "FIXCOL" : 702 -} - -XREF_PREFIX = None -XREF_MAKE = None -XREF_EDIT = None -XREF_SELECT = None -XREF_POP = None -FACE_MAKESUB = None -FACE_SELSUB = None -FACE_KILLSUB = None -IDPROP_KILL = None -IDPROP_COPY = None -SCENE_UPDATE = None -CLIGHT_MAKE = None -DFROMACT = None -FIXCOL = None - - -def RGBtoHSV( r, g, b): - cmin = min( r, g, b ) - cmax = max( r, g, b ) - v = cmax - - if(cmax!=0.0): - s = (cmax-cmin)/cmax - else: - s = 0.0 - h = 0.0 - - if(s == 0.0): - h = -1.0 - else: - cdelta = cmax-cmin - rc = (cmax-r)/cdelta - gc = (cmax-g)/cdelta - bc = (cmax-b)/cdelta - if(r==cmax): - h = bc-gc - else: - if(g==cmax): - h = 2.0+rc-bc - else: - h = 4.0+gc-rc - h = h*60.0 - if(h<0.0): - h += 360.0 - - - h = h/360.0 - if(h < 0.0): - h = 0.0 - return (h,s,v) - - -def update_state(): - state = dict() - state["activeScene"] = Blender.Scene.GetCurrent() - state["activeObject"] = state["activeScene"].objects.active - if state["activeObject"] and not state["activeObject"].sel: - state["activeObject"] = None - state["activeMesh"] = None - if state["activeObject"] and state["activeObject"].type == 'Mesh': - state["activeMesh"] = state["activeObject"].getData(mesh=True) - - state["activeFace"] = None - if state["activeMesh"]: - if state["activeMesh"].faceUV and state["activeMesh"].activeFace != None: - state["activeFace"] = state["activeMesh"].faces[state["activeMesh"].activeFace] - - #update editmode - state["editmode"] = Blender.Window.EditMode() - - return state -def pack_face_index(index, intensity): - return ((127*intensity)+(128*index)) -def unpack_face_index(face_index): - index = face_index / 128 - intensity = float(face_index - 128.0 * index) / 127.0 - return(index,intensity) - -def idprops_append(object, typecode, props): - object.properties["FLT"] = dict() - object.properties["FLT"]['type'] = typecode - for prop in props: - object.properties["FLT"][prop] = props[prop] - object.properties["FLT"]['3t8!id'] = object.name - -def idprops_kill(object): - state = update_state() - if object and object.properties.has_key('FLT'): - object.properties.pop('FLT') - -def idprops_copy(source): - state = update_state() - if source.properties.has_key('FLT'): - for object in state["activeScene"].objects: - if object.sel and object != source and (state["activeScene"].Layers & object.Layers): - idprops_kill(object) - object.properties['FLT'] = dict() - for key in source.properties['FLT']: - object.properties['FLT'][key] = source.properties['FLT'][key] - -def unpack_color(color): - return struct.unpack('>BBBB',struct.pack('>I',color)) - - -def findColorKey(colordict, hsv): - hdelta = 0.001 - for key in colordict: - if not (((hsv[0] < (key[0] + hdelta)) and (hsv[0] > (key[0] - hdelta))) and ((hsv[1] < (key[1] + hdelta)) and (hsv[1] > (key[1] - hdelta)))): - return key - return None - -def hsvsort(a, b): - (index1, mag1) = a - (index2, mag2) = b - if mag1 > mag2: - return 1 - elif mag1 < mag2: - return -1 - return 0 - -def fix_colors(): - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - scene = state["activeScene"] - colors = None - if state["activeScene"].properties.has_key('FLT'): - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - pass - if not colors: - return - - #first build a HSV version of our palette - hsvpalette = list() - for swatch in colors: - color = unpack_color(swatch) - hsv = RGBtoHSV(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0) - hsvpalette.append(hsv) - - #collect all of our meshes - meshes = list() - for object in scene.objects.context: - if object.sel and object.type == 'Mesh': - mesh = object.getData(mesh=True) - if "FLT_COL" in mesh.faces.properties: - meshes.append(mesh) - - - #Now go through our meshes, and build a dictionary of face lists keyed according to (hue,saturation) of the baked color - colordict = dict() - for mesh in meshes: - for face in mesh.faces: - hsv = RGBtoHSV(face.col[0].r/255.0, face.col[0].g/255.0, face.col[0].b/255.0) #retrieve baked color - if colordict.has_key((hsv[0],hsv[1])): - colordict[(hsv[0],hsv[1])].append(face) - else: - colordict[(hsv[0],hsv[1])] = [face] - - - #for each color key in the color dict, build a list of distances from it to the values in hsvpalette and then quicksort them for closest match - for key in colordict: - maglist = list() - for i, hsv in enumerate(hsvpalette): - norm = Blender.Mathutils.Vector(hsv[0], hsv[1]) - Blender.Mathutils.Vector(key[0],key[1]) - maglist.append((i,norm.length)) - maglist.sort(hsvsort) - print maglist[0] - for face in colordict[key]: - (index, intensity) = unpack_face_index(face.getProperty("FLT_COL")) - newfindex = pack_face_index(maglist[0][0],intensity) - face.setProperty("FLT_COL", int(newfindex)) - - for mesh in meshes: - update_mesh_colors(colors,mesh) - - if editmode: - Blender.Window.EditMode(1) - - -def update_mesh_colors(colors, mesh): - if 'FLT_COL' in mesh.faces.properties: - mesh.activeColorLayer = "FLT_Fcol" - for face in mesh.faces: - (index,intensity) = unpack_face_index(face.getProperty('FLT_COL')) - color = struct.unpack('>BBBB',struct.pack('>I',colors[index])) - - if index == 0 and intensity == 0: - color = (255,255,255) - intensity = 1.0 - #update the vertex colors for this face - for col in face.col: - col.r = int(color[0] * intensity) - col.g = int(color[1] * intensity) - col.b = int(color[2] * intensity) - col.a = 255 - - -def update_all(): - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - colors = None - if state["activeScene"].properties.has_key('FLT'): - try: - colors = state["activeScene"].properties['FLT']['Color Palette'] - except: - pass - if colors: - #update the baked FLT colors for all meshes. - for object in state["activeScene"].objects: - if object.type == "Mesh": - mesh = object.getData(mesh=True) - update_mesh_colors(colors,mesh) - if editmode: - Blender.Window.EditMode(1) - -#Change this to find the deep parent -def xref_create(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - def findchildren(object): - children = list() - for candidate in state["activeScene"].objects: - if candidate.parent == object: - children.append(candidate) - retlist = list(children) - for child in children: - retlist = retlist + findchildren(child) - return retlist - - actObject = state["activeObject"] - if actObject and xrefprefix: - scenenames = list() - for scene in Blender.Scene.Get(): - scenenames.append(scene.name) - - if xrefprefix in scenenames: - #build a unique name for the xref... - suffix = 1 - found = False - while not found: - candidate = xrefprefix + str(suffix) - if not candidate in scenenames: - xrefname = candidate - found = True - suffix+=1 - else: - xrefname = xrefprefix - #create our XRef node - xnode = state["activeScene"].objects.new('Empty') - xnode.name = 'X:' + xrefname - xnode.properties['FLT'] = dict() - for prop in FLTXRef: - xnode.properties['FLT'][prop] = FLTXRef[prop] - xnode.properties['FLT']['3t200!filename'] = xrefname + '.flt' - xnode.properties['FLT']['type'] = 63 - xnode.enableDupGroup = True - xnode.DupGroup = Blender.Group.New(xrefname) #this is dangerous... be careful! - - #copy rot and loc of actObject - xnode.setLocation(actObject.getLocation()) - xnode.setEuler(actObject.getEuler()) - - #build the new scene - xrefscene = Blender.Scene.New(xrefname) - xrefscene.properties['FLT'] = dict() - xrefscene.properties['FLT']['Filename'] = xrefname - xrefscene.properties['FLT']['Main'] = 0 - - #find the children of actObject so that we can add them to the group - linkobjects = findchildren(actObject) - linkobjects.append(actObject) - for object in linkobjects: - xrefscene.objects.link(object) - state["activeScene"].objects.unlink(object) - xnode.DupGroup.objects.link(object) - #clear rotation of actObject and location - actObject.setLocation(0.0,0.0,0.0) - actObject.setEuler(0.0,0.0,0.0) - - xrefscene.update(1) - state["activeScene"].update(1) - -def xref_select(): - state = update_state() - candidates = list() - scenelist = [scene.name for scene in Blender.Scene.Get()] - for object in state["activeScene"].objects: - if object.type == 'Empty' and object.enableDupGroup == True and object.DupGroup: - candidates.append(object) - - for object in candidates: - if object.DupGroup.name in scenelist: - object.sel = 1 - -def xref_edit(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - actObject = state["activeObject"] - - if actObject and actObject.type == 'Empty' and actObject.DupGroup: -# if actObject.properties.has_key('FLT') and actObject.properties['FLT']['type'] == 63: - for FLTscene in Blender.Scene.Get(): - if FLTscene.properties.has_key('FLT') and FLTscene.name == actObject.DupGroup.name: - actObject.sel = 0 - xrefstack.append(state["activeScene"]) - vofsstack.append(Blender.Window.GetViewOffset()) - vquatstack.append(Blender.Window.GetViewQuat()) - FLTscene.makeCurrent() - Blender.Window.SetViewOffset(0.0,0.0,0.0) - -def xref_finish(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - if xrefstack: - scene = xrefstack.pop() - Blender.Window.SetViewQuat(vquatstack.pop()) - Blender.Window.SetViewOffset(vofsstack.pop()) - scene.makeCurrent() - - -def sortSub(a,b): - aindex = a.getProperty("FLT_ORIGINDEX") - bindex = b.getProperty("FLT_ORIGINDEX") - - if aindex > bindex: - return 1 - elif aindex < bindex: - return -1 - return 0 - -def subface_make(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - if actmesh: - if not "FLT_ORIGINDEX" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_ORIGINDEX",Blender.Mesh.PropertyTypes["INT"]) - for i, face in enumerate(actmesh.faces): - face.setProperty("FLT_ORIGINDEX",i) - if not "FLT_SFLEVEL" in actmesh.faces.properties: - actmesh.faces.addPropertyLayer("FLT_SFLEVEL",Blender.Mesh.PropertyTypes["INT"]) - - #attach the subfaces to the active face. Note, this doesnt really work 100 percent properly yet, just enough for one level! - if activeFace: - #steps: - #remove actface and selected faces from the facelist - #quicksort facelist - #append actface and subfaces to end of facelist. - #generate new indices - facelist = list() - sublist = list() - for face in actmesh.faces: - facelist.append(face) - for face in facelist: - if face == activeFace: - face.setProperty("FLT_SFLEVEL",0) - sublist.insert(0,face) - elif face.sel: - face.setProperty("FLT_SFLEVEL",1) - sublist.append(face) - for face in sublist: - facelist.remove(face) - facelist.sort(sortSub) - for face in sublist: - facelist.append(face) - for i, face in enumerate(facelist): - face.setProperty("FLT_ORIGINDEX",i) - else: - pass - - if editmode: - Blender.Window.EditMode(1) - -def subface_kill(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - if actmesh: - if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: - for i,face in enumerate(actmesh.faces): - face.setProperty("FLT_ORIGINDEX",i) - face.setProperty("FLT_SFLEVEL",0) - if editmode: - Blender.Window.EditMode(1) - -def subface_select(): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - editmode = 0 - if Blender.Window.EditMode(): - Blender.Window.EditMode(0) - editmode = 1 - state = update_state() - - actmesh = state["activeMesh"] - activeFace = state["activeFace"] - if actmesh and activeFace: - if "FLT_ORIGINDEX" in actmesh.faces.properties and "FLT_SFLEVEL" in actmesh.faces.properties: - facelist = list() - actIndex = None - sublevel = None - for face in actmesh.faces: - facelist.append(face) - facelist.sort(sortSub) - for i, face in enumerate(facelist): - if face == activeFace: - actIndex = i - sublevel = face.getProperty("FLT_SFLEVEL")+1 - break - leftover = facelist[actIndex+1:] - for face in leftover: - if face.getProperty("FLT_SFLEVEL") == sublevel: - face.sel = 1 - else: - break - if editmode: - Blender.Window.EditMode(1) - -def select_by_typecode(typecode): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - - state = update_state() - - for object in state["activeScene"].objects: - if object.properties.has_key('FLT') and object.properties['FLT']['type'] == typecode and state["activeScene"].Layers & object.Layers: - object.select(1) -def clight_make(): - state = update_state() - actmesh = state["activeMesh"] - actobj = state["activeObject"] - - if actobj and actmesh: - actobj.properties['FLT'] = dict() - actobj.properties['FLT']['type'] = 111 - for prop in FLTInlineLP: - actobj.properties['FLT'][prop] = FLTInlineLP[prop] - - actmesh.verts.addPropertyLayer("FLT_VCOL", Blender.Mesh.PropertyTypes["INT"]) - for v in actmesh.verts: - v.setProperty("FLT_VCOL", 83815) - -def dfromact(): - state = update_state() - actobj = state["activeObject"] - actscene = state["activeScene"] - dof = None - - for object in actscene.objects.context: - if object.sel and (object != actobj): - if not dof: - dof = object - else: - break - - if not dof: - return - - if 'FLT' not in dof.properties: - dof.properties['FLT'] = dict() - - #Warning! assumes 1 BU == 10 meters. - #do origin - dof.properties['FLT']['5d!ORIGX'] = actobj.getLocation('worldspace')[0]*10.0 - dof.properties['FLT']['6d!ORIGY'] = actobj.getLocation('worldspace')[1]*10.0 - dof.properties['FLT']['7d!ORIGZ'] = actobj.getLocation('worldspace')[2]*10.0 - #do X axis - x = Blender.Mathutils.Vector(1.0,0.0,0.0) - x = x * actobj.getMatrix('worldspace') - x = x * 10.0 - dof.properties['FLT']['8d!XAXIS-X'] = x[0] - dof.properties['FLT']['9d!XAXIS-Y'] = x[1] - dof.properties['FLT']['10d!XAXIS-Z'] = x[2] - #do X/Y plane - x = Blender.Mathutils.Vector(1.0,1.0,0.0) - x.normalize() - x = x * actobj.getMatrix('worldspace') - x = x * 10.0 - dof.properties['FLT']['11d!XYPLANE-X'] = x[0] - dof.properties['FLT']['12d!XYPLANE-Y'] = x[1] - dof.properties['FLT']['13d!XZPLANE-Z'] = x[2] - - - - - -def event(evt,val): - if evt == Draw.ESCKEY: - Draw.Exit() - -def but_event(evt): - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - #do Xref buttons - if evt == evcode["XREF_PREFIX"]: - xrefprefix = XREF_PREFIX.val - if evt == evcode["XREF_EDIT"]: - xref_edit() - if evt == evcode["XREF_SELECT"]: - xref_select() - if evt == evcode["XREF_MAKE"]: - xref_create() - #do scene buttons - if evt == evcode["SCENE_UPDATE"]: - update_all() - #do face buttons - if evt == evcode["FACE_MAKESUB"]: - subface_make() - if evt== evcode["FACE_KILLSUB"]: - subface_kill() - if evt== evcode["FACE_SELSUB"]: - subface_select() - #common buttons - if evt == evcode["IDPROP_KILL"]: - if state["activeObject"]: - idprops_kill(state["activeObject"]) - if evt == evcode["IDPROP_COPY"]: - if state["activeObject"]: - idprops_copy(state["activeObject"]) - if evt == evcode["XREF_POP"]: - xref_finish() - if evt == evcode["CLIGHT_MAKE"]: - clight_make() - if evt == evcode["DFROMACT"]: - dfromact() - if evt == evcode["FIXCOL"]: - fix_colors() - Draw.Redraw(1) - Blender.Window.RedrawAll() - - -def box(x,y,w,h,c,mode): - glColor3f(c[0],c[1],c[2]) - if mode == "outline": - glBegin(GL_LINE_LOOP) - else: - glBegin(GL_POLYGON) - glVertex2i(x,y) - glVertex2i(x+w,y) - glVertex2i(x+w,y+h) - glVertex2i(x,y+h) - glEnd() - -def draw_postcommon(x,y,finaly): - global sheetlabel - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - width = prop_w - height = prop_h - - #draw the header - glColor3f(0.15,0.15,0.15) - glBegin(GL_POLYGON) - glVertex2i(x-1,y) - glVertex2i(x+width+1,y) - glVertex2i(x+width+1,y-25) - glVertex2i(x-1,y-25) - glEnd() - glColor3f(1,1,1) - glRasterPos2i(x,y-20) - sheetlabel = Blender.Draw.Text("FLT Tools Panel") - #draw the box outline - glColor3f(0,0,0) - glBegin(GL_LINE_LOOP) - glVertex2i(x-1,y) - glVertex2i(x+1+width,y) - glVertex2i(x+1+width,finaly-1) - glVertex2i(x-1,finaly-1) - glEnd() - return finaly - - -def draw_propsheet(x,y): - global XREF_PREFIX - global XREF_MAKE - global XREF_EDIT - global XREF_SELECT - global XREF_POP - global FACE_MAKESUB - global FACE_SELSUB - global FACE_KILLSUB - global IDPROP_KILL - global IDPROP_COPY - global SCENE_UPDATE - global DFROMACT - global FIXCOL - - global CLIGHT_MAKE - global xrefprefix - global xrefstack - global vofsstack - global vquatstack - global prop_w - global prop_h - global evcode - - state = update_state() - - width = prop_w - height = prop_h - origx = x - origy = y - - #draw Xref tools - y = y-20 - XREF_PREFIX = Blender.Draw.String("XRef Name:",evcode["XREF_PREFIX"],x,y,width,20,xrefprefix,18,"Xref prefix name, Actual name is generated from this") - y = y-20 - XREF_MAKE = Blender.Draw.PushButton("Make XRef",evcode["XREF_MAKE"],x,y,width,20,"Make External Reference") - y = y-20 - XREF_EDIT = Blender.Draw.PushButton("Edit XRef",evcode["XREF_EDIT"],x,y,width,20,"Edit External Reference") - y = y-20 - XREF_SELECT = Blender.Draw.PushButton("Select XRefs",evcode["XREF_SELECT"],x,y,width,20,"Select External References") - y = y - 20 - XREF_POP = Blender.Draw.PushButton("Return to previous scene",evcode["XREF_POP"],x,y,width,20,"Go up one level in xref hierarchy") - - #Draw facetools - y = y-20 - FACE_MAKESUB = Blender.Draw.PushButton("Make Subfaces",evcode["FACE_MAKESUB"],x,y,width,20,"Make subfaces") - y = y-20 - FACE_SELSUB = Blender.Draw.PushButton("Select Subfaces",evcode["FACE_SELSUB"],x,y,width,20,"Select subfaces") - y = y-20 - FACE_KILLSUB = Blender.Draw.PushButton("Kill Subfaces",evcode["FACE_KILLSUB"],x,y,width,20,"Kill subfaces") - - #Draw ID Property tools - y = y - 20 - IDPROP_KILL = Blender.Draw.PushButton("Delete ID props",evcode["IDPROP_KILL"],x,y,width,20,"Delete ID props") - y = y - 20 - IDPROP_COPY = Blender.Draw.PushButton("Copy to selected",evcode["IDPROP_COPY"],x,y,width,20, "Copy from active to all selected") - - y= y - 20 - CLIGHT_MAKE = Blender.Draw.PushButton("Make Light Point", evcode["CLIGHT_MAKE"],x,y,width,20,"Create inline light points from current mesh") - #General tools - y = y-20 - SCENE_UPDATE = Blender.Draw.PushButton("Update All",evcode["SCENE_UPDATE"],x,y,width,20,"Update all vertex colors") - - y=y-20 - DFROMACT = Blender.Draw.PushButton("Dof from Active", evcode["DFROMACT"],x,y,width,20,"Get Dof origin from active object") - y=y-20 - FIXCOL = Blender.Draw.PushButton("Fix Colors", evcode["FIXCOL"],x,y,width,20,"Fix baked FLT colors of selected meshes") - draw_postcommon(origx, origy,y) - -def gui(): - #draw the propsheet/toolbox. - psheety = 300 - #psheetx = psheety + 10 - draw_propsheet(0,psheety) -Draw.Register(gui,event,but_event) -
\ No newline at end of file diff --git a/release/scripts/weightpaint_invert.py b/release/scripts/weightpaint_invert.py deleted file mode 100644 index cdae83a9d50..00000000000 --- a/release/scripts/weightpaint_invert.py +++ /dev/null @@ -1,95 +0,0 @@ -#!BPY -""" -Name: 'Invert Active Group' -Blender: 245 -Group: 'WeightPaint' -Tooltip: 'Invert the active vertex group' -""" - -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- -import Blender -from Blender import Scene, Mesh, Window, sys - -import BPyMessages -import bpy - -def vgroup_invert(ob_orig, me): - if not me.getVertGroupNames(): - return - group_act = me.activeGroup - if group_act == None: - return - - group_data = me.getVertsFromGroup(group_act, 1) - - weights= [1.0] * len(me.verts) # 1.0 - initialize inverted - - group_data = me.getVertsFromGroup(group_act, 1) # (i,w) tuples. - - me.removeVertGroup(group_act) # messes up the active group. - for i,w in group_data: - weights[i] = 1.0-w - - me.addVertGroup(group_act) - - rep = Blender.Mesh.AssignModes.REPLACE - vertList= [None] - for i,weight in enumerate(weights): - vertList[0] = i - me.assignVertsToGroup(group_act, vertList, weight, rep) - - me.activeGroup = group_act - me.update() - -def main(): - - # Gets the current scene, there can be many scenes in 1 blend file. - sce = bpy.data.scenes.active - - # Get the active object, there can only ever be 1 - # and the active object is always the editmode object. - ob_act = sce.objects.active - - if not ob_act or ob_act.type != 'Mesh': - BPyMessages.Error_NoMeshActive() - return - - # Saves the editmode state and go's out of - # editmode if its enabled, we cant make - # changes to the mesh data while in editmode. - is_editmode = Window.EditMode() - Window.EditMode(0) - - Window.WaitCursor(1) - me = ob_act.getData(mesh=1) # old NMesh api is default - t = sys.time() - - # Run the mesh editing function - vgroup_invert(ob_act, me) - - # Timing the script is a good way to be aware on any speed hits when scripting - print 'Invert VGroup in %.2f seconds' % (sys.time()-t) - Window.WaitCursor(0) - if is_editmode: Window.EditMode(1) - -# This lets you can import the script without running it -if __name__ == '__main__': - main()
\ No newline at end of file diff --git a/release/scripts/wizard_curve2tree.py b/release/scripts/wizard_curve2tree.py deleted file mode 100644 index eb27f1ca0f5..00000000000 --- a/release/scripts/wizard_curve2tree.py +++ /dev/null @@ -1,4034 +0,0 @@ -#!BPY -""" -Name: 'Tree from Curves' -Blender: 245 -Group: 'Wizards' -Tip: 'Generate trees from curve shapes' -""" - -__author__ = "Campbell Barton" -__url__ = ['www.blender.org', 'blenderartists.org'] -__version__ = "0.1" - -__bpydoc__ = """\ - -""" - -# -------------------------------------------------------------------------- -# Tree from Curves v0.1 by Campbell Barton (AKA Ideasman42) -# -------------------------------------------------------------------------- -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# -------------------------------------------------------------------------- - -import bpy -import Blender -import BPyMesh -from Blender.Mathutils import Vector, Matrix, CrossVecs, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix, RotationMatrix, Rand -from Blender.Geometry import ClosestPointOnLine -from Blender.Noise import randuvec - -GLOBALS = {} -GLOBALS['non_bez_error'] = 0 - -''' -def debugVec(v1,v2): - sce = bpy.data.scenes.active - me = bpy.data.meshes.new() - me.verts.extend( [v1,v2] ) - me.edges.extend( [(0,1)] ) - sce.objects.new(me) -''' - -def AngleBetweenVecsSafe(a1, a2): - try: - return AngleBetweenVecs(a1,a2) - except: - return 180.0 - -# Copied from blender, we could wrap this! - BKE_curve.c -# But probably not toooo bad in python -def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis): - f= float(steps) - rt0= q0 - rt1= 3.0*(q1-q0)/f - f*= f - rt2= 3.0*(q0-2.0*q1+q2)/f - f*= steps - rt3= (q3-q0+3.0*(q1-q2))/f - - q0= rt0 - q1= rt1+rt2+rt3 - q2= 2*rt2+6*rt3 - q3= 6*rt3 - if axis == None: - for a in xrange(steps+1): - pointlist[a] = q0 - q0+= q1 - q1+= q2 - q2+= q3; - - else: - for a in xrange(steps+1): - pointlist[a][axis] = q0 - q0+= q1 - q1+= q2 - q2+= q3; - -def points_from_bezier_seg(steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2): - - # x,y,z,axis - for ii in (0,1,2): - forward_diff_bezier(bez1_vec[1][ii], bez1_vec[2][ii], bez2_vec[0][ii], bez2_vec[1][ii], pointlist, steps, ii) - - # radius - no axis, Copied from blenders BBone roll interpolation. - forward_diff_bezier(radius1, radius1 + 0.390464*(radius2-radius1), radius2 - 0.390464*(radius2-radius1), radius2, radlist, steps, None) - - -def debug_pt(co): - Blender.Window.SetCursorPos(tuple(co)) - Blender.Window.RedrawAll() - print 'debugging', co - -def freshMesh(mesh): - ''' - Utility function to get a new mesh or clear the existing one, but dont clear everything. - ''' - if mesh: - materials = mesh.materials - mesh.verts = None - for group in mesh.getVertGroupNames(): - mesh.removeVertGroup(group) - - # Add materials back - mesh.materials = materials - else: - mesh = bpy.data.meshes.new() - - return mesh - -def getObFromName(name): - if name: - try: return bpy.data.objects[name] - except: return None - else: - return None - -def getGroupFromName(name): - if name: - try: return bpy.data.groups[name] - except: return None - else: - return None - -def closestVecIndex(vec, vecls): - best= -1 - best_dist = 100000000 - for i, vec_test in enumerate(vecls): - # Dont use yet, we may want to tho - if vec_test: # Seems odd, but use this so we can disable some verts in the list. - dist = (vec-vec_test).length - if dist < best_dist: - best = i - best_dist = dist - - return best - -IRATIONAL_NUM = 22.0/7.0 -def next_random_num(rnd): - ''' - return a random number between 0.0 and 1.0 - ''' - rnd[0] += (rnd[0] * IRATIONAL_NUM) % 1 - # prevent - if rnd[0] > 1000000: - rnd[0]-=1000000 - return rnd[0] % 1 - -eul = 0.00001 - -BRANCH_TYPE_CURVE = 0 -BRANCH_TYPE_GROWN = 1 -BRANCH_TYPE_FILL = 2 - -class tree: - def __init__(self): - self.branches_all = [] - self.branches_root = [] - self.branches_twigs = [] - self.mesh = None - self.armature = None - self.objectCurve = None - self.objectCurveMat = None - self.objectCurveIMat = None - - self.objectTwigBounds = None # use for twigs only at the moment. - self.objectTwigBoundsIMat = None - self.objectTwigBoundsMat = None - self.objectTwigBoundsMesh = None - - self.objectLeafBounds = None - self.objectLeafBoundsIMat = None - self.objectLeafBoundsMesh = None - - self.limbScale = 1.0 - - self.debug_objects = [] - self.steps = 6 # defalt, curve overwrites - - def __repr__(self): - s = '' - s += '[Tree]' - s += ' limbScale: %.6f' % self.limbScale - s += ' object: %s' % self.objectCurve - - for brch in self.branches_root: - s += str(brch) - return s - - def fromCurve(self, objectCurve): - # Now calculate the normals - self.objectCurve = objectCurve - self.objectCurveMat = objectCurve.matrixWorld - self.objectCurveIMat = self.objectCurveMat.copy().invert() - curve = objectCurve.data - self.steps = curve.resolu # curve resolution - - # Set the curve object scale - if curve.bevob: - # A bit of a hack to guess the size of the curve object if you have one. - bb = curve.bevob.boundingBox - # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED - self.limbScale = (bb[0] - bb[7]).length / 1.8 - elif curve.ext2 != 0.0: - self.limbScale = curve.ext2 * 1.5 - - # forward_diff_bezier will fill in the blanks - # nice we can reuse these for every curve segment :) - pointlist = [[None, None, None] for i in xrange(self.steps+1)] - radlist = [ None for i in xrange(self.steps+1) ] - - for spline in curve: - - if len(spline) < 2: # Ignore single point splines - continue - - if spline.type != 1: # 0 poly, 1 bez, 4 nurbs - GLOBALS['non_bez_error'] = 1 - continue - - - brch = branch() - brch.type = BRANCH_TYPE_CURVE - - - - bez_list = list(spline) - for i in xrange(1, len(bez_list)): - bez1 = bez_list[i-1] - bez2 = bez_list[i] - vec1 = bez1.vec - vec2 = bez2.vec - if abs(vec1[1][0]-vec2[1][0]) > 0.000001 or\ - abs(vec1[1][1]-vec2[1][1]) > 0.000001 or\ - abs(vec1[1][2]-vec2[1][2]) > 0.000001: - - points_from_bezier_seg(self.steps, pointlist, radlist, vec1, vec2, bez1.radius, bez2.radius) - - # remove endpoint for all but the last - len_pointlist = len(pointlist) - if i != len(bez_list)-1: - len_pointlist -= 1 - - brch.bpoints.extend([ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii] * self.limbScale) for ii in xrange(len_pointlist) ]) - - # Finalize once point data is there - if brch.bpoints: - # if all points are in the same location, this is possible - self.branches_all.append(brch) - if brch.bpoints[0].radius < brch.bpoints[-1].radius: # This means we dont have to worry about curve direction. - brch.bpoints.reverse() - brch.calcData() - - # Sort from big to small, so big branches get priority - self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius ) - - - def closestBranchPt(self, co): - best_brch = None - best_pt = None - best_dist = 10000000000 - for brch in self.branches_all: - for pt in brch.bpoints: - # if pt.inTwigBounds: # only find twigs, give different results for leaves - l = (pt.co-co).length - if l < best_dist: - best_dist = l - best_brch = brch - best_pt = pt - return best_brch, best_pt - - def setTwigBounds(self, objectMesh): - self.objectTwigBounds = objectMesh - self.objectTwigBoundsMesh = objectMesh.getData(mesh=1) - self.objectTwigBoundsMat = objectMesh.matrixWorld.copy() - self.objectTwigBoundsIMat = self.objectTwigBoundsMat.copy().invert() - - for brch in self.branches_all: - brch.calcTwigBounds(self) - - def setLeafBounds(self, objectMesh): - self.objectLeafBounds = objectMesh - self.objectLeafBoundsMesh = objectMesh.getData(mesh=1) - self.objectLeafBoundsIMat = objectMesh.matrixWorld.copy().invert() - - def isPointInTwigBounds(self, co, selected_only=False): - return self.objectTwigBoundsMesh.pointInside(co * self.objectCurveMat * self.objectTwigBoundsIMat, selected_only) - - def isPointInLeafBounds(self, co, selected_only=False): - return self.objectLeafBoundsMesh.pointInside(co * self.objectCurveMat * self.objectLeafBoundsIMat, selected_only) - - def resetTags(self, value): - for brch in self.branches_all: - brch.tag = value - - def buildConnections( self,\ - sloppy = 1.0,\ - connect_base_trim = 1.0,\ - do_twigs = False,\ - twig_ratio = 2.0,\ - twig_select_mode = 0,\ - twig_select_factor = 0.5,\ - twig_scale = 0.8,\ - twig_scale_width = 1.0,\ - twig_random_orientation = 180,\ - twig_random_angle = 33,\ - twig_recursive=True,\ - twig_recursive_limit=3,\ - twig_ob_bounds=None,\ - twig_ob_bounds_prune=True,\ - twig_ob_bounds_prune_taper=1.0,\ - twig_placement_maxradius=10.0,\ - twig_placement_maxtwig=0,\ - twig_follow_parent=0.0,\ - twig_follow_x=0.0,\ - twig_follow_y=0.0,\ - twig_follow_z=0.0,\ - do_variation = 0,\ - variation_seed = 1,\ - variation_orientation = 0.0,\ - variation_scale = 0.0,\ - do_twigs_fill = 0,\ - twig_fill_levels=4,\ - twig_fill_rand_scale=0.0,\ - twig_fill_fork_angle_max=180.0,\ - twig_fill_radius_min=0.1,\ - twig_fill_radius_factor=0.75,\ - twig_fill_shape_type=0,\ - twig_fill_shape_rand=0.0,\ - twig_fill_shape_power=0.3,\ - ): - ''' - build tree data - fromCurve must run first - ''' - - - # Sort the branchs by the first radius, so big branchs get joins first - ### self.branches_all.sort( key = lambda brch: brch.bpoints[0].radius ) - - #self.branches_all.reverse() - - # Connect branches - for i in xrange(len(self.branches_all)): - brch_i = self.branches_all[i] - - for j in xrange(len(self.branches_all)): - if i != j: - # See if any of the points match this branch - # see if Branch 'i' is the child of branch 'j' - - brch_j = self.branches_all[j] - - if not brch_j.inParentChain(brch_i): # So we dont make cyclic tree! - - pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co) - - # Check its in range, allow for a bit out - hense the sloppy - # The second check in the following IF was added incase the point is close enough to the line but the midpoint is further away - # ...in this case the the resulting mesh will be adjusted to fit the join so its best to make it. - if (dist < pt_best_j.radius * sloppy) or \ - ((brch_i.bpoints[0].co - pt_best_j.co).length < pt_best_j.radius * sloppy): - - - brch_i.parent_pt = pt_best_j - pt_best_j.childCount += 1 # dont remove me - - brch_i.baseTrim(connect_base_trim) - - ''' - if pt_best_j.childCount>4: - raise "ERROR" - ''' - - # addas a member of best_j.children later when we have the geometry info available. - - #### print "Found Connection!!!", i, j - break # go onto the next branch - - """ - children = [brch_child for brch_child in pt.children] - if children: - # This pt is one side of the segment, pt.next joins this segment. - # calculate the median point the 2 segments would spanal - # Once this is done we need to adjust 2 things - # 1) move both segments up/down so they match the branches best. - # 2) set the spacing of the segments around the point. - - - # First try to get the ideal some space around each joint - # the spacing shoule be an average of - for brch.bpoints: - """ - - ''' - for brch in self.branches_all: - brch.checkPointList() - ''' - - # Variations - use for making multiple versions of the same tree. - if do_variation: - irational_num = 22.0/7.0 # use to make the random number more odd - rnd = [variation_seed] - - # Add children temporarily - for brch in self.branches_all: - if brch.parent_pt: - rnd_rot = ((next_random_num(rnd) * variation_orientation) - 0.5) * 720 - mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no) - rnd_sca = 1 + ((next_random_num(rnd)-0.5)* variation_scale ) - mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca]) - # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no) - brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co) - - if (do_twigs or do_twigs_fill) and twig_ob_bounds: # Only spawn twigs inside this mesh - self.setTwigBounds(twig_ob_bounds) - - # Important we so this with existing parent/child but before connecting and calculating verts. - if do_twigs: - - # scale values down - twig_random_orientation= twig_random_orientation/360.0 - twig_random_angle= twig_random_angle/360.0 - - irational_num = 22.0/7.0 # use to make the random number more odd - - if not twig_recursive: - twig_recursive_limit = 0 - - self.buildTwigs(twig_ratio, twig_select_mode, twig_select_factor) - - branches_twig_attached = [] - - # This wont add all! :/ - brch_twig_index = 0 - brch_twig_index_LAST = -1 # use this to prevent in inf loop, since its possible we cant place every branch - while brch_twig_index < len(self.branches_twigs) and brch_twig_index_LAST != brch_twig_index: - ###print "While" - ### print brch_twig_index, len(self.branches_twigs) # if this dosnt change, quit the while - - brch_twig_index_LAST = brch_twig_index - - # new twigs have been added, recalculate - branches_twig_sort = [brch.bestTwigSegment() for brch in self.branches_all] - branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list - - for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used. - if twig_pt_index != -1 and \ - (twig_recursive_limit == 0 or brch_parent.generation < twig_recursive_limit) and \ - (twig_placement_maxtwig == 0 or brch_parent.twig_count < twig_placement_maxtwig) and \ - brch_parent.bpoints[twig_pt_index].radius < twig_placement_maxradius: - - if brch_twig_index >= len(self.branches_twigs): - break - - brch_twig = self.branches_twigs[brch_twig_index] - parent_pt = brch_parent.bpoints[twig_pt_index] - - brch_twig.parent_pt = parent_pt - parent_pt.childCount += 1 - - # Scale this twig using this way... - # The size of the parent, scaled by the parent point's radius, - # ...compared to the parent branch;s root point radius. - # Also take into account the length of the parent branch - # Use this for pretend random numbers too. - scale = twig_scale * (parent_pt.branch.bpoints[0].radius / brch_twig.bpoints[0].radius) * (parent_pt.radius / parent_pt.branch.bpoints[0].radius) - - # Random orientation - # THIS IS NOT RANDOM - Dont be real random so we can always get re-produceale results. - if twig_random_orientation: rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation - else: rnd1 = 0.0 - if twig_random_angle: rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle - else: rnd2 = 0.0 - - # Align this with the existing branch - angle = AngleBetweenVecsSafe(zup, parent_pt.no) - cross = CrossVecs(zup, parent_pt.no) - mat_align = RotationMatrix(angle, 3, 'r', cross) - - # Use the bend on the point to work out which way to make the branch point! - if parent_pt.prev: cross = CrossVecs(parent_pt.no, parent_pt.prev.no - parent_pt.no) - else: cross = CrossVecs(parent_pt.no, parent_pt.next.no - parent_pt.no) - - if parent_pt.branch.parent_pt: - angle = AngleBetweenVecsSafe(parent_pt.branch.parent_pt.no, parent_pt.no) - else: - # Should add a UI for this... only happens when twigs come off a root branch - angle = 66 - - mat_branch_angle = RotationMatrix(angle+rnd1, 3, 'r', cross) - mat_scale = Matrix([scale,0,0],[0,scale,0],[0,0,scale]) - - mat_orientation = RotationMatrix(rnd2, 3, 'r', parent_pt.no) - - if twig_scale_width != 1.0: - # adjust length - no radius adjusting - for pt in brch_twig.bpoints: - pt.radius *= twig_scale_width - - brch_twig.transform(mat_scale * mat_branch_angle * mat_align * mat_orientation, parent_pt.co) - - # Follow the parent normal - if twig_follow_parent or twig_follow_x or twig_follow_y or twig_follow_z: - - vecs = [] - brch_twig_len = float(len(brch_twig.bpoints)) - - if twig_follow_parent: - no = parent_pt.no.copy() * twig_follow_parent - else: - no = Vector() - - no.x += twig_follow_x - no.y += twig_follow_y - no.z += twig_follow_z - - for i, pt in enumerate(brch_twig.bpoints): - if pt.prev: - fac = i / brch_twig_len - - # Scale this value - fac_inv = 1-fac - - no_orig = pt.co - pt.prev.co - len_orig = no_orig.length - - no_new = (fac_inv * no_orig) + (fac * no) - no_new.length = len_orig - - # Mix the 2 normals - vecs.append(no_new) - - # Apply the coords - for i, pt in enumerate(brch_twig.bpoints): - if pt.prev: - pt.co = pt.prev.co + vecs[i-1] - - brch_twig.calcPointExtras() - - - # When using a bounding mesh, clip and calculate points in bounds. - #print "Attempting to trim base" - brch_twig.baseTrim(connect_base_trim) - - if twig_ob_bounds and (twig_ob_bounds_prune or twig_recursive): - brch_twig.calcTwigBounds(self) - - # we would not have been but here if the bounds were outside - if twig_ob_bounds_prune: - brch_twig.boundsTrim() - if twig_ob_bounds_prune_taper != 1.0: - # taper to a point. we could use some nice taper algo here - just linear atm. - - brch_twig.taper(twig_ob_bounds_prune_taper) - - # Make sure this dosnt mess up anything else - - brch_twig_index += 1 - - # Add to the branches - #self.branches_all.append(brch_twig) - if len(brch_twig.bpoints) > 2: - branches_twig_attached.append(brch_twig) - brch_twig.generation = brch_parent.generation + 1 - brch_parent.twig_count += 1 - else: - # Dont add the branch - parent_pt.childCount -= 1 - - # Watch This! - move 1 tab down for no recursive twigs - if twig_recursive: - self.branches_all.extend(branches_twig_attached) - branches_twig_attached = [] - - if not twig_recursive: - self.branches_all.extend(branches_twig_attached) - branches_twig_attached = [] - - - if do_twigs_fill and twig_ob_bounds: - self.twigFill(\ - twig_fill_levels,\ - twig_fill_rand_scale,\ - twig_fill_fork_angle_max,\ - twig_fill_radius_min,\ - twig_fill_radius_factor,\ - twig_fill_shape_type,\ - twig_fill_shape_rand,\ - twig_fill_shape_power,\ - ) - - ### self.branches_all.sort( key = lambda brch: brch.parent_pt != None ) - - # Calc points with dependancies - # detect circular loops!!! - TODO - #### self.resetTags(False) # NOT NEEDED NOW - done_nothing = False - while done_nothing == False: - done_nothing = True - - for brch in self.branches_all: - - if brch.tag == False and (brch.parent_pt == None or brch.parent_pt.branch.tag == True): - # Assign this to a spesific side of the parents point - # we know this is a child but not which side it should be attached to. - if brch.parent_pt: - - child_locs = [\ - brch.parent_pt.childPointUnused(0),\ - brch.parent_pt.childPointUnused(1),\ - brch.parent_pt.childPointUnused(2),\ - brch.parent_pt.childPointUnused(3)] - - best_idx = closestVecIndex(brch.bpoints[0].co, child_locs) - - # best_idx could be -1 if all childPoint's are used however we check for this and dont allow it to happen. - #if best_idx==-1: - # raise "Error"z - brch.parent_pt.children[best_idx] = brch - - for pt in brch.bpoints: - pt.calcVerts() - - done_nothing = False - brch.tag = True - - ''' - for i in xrange(len(self.branches_all)): - brch_i = self.branches_all[i] - print brch_i.myindex, - print 'tag', brch_i.tag, - print 'parent is', - if brch_i.parent_pt: - print brch_i.parent_pt.branch.myindex - else: - print None - ''' - - def optimizeSpacing(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, joint_compression=1.0, joint_smooth=1.0): - ''' - Optimize spacing, taking branch hierarchy children into account, - can add or subdivide segments so branch joins dont look horrible. - ''' - for brch in self.branches_all: - brch.evenJointDistrobution(joint_compression) - - # Correct points that were messed up from sliding - # This happens when one point is pushed past another and the branch gets an overlaping line - - for brch in self.branches_all: - brch.fixOverlapError(joint_smooth) - - - # Collapsing - for brch in self.branches_all: - brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth) - - ''' - for brch in self.branches_all: - brch.branchReJoin() - ''' - - def twigFill(self_tree,\ - twig_fill_levels,\ - twig_fill_rand_scale,\ - twig_fill_fork_angle_max,\ - twig_fill_radius_min,\ - twig_fill_radius_factor,\ - twig_fill_shape_type,\ - twig_fill_shape_rand,\ - twig_fill_shape_power,\ - ): - ''' - Fill with twigs, this function uses its own class 'segment' - - twig_fill_shape_type; - 0 - no child smoothing - 1 - smooth one child - 2 - smooth both children - - ''' - - rnd = [1] - - segments_all = [] - segments_level = [] - - # Only for testing - def preview_curve(): - TWIG_WIDTH_MAX = 1.0 - TWIG_WIDTH_MIN = 0.1 - cu = bpy.data.curves["cu"] - # remove all curves - while len(cu): - del cu[0] - # return - - cu.setFlag(1) - cu.ext2 = 0.01 - - WIDTH_STEP = (TWIG_WIDTH_MAX-TWIG_WIDTH_MIN) / twig_fill_levels - - for i, seg in enumerate(segments_all): - - # 1 is the base and 2 is the tail - - p1_h2 = seg.getHeadHandle() # isnt used - p1_co = seg.headCo - p1_h1 = seg.getHeadHandle() - - p2_h1 = seg.getTailHandle() - - p2_co = seg.tailCo - p2_h2 = seg.tailCo # isnt used - - bez1 = Blender.BezTriple.New([ p1_h1[0], p1_h1[1], p1_h1[2], p1_co[0], p1_co[1], p1_co[2], p1_h2[0], p1_h2[1], p1_h2[2] ]) - bez2 = Blender.BezTriple.New([ p2_h1[0], p2_h1[1], p2_h1[2], p2_co[0], p2_co[1], p2_co[2], p2_h2[0], p2_h2[1], p2_h2[2] ]) - bez1.handleTypes = bez2.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE] - - bez1.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * (seg.levelFromLeaf+1)) - bez2.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * seg.levelFromLeaf) - - cunurb = cu.appendNurb(bez1) - cunurb.append(bez2) - - # This sucks - for bez in cunurb: - bez.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE] - - ### cc = sce.objects.new( cu ) - cu.update() - - - def mergeCo(parentCo, ch1Co, ch2Co, twig_fill_shape_rand): - if twig_fill_shape_rand==0.0: - return (parentCo + ch1Co + ch2Co) / 3.0 - else: - - w1 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand) - w2 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand) - w3 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand) - wtot = w1+w2+w3 - w1=w1/wtot - w2=w2/wtot - w3=w3/wtot - - # return (parentCo*w1 + ch1Co*w2 + ch2Co*w2) - co1 = (parentCo * w1) + (ch1Co * (1.0-w1)) - co2 = (ch1Co * w2) + (ch2Co * (1.0-w2)) - co3 = (ch2Co * w3) + (parentCo * (1.0-w3)) - - return (co1 + co2 + co3) / 3.0 - - - - class segment: - def __init__(self, level): - self.headCo = Vector() - self.tailCo = Vector() - self.parent = None - self.mergeCount = 0 - self.levelFromLeaf = level # how far we are from the leaf in levels - self.levelFromRoot = -1 # set later, assume root bone - self.children = [] - segments_all.append(self) - - if level >= len(segments_level): segments_level.append([self]) - else: segments_level[level].append(self) - - self.brothers = [] - self.no = Vector() # only endpoints have these - # self.id = len(segments_all) - - # First value is the bpoint, - # Second value is what to do - - # 0 - dont join - # 1 - Join to parent (tree point) - # 2 - join to parent, point from another fill-twig branch we just created. - - self.bpt = (None, False) # branch point for root segs only - self.new_bpt = None - - self.used = False # use this to tell if we are apart of a branch - - def sibling(self): - i = self.parent.children.index(self) - - if i == 0: - return self.parent.children[ 1 ] - elif i == 1: - return self.parent.children[ 0 ] - else: - raise "error" - - - def getHeadHandle(self): - """ - For Bezier only - """ - - if not self.parent: - return self.headCo - - if twig_fill_shape_type == 0: # no smoothing - return self.headCo - elif twig_fill_shape_type == 1: - if self.parent.children[1] == self: - return self.headCo - # 2 - always do both - - - # Y shape with curve? optional - - # we have a parent but it has no handle direction, easier - if not self.parent.parent: no = self.parent.headCo - self.parent.tailCo - else: no = self.parent.parent.headCo-self.parent.tailCo - - no.length = self.getLength() * twig_fill_shape_power - # Ok we have to account for the parents handle - return self.headCo - no - # return self.headCo - Vector(1, 0,0) - - def getTailHandle(self): - """ - For Bezier only - """ - if self.parent: - no = self.parent.headCo-self.tailCo - no.length = self.getLength() * twig_fill_shape_power - return self.tailCo + no - else: - return self.tailCo # isnt used - - def getRootSeg(self): - seg = self - while seg.parent: - seg = seg.parent - - return seg - - def calcBrothers(self): - # Run on children first - self.brothers.extend( \ - [seg_child_sibling.parent \ - for seg_child in self.children \ - for seg_child_sibling in seg_child.brothers \ - if seg_child_sibling.parent not in (self, None)]\ - ) - #print self.brothers - - def calcLevelFromRoot(self): - if self.parent: - self.levelFromRoot = self.parent.levelFromRoot + 1 - - for seg_child in self.children: - seg_child.calcLevelFromRoot() - - # Dont use for now, but scale worked, transform was never tested. - """ - def transform(self, matrix): - self.headCo = self.headCo * matrix - self.tailCo = self.tailCo * matrix - - if self.children: - ch1 = self.children[0] - ch2 = self.children[1] - - ch1.transform(matrix) - ch2.transform(matrix) - - def scale(self, scale, cent=None): - # scale = 0.9 - #matrix = Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4() - #self.transform(matrix) - if cent == None: # first iter - cent = self.headCo - self.tailCo = ((self.tailCo-cent) * scale) + cent - else: - self.headCo = ((self.headCo-cent) * scale) + cent - self.tailCo = ((self.tailCo-cent) * scale) + cent - - if self.children: - self.children[0].scale(scale, cent) - self.children[1].scale(scale, cent) - """ - def recalcChildLoc(self): - if not self.children: - return - ch1 = self.children[0] - ch2 = self.children[1] - new_mid = mergeCo(self.headCo, ch1.tailCo, ch2.tailCo, twig_fill_shape_rand) - - self.tailCo[:] = ch1.headCo[:] = ch2.headCo[:] = new_mid - - ch1.recalcChildLoc() - ch2.recalcChildLoc() - - def merge(self, other): - """ - Merge other into self and make a new segment - """ - """ - seg_child = segment(self.levelFromLeaf) - self.levelFromLeaf += 1 - - seg_child.parent = other.parent = self - - # No need, recalcChildLoc sets the other coords - #self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0 - #self.parent.headCo[:] = self.headCo - - seg_child.headCo[:] = self.headCo - - # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo) - # new_head = (isect[0]+isect[1]) * 0.5 - - seg_child.mergeCount += 1 - other.mergeCount += 1 - - self.children.extend([ seg_child, other ]) - - self.recalcChildLoc() - - # print 'merging', self.id, other.id - """ - - #new_head = (self.headCo + self.tailCo + other.headCo + other.tailCo) * 0.25 - - self.parent = other.parent = segment(self.levelFromLeaf + 1) - - # No need, recalcChildLoc sets the self.parent.tailCo - # self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0 - - self.parent.headCo[:] = self.headCo - self.parent.bpt = self.bpt - self.bpt = (None, False) - - # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo) - # new_head = (isect[0]+isect[1]) * 0.5 - - self.mergeCount += 1 - other.mergeCount += 1 - - self.parent.children.extend([ self, other ]) - - self.parent.recalcChildLoc() - # print 'merging', self.id, other.id - - - def findBestMerge(self, twig_fill_fork_angle_max): - # print "findBestMerge" - if self.parent != None: - return - - best_dist = 1000000 - best_seg = None - for seg_list in (self.brothers, segments_level[self.levelFromLeaf]): - #for seg_list in (segments_level[self.levelFromLeaf],): - - # only use all other segments if we cant find any from our brothers - if seg_list == segments_level[self.levelFromLeaf] and best_seg != None: - break - - for seg in seg_list: - # 2 ppoint join - if seg != self and seg.mergeCount == 0 and seg.parent == None: - - # find the point they would join - test_dist = (self.tailCo - seg.tailCo).length - if test_dist < best_dist: - if twig_fill_fork_angle_max > 179: - best_dist = test_dist - best_seg = seg - else: - # Work out if the desired angle range is ok. - mco = mergeCo( self.headCo, self.tailCo, seg.tailCo, 0.0 ) # we dont want the random value for this test - ang = AngleBetweenVecsSafe(self.tailCo-mco, seg.tailCo-mco) - if ang < twig_fill_fork_angle_max: - best_dist = test_dist - best_seg = seg - return best_seg - - def getNormal(self): - return (self.headCo - self.tailCo).normalize() - - def getLength(self): - return (self.headCo - self.tailCo).length - """ - def toMatrix(self, LEAF_SCALE, LEAF_RANDSCALE, LEAF_RANDVEC): - if LEAF_RANDSCALE: scale = LEAF_SCALE * Rand(1.0-LEAF_RANDSCALE, 1.0+LEAF_RANDSCALE) - else: scale = LEAF_SCALE * 1.0 - - if LEAF_RANDVEC: rand_vec = Vector( Rand(-1, 1), Rand(-1, 1), Rand(-1, 1) ).normalize() * LEAF_RANDVEC - else: rand_vec = Vector( ) - - return Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4() * (self.no + rand_vec).toTrackQuat('x', 'z').toMatrix().resize4x4() * TranslationMatrix(self.tailCo) - """ - def distripute_seg_on_mesh(me__, face_group): - """ - add segment endpoints - """ - - vert_segment_mapping = {} - for f in face_group: - for v in f: - i = v.index - if i not in vert_segment_mapping: - vert_segment_mapping[i] = len(segments_all) - v.sel = True - seg = segment(0) - # seg.tailCo = v.co.copy() # headCo undefined atm. - seg.tailCo = v.co.copy() * self_tree.objectTwigBoundsMat * self_tree.objectCurveIMat - - # self_tree.objectCurveMat - - seg.no = v.no - - # Build connectivity - for ed in me__.edges: - if ed.v1.sel and ed.v2.sel: - i1,i2 = ed.key - i1 = vert_segment_mapping[i1] - i2 = vert_segment_mapping[i2] - - segments_all[i1].brothers.append( segments_all[i2] ) - segments_all[i2].brothers.append( segments_all[i1] ) - - # Dont need to return anything, added when created. - - def set_seg_attach_point(seg, interior_points, twig_fill_rand_scale): - """ - Can only run on end nodes that have normals set - """ - best_dist = 1000000000.0 - best_point = None - - co = seg.tailCo - - for pt in interior_points: - # line from the point to the seg endpoint - - line_normal = seg.tailCo - pt.nextMidCo - l = line_normal.length - - - cross1 = CrossVecs( seg.no, line_normal ) - cross2 = CrossVecs( pt.no, line_normal ) - - angle_line = min(AngleBetweenVecsSafe(cross1, cross2), AngleBetweenVecsSafe(cross1, -cross2)) - angle_leaf_no_diff = min(AngleBetweenVecsSafe(line_normal, seg.no), AngleBetweenVecsSafe(line_normal, -seg.no)) - - # BEST_ANG=66.0 - # angle = 66.0 # min(AngleBetweenVecs(v2_co-v1_co, leaf.co-cc), AngleBetweenVecs(v1_co-v2_co, leaf.co-cc)) - # print angle, angle2 - # l = (l * ((1+abs(angle-BEST_ANG))**2 )) / (1+angle_line) - l = (1+(angle_leaf_no_diff/180)) * (1+(angle_line/180)) * l - - if l < best_dist: - best_pt = pt - best_co = pt.nextMidCo - - best_dist = l - - # twig_fill_rand_scale - seg.headCo = best_co.copy() - - if twig_fill_rand_scale: - seg_dir = seg.tailCo - seg.headCo - - seg_dir.length = seg_dir.length * ( 1.0 - (next_random_num(rnd)*twig_fill_rand_scale) ) - seg.tailCo = seg.headCo + seg_dir - - - if best_pt.childCount < 4: - # Watch this!!! adding a user before its attached and the branch is created! - # make sure if its not added later on, this isnt left added - best_pt.childCount += 1 - - # True/False denotes weather we try to connect to our parent branch - seg.bpt = (best_pt, True) - else: - seg.bpt = (best_pt, False) - - return True - - - # END Twig code, next add them - - - """ - Uses a reversed approch, fill in twigs from a bounding mesh - """ - # print "twig_fill_fork_angle_max" - # twig_fill_fork_angle_max = 60.0 # - # forward_diff_bezier will fill in the blanks - # nice we can reuse these for every curve segment :) - pointlist = [[None, None, None] for i in xrange(self_tree.steps+1)] - radlist = [ None for i in xrange(self_tree.steps+1) ] - - orig_branch_count = len(self_tree.branches_all) - - for face_group in BPyMesh.mesh2linkedFaces(self_tree.objectTwigBoundsMesh): - # Set the selection to do point inside. - self_tree.objectTwigBoundsMesh.sel = False - for f in face_group: f.sel = True - - interior_points = [] - interior_normal = Vector() - for i, brch in enumerate(self_tree.branches_all): - - if i == orig_branch_count: - break # no need to check new branches are inside us - - for pt in brch.bpoints: - if pt.next and pt.childCount < 4: # cannot attach to the last points - if self_tree.isPointInTwigBounds(pt.co, True): # selected_only - interior_points.append(pt) - interior_normal += pt.no * pt.radius - - segments_all[:] = [] - segments_level[:] = [] - - if interior_points: - # Ok, we can add twigs now - distripute_seg_on_mesh( self_tree.objectTwigBoundsMesh, face_group ) - - for seg in segments_level[0]: # only be zero segments - # Warning, increments the child count for bpoints we attach to!! - set_seg_attach_point(seg, interior_points, twig_fill_rand_scale) - - # Try sorting by other properties! this is ok for now - for segments_level_current in segments_level: - segments_level_current.sort( key = lambda seg: -(seg.headCo-seg.tailCo).length ) - - for level in xrange(twig_fill_levels): - if len(segments_level) > level: - for seg in segments_level[level]: - # print level, seg.brothers - if seg.mergeCount == 0: - seg_merge = seg.findBestMerge(twig_fill_fork_angle_max) - if seg_merge: - seg.merge( seg_merge ) - - if len(segments_level) > level+1: - for seg in segments_level[level+1]: - seg.calcBrothers() - - for seg in segments_all: - if seg.parent == None: - seg.levelFromRoot = 0 - seg.calcLevelFromRoot() - - ''' - for i, seg in enumerate(segments_all): - # Make a branch from this data! - - brch = branch() - brch.type = BRANCH_TYPE_FILL - self_tree.branches_all.append(brch) - - # ============================= do this per bez pair - # 1 is the base and 2 is the tail - - #p1_h1 = seg.getHeadHandle() - p1_co = seg.headCo.copy() - p1_h2 = seg.getHeadHandle() # isnt used - - p2_h1 = seg.getTailHandle() - p2_co = seg.tailCo.copy() - #p2_h2 = seg.getTailHandle() # isnt used - - - bez1_vec = (None, p1_co, p1_h2) - bez2_vec = (p2_h1, p2_co, None) - - seg_root = seg.getRootSeg() - - radius_root = seg_root.bpt.radius * twig_fill_radius_factor - # Clamp so the head is never smaller then the tail - if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min - - if seg_root.levelFromLeaf: - # print seg_root.levelFromLeaf, seg.levelFromRoot - WIDTH_STEP = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1) - - radius1 = twig_fill_radius_min + (WIDTH_STEP * (seg.levelFromLeaf+1)) - if seg.levelFromLeaf: radius2 = twig_fill_radius_min + (WIDTH_STEP * seg.levelFromLeaf) - else: radius2 = twig_fill_radius_min - else: - radius1 = radius_root - radius2 = twig_fill_radius_min - - - points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2) - - # dont apply self_tree.limbScale here! - its alredy done - bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(len(pointlist)) ] - - # remove endpoint for all but the last - #if i != len(bez_list)-1: - # bpoints.pop() - - brch.bpoints.extend(bpoints) - # ============================= - - # Finalize once point data is there - brch.calcData() - # - #preview_curve() - ''' - - for segments_level_current in reversed(segments_level): - for seg in segments_level_current: - if seg.used == False and (seg.parent == None or seg.parent.used == True): - - # The root segment for this set of links. - # seg_root_linked = seg - - brch = branch() - brch.type = BRANCH_TYPE_FILL - self_tree.branches_all.append(brch) - - # Can we attach to a real branch? - if seg.parent == None: - if seg.bpt[1]: # we can do a real join into the attach point - brch.parent_pt = seg.bpt[0] - # brch.parent_pt.childCount # this has alredy changed from - - ''' - if seg.parent: - if seg.bpt[1] == 2: - #if seg.bpt[1]: - # print "Making Connection" - if seg.bpt[0] == None: - raise "Error" - if seg.bpt[1] != 2: - print seg.bpt[1] - raise "Error" - - brch.parent_pt = seg.bpt[1] - brch.parent_pt.childCount += 1 - if brch.parent_pt.childCount > 4: - raise "Aeeae" - print "\n\nM<aking Joint!!" - ''' - - if seg.parent: - sibling = seg.sibling() - if sibling.new_bpt: - if sibling.new_bpt.childCount < 4: - brch.parent_pt = sibling.new_bpt - brch.parent_pt.childCount +=1 - - # Go down the hierarhy - is_first = True - while seg != None: - seg.used = True - - # ============================================== - - #p1_h1 = seg.getHeadHandle() - p1_co = seg.headCo.copy() - p1_h2 = seg.getHeadHandle() # isnt used - - p2_h1 = seg.getTailHandle() - p2_co = seg.tailCo.copy() - #p2_h2 = seg.getTailHandle() # isnt used - - - bez1_vec = (None, p1_co, p1_h2) - bez2_vec = (p2_h1, p2_co, None) - - seg_root = seg.getRootSeg() - - radius_root = seg_root.bpt[0].radius * twig_fill_radius_factor - # Clamp so the head is never smaller then the tail - if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min - - if seg_root.levelFromLeaf: - # print seg_root.levelFromLeaf, seg.levelFromRoot - widthStep = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1) - - radius1 = twig_fill_radius_min + (widthStep * (seg.levelFromLeaf+1)) - if seg.levelFromLeaf: radius2 = twig_fill_radius_min + (widthStep * seg.levelFromLeaf) - else: radius2 = twig_fill_radius_min - else: - radius1 = radius_root - radius2 = twig_fill_radius_min - - points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2) - - - start_pointlist = 0 - - # This is like baseTrim, (remove the base points to make nice joins, accounting for radius of parent point) - # except we do it before the branch is made - - if brch.parent_pt: - while len(pointlist) - start_pointlist > 2 and (Vector(pointlist[start_pointlist]) - brch.parent_pt.co).length < (brch.parent_pt.radius*2): - start_pointlist +=1 - - if is_first and brch.parent_pt: - # We need to move the base point to a place where it looks good on the parent branch - # to do this. move the first point, then remove the following points that look horrible (double back on themself) - - no = Vector(pointlist[0]) - Vector(pointlist[-1]) - no.length = brch.parent_pt.radius*2 - pointlist[0] = list(Vector(pointlist[0]) - no) - - """ - pointlist[1][0] = (pointlist[0][0] + pointlist[2][0])/2.0 - pointlist[1][1] = (pointlist[0][1] + pointlist[2][1])/2.0 - pointlist[1][2] = (pointlist[0][2] + pointlist[2][2])/2.0 - - pointlist[2][0] = (pointlist[1][0] + pointlist[3][0])/2.0 - pointlist[2][1] = (pointlist[1][1] + pointlist[3][1])/2.0 - pointlist[2][2] = (pointlist[1][2] + pointlist[3][2])/2.0 - """ - - - # Done setting the start point - - - len_pointlist = len(pointlist) - if seg.children: - len_pointlist -= 1 - - # dont apply self_tree.limbScale here! - its alredy done - bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(start_pointlist, len_pointlist) ] - brch.bpoints.extend( bpoints ) - # ============================================== - - seg.new_bpt = bpoints[0] - - if seg.children: - seg = seg.children[0] - else: - seg = None - - is_first = False - - # done adding points - brch.calcData() - - - - - def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor): - - ratio_int = int(len(self.branches_all) * twig_ratio) - if ratio_int == 0: - return - - # So we only mix branches of similar lengths - branches_sorted = self.branches_all[:] - - # Get the branches based on our selection method! - if twig_select_mode==0: - branches_sorted.sort( key = lambda brch: brch.getLength()) - elif twig_select_mode==1: - branches_sorted.sort( key = lambda brch:-brch.getLength()) - elif twig_select_mode==2: - branches_sorted.sort( key = lambda brch:brch.getStraightness()) - elif twig_select_mode==3: - branches_sorted.sort( key = lambda brch:-brch.getStraightness()) - - factor_int = int(len(self.branches_all) * twig_select_factor) - branches_sorted[factor_int:] = [] # remove the last part of the list - - branches_sorted.sort( key = lambda brch: len(brch.bpoints)) - - branches_new = [] - #for i in xrange(ratio_int): - tot_twigs = 0 - - step = 1 - while tot_twigs < ratio_int and step < len(branches_sorted): - # Make branches from the existing - for j in xrange(step, len(branches_sorted)): - brch = branches_sorted[j-step].mixToNew(branches_sorted[j], None) - branches_new.append( brch ) - tot_twigs +=1 - - if tot_twigs > ratio_int: - break - - ### print "TwigCount", len(branches_new), ratio_int - - self.branches_twigs = branches_new - - def toDebugDisplay(self): - ''' - Should be able to call this at any time to see whats going on, dosnt work so nice ATM. - ''' - sce = bpy.data.scenes.active - - for ob in self.debug_objects: - for ob in sce.objects: - sce.objects.unlink(ob) - - for branch_index, brch in enumerate(self.branches_all): - pt_index = 0 - for pt_index, pt in enumerate(brch.bpoints): - name = '%.3d_%.3d' % (branch_index, pt_index) - if pt.next==None: - name += '_end' - if pt.prev==None: - name += '_start' - - ob = sce.objects.new('Empty', name) - self.debug_objects.append(ob) - mat = ScaleMatrix(pt.radius, 4) * TranslationMatrix(pt.co) - ob.setMatrix(mat) - ob.setDrawMode(8) # drawname - Blender.Window.RedrawAll() - - - - def toMesh(self, mesh=None,\ - do_uv=True,\ - do_uv_keep_vproportion=True,\ - do_uv_vnormalize=False,\ - do_uv_uscale=False,\ - uv_image = None,\ - uv_x_scale=1.0,\ - uv_y_scale=4.0,\ - do_uv_blend_layer= False,\ - do_cap_ends=False,\ - ): - - self.mesh = freshMesh(mesh) - totverts = 0 - - for brch in self.branches_all: - totverts += len(brch.bpoints) - - self.mesh.verts.extend( [ (0.0,0.0,0.0) ] * ((totverts * 4)+1) ) # +1 is a dummy vert - verts = self.mesh.verts - - # Assign verts to points, 4 verts for each point. - i = 1 # dummy vert, should be 0 - for brch in self.branches_all: - for pt in brch.bpoints: - pt.verts[0] = verts[i] - pt.verts[1] = verts[i+1] - pt.verts[2] = verts[i+2] - pt.verts[3] = verts[i+3] - i+=4 - - # Do this again because of collapsing - # pt.calcVerts(brch) - - # roll the tube so quads best meet up to their branches. - for brch in self.branches_all: - #for pt in brch.bpoints: - if brch.parent_pt: - - # Use temp lists for gathering an average - if brch.parent_pt.roll_angle == None: - brch.parent_pt.roll_angle = [brch.getParentQuadAngle()] - # More then 2 branches use this point, add to the list - else: - brch.parent_pt.roll_angle.append( brch.getParentQuadAngle() ) - - # average the temp lists into floats - for brch in self.branches_all: - #for pt in brch.bpoints: - if brch.parent_pt and type(brch.parent_pt.roll_angle) == list: - # print brch.parent_pt.roll_angle - f = 0.0 - for val in brch.parent_pt.roll_angle: - f += val - brch.parent_pt.roll_angle = f/len(brch.parent_pt.roll_angle) - - # set the roll of all the first segments that have parents, - # this is because their roll is set from their parent quad and we dont want them to roll away from that. - for brch in self.branches_all: - if brch.parent_pt: - # if the first joint has a child then apply half the roll - # theres no correct solition here, but this seems ok - if brch.bpoints[0].roll_angle != None: - #brch.bpoints[0].roll_angle *= 0.5 - #brch.bpoints[0].roll_angle = 0.0 - #brch.bpoints[1].roll_angle = 0.0 - brch.bpoints[0].roll_angle = 0.0 - pass - else: - # our roll was set from the branches parent and needs no changing - # set it to zero so the following functions know to interpolate. - brch.bpoints[0].roll_angle = 0.0 - #brch.bpoints[1].roll_angle = 0.0 - - ''' - Now interpolate the roll! - The method used here is a little odd. - - * first loop up the branch and set each points value to the "last defined" value and record the steps - since the last defined value - * Do the same again but backwards - - now for each undefined value we have 1 or 2 values, if its 1 its simple we just use that value - ( no interpolation ), if there are 2 then we use the offsets from each end to work out the interpolation. - - one up, one back, and another to set the values, so 3 loops all up. - ''' - #### print "scan up the branch..." - for brch in self.branches_all: - last_value = None - last_index = -1 - for i in xrange(len(brch.bpoints)): - pt = brch.bpoints[i] - if type(pt.roll_angle) in (float, int): - last_value = pt.roll_angle - last_index = i - else: - if type(last_value) in (float, int): - # Assign a list, because there may be a connecting roll value from another joint - pt.roll_angle = [(last_value, i-last_index)] - - #### print "scan down the branch..." - last_value = None - last_index = -1 - for i in xrange(len(brch.bpoints)-1, -1, -1): # same as above but reverse - pt = brch.bpoints[i] - if type(pt.roll_angle) in (float, int): - last_value = pt.roll_angle - last_index = i - else: - if last_value != None: - if type(pt.roll_angle) == list: - pt.roll_angle.append((last_value, last_index-i)) - else: - #pt.roll_angle = [(last_value, last_index-i)] - - # Dont bother assigning a list because we wont need to add to it later - pt.roll_angle = last_value - - # print "looping ,...." - ### print "assigning/interpolating roll values" - for pt in brch.bpoints: - - # print "this roll IS", pt.roll_angle - - if pt.roll_angle == None: - continue - elif type(pt.roll_angle) in (float, int): - pass - elif len(pt.roll_angle) == 1: - pt.roll_angle = pt.roll_angle[0][0] - else: - # interpolate - tot = pt.roll_angle[0][1] + pt.roll_angle[1][1] - pt.roll_angle = \ - (pt.roll_angle[0][0] * (tot - pt.roll_angle[0][1]) +\ - pt.roll_angle[1][0] * (tot - pt.roll_angle[1][1])) / tot - - #### print pt.roll_angle, 'interpolated roll' - - pt.roll(pt.roll_angle) - - # Done with temp average list. now we know the best roll for each branch. - - # mesh the data - for brch in self.branches_all: - for pt in brch.bpoints: - pt.toMesh(self.mesh) - - #faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ] - - - - faces_extend = [] - for brch in self.branches_all: - if brch.parent_pt: - faces_extend.extend(brch.faces) - for pt in brch.bpoints: - for face in pt.faces: - if face: - faces_extend.append(face) - - if do_cap_ends: - # TODO - UV map and image? - faces_extend.extend([ brch.bpoints[-1].verts for brch in self.branches_all ]) - - faces = self.mesh.faces - - faces.extend(faces_extend, smooth=True) - - if do_uv: - # Assign the faces back - face_index = 0 - for brch in self.branches_all: - if brch.parent_pt: - for i in (0,1,2,3): - face = brch.faces[i] = faces[face_index+i] - face_index +=4 - - for pt in brch.bpoints: - for i in (0,1,2,3): - if pt.faces[i]: - pt.faces[i] = faces[face_index] - face_index +=1 - - #if self.mesh.faces: - # self.mesh.faceUV = True - mesh.addUVLayer( 'base' ) - - # rename the uv layer - #mesh.renameUVLayer(mesh.getUVLayerNames()[0], 'base') - - for brch in self.branches_all: - - uv_x_scale_branch = 1.0 - if do_uv_uscale: - uv_x_scale_branch = 0.0 - for pt in brch.bpoints: - uv_x_scale_branch += pt.radius - - uv_x_scale_branch = uv_x_scale_branch / len(brch.bpoints) - # uv_x_scale_branch = brch.bpoints[0].radius - - if do_uv_vnormalize: - uv_normalize = [] - - def uvmap_faces(my_faces, y_val, y_size): - ''' - Accept a branch or pt faces - ''' - uv_ls = [None, None, None, None] - for i in (0,1,2,3): - if my_faces[i]: - if uv_image: - my_faces[i].image = uv_image - uvs = my_faces[i].uv - else: - # Use these for calculating blending values - uvs = [Vector(0,0), Vector(0,0), Vector(0,0), Vector(0,0)] - - uv_ls[i] = uvs - - x1 = i*0.25 * uv_x_scale * uv_x_scale_branch - x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch - - uvs[3].x = x1; - uvs[3].y = y_val+y_size - - uvs[0].x = x1 - uvs[0].y = y_val - - uvs[1].x = x2 - uvs[1].y = y_val - - uvs[2].x = x2 - uvs[2].y = y_val+y_size - - if do_uv_vnormalize: - uv_normalize.extend(uvs) - - return uv_ls - - # Done uvmap_faces - - y_val = 0.0 - - if brch.parent_pt: - y_size = (brch.getParentFaceCent() - brch.bpoints[0].co).length - - if do_uv_keep_vproportion: - y_size = y_size / ((brch.bpoints[0].radius + brch.parent_pt.radius)/2) * uv_y_scale - - brch.uv = uvmap_faces(brch.faces, 0.0, y_size) - - y_val += y_size - - for pt in brch.bpoints: - if pt.next: - y_size = (pt.co-pt.next.co).length - # scale the uvs by the radius, avoids stritching. - if do_uv_keep_vproportion: - y_size = y_size / pt.radius * uv_y_scale - pt.uv = uvmap_faces(pt.faces, y_val, y_size) - y_val += y_size - - - if do_uv_vnormalize and uv_normalize: - # Use yscale here so you can choose to have half the normalized value say. - vscale = (1/uv_normalize[-1].y) * uv_y_scale - for uv in uv_normalize: - uv.y *= vscale - - - # Done with UV mapping the first layer! now map the blend layers - if do_uv_blend_layer: - # Set up the blend UV layer - this is simply the blending for branch joints - mesh.addUVLayer( 'blend' ) - mesh.activeUVLayer = 'blend' - - # Set all faces to be on full blend - for f in mesh.faces: - for uv in f.uv: - uv.y = uv.x = 0.0 - - for brch in self.branches_all: - if brch.parent_pt: - for f in brch.faces: - if f: - uvs = f.uv - uvs[0].x = uvs[1].x = uvs[2].x = uvs[3].x = 0.0 - uvs[0].y = uvs[1].y = 1.0 # swap these? - same as inverting the blend - uvs[2].y = uvs[3].y = 0.0 - - # Set up the join UV layer, this overlays nice blended - mesh.addUVLayer( 'join' ) - mesh.activeUVLayer = 'join' - - # Set all faces to be on full blend - for f in mesh.faces: - for uv in f.uv: - uv.y = uv.x = 0.0 - - for brch in self.branches_all: - if brch.parent_pt: - # The UV's that this branch would cover if it was a face, - uvs_base = brch.parent_pt.uv[brch.getParentQuadIndex()] - - uvs_base_mid = Vector(0,0) - for uv in uvs_base: - uvs_base_mid += uv - - uvs_base_mid *= 0.25 - - # TODO - Factor scale and distance in here - ## uvs_base_small = [(uv+uvs_base_mid)*0.5 for uv in uvs_base] - uvs_base_small = [uvs_base_mid, uvs_base_mid, uvs_base_mid, uvs_base_mid] - - if brch.faces[0]: - f = brch.faces[0] - uvs = f.uv - uvs[0][:] = uvs_base[0] - uvs[1][:] = uvs_base[1] - - uvs[2][:] = uvs_base_small[1] - uvs[3][:] = uvs_base_small[0] - - if brch.faces[1]: - f = brch.faces[1] - uvs = f.uv - uvs[0][:] = uvs_base[1] - uvs[1][:] = uvs_base[2] - - uvs[2][:] = uvs_base_small[2] - uvs[3][:] = uvs_base_small[1] - - if brch.faces[2]: - f = brch.faces[2] - uvs = f.uv - uvs[0][:] = uvs_base[2] - uvs[1][:] = uvs_base[3] - - uvs[2][:] = uvs_base_small[3] - uvs[3][:] = uvs_base_small[2] - - if brch.faces[3]: - f = brch.faces[3] - uvs = f.uv - uvs[0][:] = uvs_base[3] - uvs[1][:] = uvs_base[0] - - uvs[2][:] = uvs_base_small[0] - uvs[3][:] = uvs_base_small[3] - - mesh.activeUVLayer = 'base' # just so people dont get worried the texture is not there - dosnt effect rendering. - else: - # no UV's - pass - - if do_cap_ends: - # de-select end points for - i = len(faces)-1 - - cap_end_face_start = len(faces) - len(self.branches_all) - - j = 0 - for i in xrange(cap_end_face_start, len(faces)): - self.branches_all[j].face_cap = faces[i] - faces[i].sel = 0 - - # default UV's are ok for now :/ - if do_uv and uv_image: - faces[i].image = uv_image - - j +=1 - - # set edge crease for capped ends. - for ed in self.mesh.edges: - if ed.v1.sel==False and ed.v2.sel==False: - ed.crease = 255 - ed.sel = True # so its all selected still - - del faces_extend - - return self.mesh - - def toLeafMesh(self, mesh_leaf,\ - leaf_branch_limit = 0.5,\ - leaf_branch_limit_rand = 0.8,\ - leaf_branch_limit_type_curve = False,\ - leaf_branch_limit_type_grow = False,\ - leaf_branch_limit_type_fill = False,\ - leaf_size = 0.5,\ - leaf_size_rand = 0.5,\ - leaf_branch_density = 0.2,\ - leaf_branch_pitch_angle = 0.0,\ - leaf_branch_pitch_rand = 0.2,\ - leaf_branch_roll_rand = 0.2,\ - leaf_branch_angle = 75.0,\ - leaf_rand_seed = 1.0,\ - leaf_object=None,\ - ): - - ''' - return a mesh with leaves seperate from the tree - - Add to the existing mesh. - ''' - - #radius = [(pt.radius for pt in self.branches_all for pt in brch.bpoints for pt in brch.bpoints] - mesh_leaf = freshMesh(mesh_leaf) - self.mesh_leaf = mesh_leaf - - # if not leaf_object: return # make the dupli anyway :/ - they can do it later or the script could complain - - if leaf_branch_limit == 1.0: - max_radius = 1000000.0 - else: - # We wont place leaves on all branches so... - # first collect stats, we want to know the average radius and total segments - totpoints = 0 - radius = 0.0 - max_radius = 0.0 - for brch in self.branches_all: - for pt in brch.bpoints: - radius += pt.radius - if pt.radius > max_radius: - max_radius = pt.radius - - #totpoints += len(brch.bpoints) - - radius_max = max_radius * leaf_branch_limit - - verts_extend = [] - faces_extend = [] - - co1 = Vector(0.0, -0.5, -0.5) - co2 = Vector(0.0, -0.5, 0.5) - co3 = Vector(0.0, 0.5, 0.5) - co4 = Vector(0.0, 0.5, -0.5) - - rnd_seed = [leaf_rand_seed] # could have seed as an input setting - - for brch in self.branches_all: - - # quick test, do we need leaves on this branch? - if leaf_branch_limit != 1.0 and brch.bpoints[-1].radius > radius_max: - continue - - - for pt in brch.bpoints: - - # For each point we can add 2 leaves - for odd_even in (0,1): - - - if (pt == brch.bpoints[-1] and odd_even==1) or \ - (leaf_branch_density != 1.0 and leaf_branch_density < next_random_num(rnd_seed)): - pass - else: - if leaf_branch_limit_rand: - # (-1 : +1) * leaf_branch_limit_rand - rnd = 1 + (((next_random_num(rnd_seed) - 0.5) * 2 ) * leaf_branch_limit_rand) - else: - rnd = 1.0 - - if pt.childCount == 0 and (leaf_branch_limit == 1.0 or (pt.radius * rnd) < radius_max): - leaf_size_tmp = leaf_size * (1.0-(next_random_num(rnd_seed)*leaf_size_rand)) - - # endpoints dont rotate - if pt.next != None: - cross1 = CrossVecs(zup, pt.no) # use this to offset the leaf later - cross2 = CrossVecs(cross1, pt.no) - if odd_even ==0: - mat_yaw = RotationMatrix(leaf_branch_angle, 3, 'r', cross2) - else: - mat_yaw = RotationMatrix(-leaf_branch_angle, 3, 'r', cross2) - - leaf_no = (pt.no * mat_yaw) - - # Correct upwards pointing from changing the yaw - #my_up = zup * mat - - # correct leaf location for branch width - cross1.length = pt.radius/2 - leaf_co = pt.co + cross1 - else: - # no correction needed, we are at the end of the branch - leaf_no = pt.no - leaf_co = pt.co - - mat = Matrix([leaf_size_tmp,0,0],[0,leaf_size_tmp,0],[0,0,leaf_size_tmp]) * leaf_no.toTrackQuat('x', 'z').toMatrix() - - # Randomize pitch and roll for the leaf - - # work out the axis to pitch and roll - cross1 = CrossVecs(zup, leaf_no) # use this to offset the leaf later - if leaf_branch_pitch_rand or leaf_branch_pitch_angle: - - angle = -leaf_branch_pitch_angle - if leaf_branch_pitch_rand: - angle += leaf_branch_pitch_rand * ((next_random_num(rnd_seed)-0.5)*360) - - mat_pitch = RotationMatrix( angle, 3, 'r', cross1) - mat = mat * mat_pitch - if leaf_branch_roll_rand: - mat_roll = RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no) - mat = mat * mat_roll - - mat = mat.resize4x4() * TranslationMatrix(leaf_co) - - i = len(verts_extend) - faces_extend.append( (i,i+1,i+2,i+3) ) - verts_extend.extend([tuple(co4*mat), tuple(co3*mat), tuple(co2*mat), tuple(co1*mat)]) - #count += 1 - - - # setup dupli's - - self.mesh_leaf.verts.extend(verts_extend) - self.mesh_leaf.faces.extend(faces_extend) - - return self.mesh_leaf - - - def toArmature(self, ob_arm, armature): - - armature.drawType = Blender.Armature.STICK - armature.makeEditable() # enter editmode - - # Assume toMesh has run - self.armature = armature - for bonename in armature.bones.keys(): - del armature.bones[bonename] - - - group_names = [] - - for i, brch in enumerate(self.branches_all): - - # get a list of parent points to make into bones. use parents and endpoints - bpoints_parent = [pt for pt in brch.bpoints if pt.childCount or pt.prev == None or pt.next == None] - bpbone_last = None - for j in xrange(len(bpoints_parent)-1): - - # bone container class - bpoints_parent[j].bpbone = bpbone = bpoint_bone() - bpbone.name = '%i_%i' % (i,j) # must be unique - group_names.append(bpbone.name) - - bpbone.editbone = Blender.Armature.Editbone() # automatically added to the armature - self.armature.bones[bpbone.name] = bpbone.editbone - - bpbone.editbone.head = bpoints_parent[j].co - bpbone.editbone.head = bpoints_parent[j].co - bpbone.editbone.tail = bpoints_parent[j+1].co - - # parent the chain. - if bpbone_last: - bpbone.editbone.parent = bpbone_last.editbone - bpbone.editbone.options = [Blender.Armature.CONNECTED] - - bpbone_last = bpbone - - for brch in self.branches_all: - if brch.parent_pt: # We must have a parent - - # find the bone in the parent chain to use for the parent of this - parent_pt = brch.parent_pt - bpbone_parent = None - while parent_pt: - bpbone_parent = parent_pt.bpbone - if bpbone_parent: - break - - parent_pt = parent_pt.prev - - - if bpbone_parent: - brch.bpoints[0].bpbone.editbone.parent = bpbone_parent.editbone - else: # in rare cases this may not work. should be verry rare but check anyway. - print 'this is really odd... look into the bug.' - - self.armature.update() # exit editmode - - # Skin the mesh - if self.mesh: - for group in group_names: - self.mesh.addVertGroup(group) - - for brch in self.branches_all: - vertList = [] - group = '' # dummy - - for pt in brch.bpoints: - if pt.bpbone: - if vertList: - self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD) - - vertList = [] - group = pt.bpbone.name - - vertList.extend( [v.index for v in pt.verts] ) - - if vertList: - self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD) - - return self.armature - - def toAction(self, ob_arm, texture, anim_speed=1.0, anim_magnitude=1.0, anim_speed_size_scale=True, anim_offset_scale=1.0): - # Assume armature - action = ob_arm.action - if not action: - action = bpy.data.actions.new() - action.fakeUser = False # so we dont get masses of bad data - ob_arm.action = action - - # Blender.Armature.NLA.ob_arm. - pose = ob_arm.getPose() - - for pose_bone in pose.bones.values(): - pose_bone.insertKey(ob_arm, 0, [Blender.Object.Pose.ROT], True) - - # Now get all the IPO's - - ipo_dict = action.getAllChannelIpos() - # print ipo_dict - - # Sicne its per frame, it increases very fast. scale it down a bit - anim_speed = anim_speed/100 - - # When we have the same trees next to eachother, they will animate the same way unless we give each its own texture or offset settings. - # We can use the object's location as a factor - this also will have the advantage? of seeing the animation move across the tree's - # allow a scale so the difference between tree textures can be adjusted. - anim_offset = self.objectCurve.matrixWorld.translationPart() * anim_offset_scale - - anim_speed_final = anim_speed - # Assign drivers to them all - for name, ipo in ipo_dict.iteritems(): - tex_str = 'b.Texture.Get("%s")' % texture.name - - if anim_speed_size_scale: - # Adjust the speed by the bone size. - # get the point from the name. a bit ugly but works fine ;) - Just dont mess the index up! - lookup = [int(val) for val in name.split('_')] - pt = self.branches_all[ lookup[0] ].bpoints[ lookup[1] ] - anim_speed_final = anim_speed / (1+pt.radius) - - cu = ipo[Blender.Ipo.PO_QUATX] - try: cu.delBezier(0) - except: pass - cu.driver = 2 # Python expression - cu.driverExpression = '%.3f*(%s.evaluate(((b.Get("curframe")*%.3f)+%.3f,%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_speed_final, anim_offset.x, anim_offset.y, anim_offset.z) - - cu = ipo[Blender.Ipo.PO_QUATY] - try: cu.delBezier(0) - except: pass - cu.driver = 2 # Python expression - cu.driverExpression = '%.3f*(%s.evaluate((%.3f,(b.Get("curframe")*%.3f)+%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_offset.x, anim_speed_final, anim_offset.y, anim_offset.z) - - cu = ipo[Blender.Ipo.PO_QUATZ] - try: cu.delBezier(0) - except: pass - cu.driver = 2 # Python expression - cu.driverExpression = '%.3f*(%s.evaluate((%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z) - -xyzup = Vector(1,1,1).normalize() -xup = Vector(1,0,0) -yup = Vector(0,1,0) -zup = Vector(0,0,1) - -class bpoint_bone: - def __init__(self): - self.name = None - self.editbone = None - self.blenbone = None - self.posebone = None - -class bpoint(object): - ''' The point in the middle of the branch, not the mesh points - ''' - __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'uv', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds' - def __init__(self, brch, co, no, radius): - self.branch = brch - self.co = co - self.no = no - self.radius = radius - self.vecs = [None, None, None, None] # 4 for now - self.verts = [None, None, None, None] - self.children = [None, None, None, None] # child branches, dont fill in faces here - self.faces = [None, None, None, None] - self.uv = None # matching faces, except - UV's are calculated even if there is no face, this is so we can calculate the blending UV's - self.next = None - self.prev = None - self.childCount = 0 - self.bpbone = None # bpoint_bone instance - - # when set, This is the angle we need to roll to best face our branches - # the roll that is set may be interpolated if we are between 2 branches that need to roll. - # Set to None means that the roll will be left default (from parent) - self.roll_angle = None - - - # The location between this and the next point, - # if we want to be tricky we can try make this not just a simple - # inbetween and use the normals to have some curvature - self.nextMidCo = None - - # Similar to above, median point of all children - self.childrenMidCo = None - - # Similar as above, but for radius - self.childrenMidRadius = None - - # Target locations are used when you want to move the point to a new location but there are - # more then 1 influence, build up a list and then apply - self.targetCos = [] - - # When we use twig bounding mesh, store if this point is in the bounding mesh. Assume true unless we set to false and do the test - self.inTwigBounds = True - - def __repr__(self): - s = '' - s += '\t\tco:', self.co - s += '\t\tno:', self.no - s += '\t\tradius:', self.radius - s += '\t\tchildren:', [(child != False) for child in self.children] - return s - - def makeLast(self): - self.next = None - self.nextMidCo = None - self.childrenMidCo = None - - def setCo(self, co): - self.co[:] = co - self.calcNextMidCo() - self.calcNormal() - - if self.prev: - self.prev.calcNextMidCo() - self.prev.calcNormal() - self.prev.calcChildrenMidData() - - if self.next: - self.prev.calcNormal() - - self.calcChildrenMidData() - - - def nextLength(self): - return (self.co-self.next.co).length - def prevLength(self): - return (self.co-self.prev.co).length - - def hasOverlapError(self): - if self.prev == None: - return False - if self.next == None: - return False - ''' - # see if this point sits on the line between its siblings. - co, fac = ClosestPointOnLine(self.co, self.prev.co, self.next.co) - - if fac >= 0.0 and fac <= 1.0: - return False # no overlap, we are good - else: - return True # error, some overlap - ''' - - - # Alternate method, maybe better - ln = self.nextLength() - lp = self.prevLength() - ls = (self.prev.co-self.next.co).length - - # Are we overlapping? the length from our next or prev is longer then the next-TO-previous? - if ln>ls or lp>ls: - return True - else: - return False - - - def applyTargetLocation(self): - if not self.targetCos: - return False - elif len(self.targetCos) == 1: - co_all = self.targetCos[0] - else: - co_all = Vector() - for co in self.targetCos: - co_all += co - co_all = co_all / len(self.targetCos) - - self.targetCos[:] = [] - - length = (self.co-co_all).length - # work out if we are moving up or down - if AngleBetweenVecsSafe(self.no, self.co - co_all) < 90: - - # Up - while length > (self.co-self.prev.co).length: - if not self.collapseUp(): - break - - else: - # Down - while length*2 > (self.co-self.next.co).length: - if not self.collapseDown(): - break - - self.setCo(co_all) - - return True - - def calcNextMidCo(self): - if not self.next: - return None - - # be tricky later. - self.nextMidCo = (self.co + self.next.co) * 0.5 - - def calcNormal(self): - if self.prev == None: - self.no = (self.next.co - self.co).normalize() - elif self.next == None: - self.no = (self.co - self.prev.co).normalize() - else: - self.no = (self.next.co - self.prev.co).normalize() - - def calcChildrenMidData(self): - ''' - Calculate childrenMidCo & childrenMidRadius - This is a bit tricky, we need to find a point between this and the next, - the medium of all children, this point will be on the line between this and the next. - ''' - if not self.next: - return None - - # factor between this and the next point - radius = factor = factor_i = 0.0 - - count = 0 - for brch in self.children: - if brch: # we dont need the co at teh moment. - co, fac = ClosestPointOnLine(brch.bpoints[0].co, self.co, self.next.co) - factor_i += fac - count += 1 - - radius += brch.bpoints[0].radius - - if not count: - return - - # interpolate points - factor_i = factor_i/count - factor = 1-factor_i - - self.childrenMidCo = (self.co * factor) + (self.next.co * factor_i) - self.childrenMidRadius = radius - - #debug_pt(self.childrenMidCo) - - def getAbsVec(self, index): - # print self.vecs, index - return self.co + self.vecs[index] - - def slide(self, factor): - ''' - Slides the segment up and down using the prev and next points - ''' - self.setCo(self.slideCo(factor)) - - def slideCo(self, factor): - if self.prev == None or self.next == None or factor==0.0: - return - - if factor < 0.0: - prev_co = self.prev.co - co = self.co - - ofs = co-prev_co - ofs.length = abs(factor) - self.co - ofs - - return self.co - ofs - else: - next_co = self.next.co - co = self.co - - ofs = co-next_co - ofs.length = abs(factor) - - return self.co - ofs - - - def collapseDown(self): - ''' - Collapse the next point into this one - ''' - - # self.next.next == None check is so we dont shorten the final length of branches. - if self.next == None or self.next.next == None or self.childCount or self.next.childCount: - return False - - self.branch.bpoints.remove(self.next) - self.next = self.next.next # skip - self.next.prev = self - - # Watch this place - must update all data thats needed. roll is not calculaetd yet. - self.calcNextMidCo() - return True - - def collapseUp(self): - ''' - Collapse the previous point into this one - ''' - - # self.next.next == None check is so we dont shorten the final length of branches. - if self.prev == None or self.prev.prev == None or self.prev.childCount or self.prev.prev.childCount: - return False - - self.branch.bpoints.remove(self.prev) - self.prev = self.prev.prev # skip - self.prev.next = self - - # Watch this place - must update all data thats needed. roll is not calculaetd yet. - self.prev.calcNextMidCo() - return True - - - def smooth(self, factor, factor_joint): - ''' - Blend this point into the other 2 points - ''' - if self.next == None or self.prev == None: - return False - - if self.childCount or self.prev.childCount: - factor = factor_joint; - - if factor==0.0: - return False; - - radius = (self.next.radius + self.prev.radius)/2.0 - no = (self.next.no + self.prev.no).normalize() - - # do a line intersect to work out the best location - ''' - cos = LineIntersect( self.next.co, self.next.co+self.next.no,\ - self.prev.co, self.prev.co+self.prev.no) - if cos == None: - co = (self.prev.co + self.next.co)/2.0 - else: - co = (cos[0]+cos[1])/2.0 - ''' - # Above can give odd results every now and then - co = (self.prev.co + self.next.co)/2.0 - - # Now apply - factor_i = 1.0-factor - self.setCo(self.co*factor_i + co*factor) - self.radius = self.radius*factor_i + radius*factor - - return True - - def childPoint(self, index): - ''' - Returns the middle point for any children between this and the next edge - ''' - if self.next == None: - raise 'Error' - - if index == 0: return (self.getAbsVec(0) + self.next.getAbsVec(1)) / 2 - if index == 1: return (self.getAbsVec(1) + self.next.getAbsVec(2)) / 2 - if index == 2: return (self.getAbsVec(2) + self.next.getAbsVec(3)) / 2 - if index == 3: return (self.getAbsVec(3) + self.next.getAbsVec(0)) / 2 - - def childPointUnused(self, index): - ''' - Same as above but return None when the point is alredy used. - ''' - if self.children[index]: - return None - return self.childPoint(index) - - - def roll(self, angle): - ''' - Roll the quad about its normal - use for aurienting the sides of a quad to meet a branch that stems from here... - ''' - # debugVec(self.co, self.co + self.no) - - mat = RotationMatrix(angle, 3, 'r', self.no) - for i in xrange(4): - self.vecs[i] = self.vecs[i] * mat - - - def toMesh(self, mesh): - self.verts[0].co = self.getAbsVec(0) - self.verts[1].co = self.getAbsVec(1) - self.verts[2].co = self.getAbsVec(2) - self.verts[3].co = self.getAbsVec(3) - - if not self.next: - return - - if self.prev == None and self.branch.parent_pt: - # join from parent branch - - # which side are we of the parents quad - index = self.branch.parent_pt.children.index(self.branch) - - # collect the points we are to merge into between the parent its next point - if index==0: verts = [self.branch.parent_pt.verts[0], self.branch.parent_pt.verts[1], self.branch.parent_pt.next.verts[1], self.branch.parent_pt.next.verts[0]] - if index==1: verts = [self.branch.parent_pt.verts[1], self.branch.parent_pt.verts[2], self.branch.parent_pt.next.verts[2], self.branch.parent_pt.next.verts[1]] - if index==2: verts = [self.branch.parent_pt.verts[2], self.branch.parent_pt.verts[3], self.branch.parent_pt.next.verts[3], self.branch.parent_pt.next.verts[2]] - if index==3: verts = [self.branch.parent_pt.verts[3], self.branch.parent_pt.verts[0], self.branch.parent_pt.next.verts[0], self.branch.parent_pt.next.verts[3]] - - - # Watchout for overlapping faces! - self.branch.faces[:] =\ - [verts[0], verts[1], self.verts[1], self.verts[0]],\ - [verts[1], verts[2], self.verts[2], self.verts[1]],\ - [verts[2], verts[3], self.verts[3], self.verts[2]],\ - [verts[3], verts[0], self.verts[0], self.verts[3]] - - # normal join, parents or no parents - if not self.children[0]: self.faces[0] = [self.verts[0], self.verts[1], self.next.verts[1], self.next.verts[0]] - if not self.children[1]: self.faces[1] = [self.verts[1], self.verts[2], self.next.verts[2], self.next.verts[1]] - if not self.children[2]: self.faces[2] = [self.verts[2], self.verts[3], self.next.verts[3], self.next.verts[2]] - if not self.children[3]: self.faces[3] = [self.verts[3], self.verts[0], self.next.verts[0], self.next.verts[3]] - - def calcVerts(self): - if self.prev == None: - if self.branch.parent_pt: - cross = CrossVecs(self.no, self.branch.parent_pt.no) * RotationMatrix(-45, 3, 'r', self.no) - else: - # parentless branch - for best results get a cross thats not the same as the normal, in rare cases this happens. - - # Was just doing - # cross = zup - # which works most of the time, but no verticle lines - - if AngleBetweenVecsSafe(self.no, zup) > 1.0: cross = zup - elif AngleBetweenVecsSafe(self.no, yup) > 1.0: cross = yup - else: cross = xup - - else: - cross = CrossVecs(self.prev.vecs[0], self.no) - - self.vecs[0] = Blender.Mathutils.CrossVecs(self.no, cross) - self.vecs[0].length = abs(self.radius) - mat = RotationMatrix(90, 3, 'r', self.no) - self.vecs[1] = self.vecs[0] * mat - self.vecs[2] = self.vecs[1] * mat - self.vecs[3] = self.vecs[2] * mat - - def hasChildren(self): - ''' - Use .childCount where possible, this does the real check - ''' - if self.children.count(None) == 4: - return False - else: - return True - -class branch: - def __init__(self): - self.bpoints = [] - self.parent_pt = None - self.tag = False # have we calculated our points - self.face_cap = None - self.length = -1 - # self.totchildren = 0 - # Bones per branch - self.faces = [None, None, None, None] - self.uv = None # face uvs can be fake, always 4 - self.bones = [] - self.generation = 0 # use to limit twig reproduction - self.twig_count = 0 # count the number of twigs - so as to limit how many twigs a branch gets - # self.myindex = -1 - ### self.segment_spacing_scale = 1.0 # use this to scale up the spacing - so small twigs dont get WAY too many polys - self.type = None - - def __repr__(self): - s = '' - s += '\tbranch' - s += '\tbpoints:', len(self.bpoints) - for pt in brch.bpoints: - s += str(self.pt) - - def getNormal(self): - return (self.bpoints[-1].co - self.bpoints[0].co).normalize() - - def getParentAngle(self): - if self.parent_pt: - return AngleBetweenVecsSafe(self.parent_pt.no, self.bpoints[0].no ) - else: - return 45.0 - - def getParentRadiusRatio(self): - if self.parent_pt: - return self.bpoints[0].radius / self.parent_pt.radius - else: - return 0.8 - - def getLength(self): - return (self.bpoints[0].co - self.bpoints[-1].co).length - - def getStraightness(self): - straight = 0.0 - pt = self.bpoints[0] - while pt.next: - straight += AngleBetweenVecsSafe(pt.no, pt.next.no) - pt = pt.next - return straight - - - ''' - def calcTotChildren(self): - for pt in self.bpoints: - self.totchildren += pt.childCount - ''' - def calcData(self): - ''' - Finalize once point data is there - ''' - self.calcPointLinkedList() - self.calcPointExtras() - - def calcPointLinkedList(self): - for i in xrange(1, len(self.bpoints)-1): - self.bpoints[i].next = self.bpoints[i+1] - self.bpoints[i].prev = self.bpoints[i-1] - - self.bpoints[0].next = self.bpoints[1] - self.bpoints[-1].prev = self.bpoints[-2] - - def calcPointExtras(self): - ''' - Run on a new branch or after transforming an existing one. - ''' - for pt in self.bpoints: - pt.calcNormal() - pt.calcNextMidCo() - - def calcTwigBounds(self, tree): - ''' - Check if out points are - ''' - for pt in self.bpoints: - pt.inTwigBounds = tree.isPointInTwigBounds(pt.co) - #if pt.inTwigBounds: - # debug_pt(pt.co) - - def baseTrim(self, connect_base_trim): - # if 1) dont remove the whole branch, maybe an option but later - # if 2) we are alredy a parent, cant remove me now.... darn :/ not nice... - # could do this properly but it would be slower and its a corner case. - # - # if 3) this point is within the branch, remove it. - # Scale this value by the difference in radius, a low trim looks better when the parent is a lot bigger.. - # - - while len(self.bpoints)>2 and\ - self.bpoints[0].childCount == 0 and\ - (self.parent_pt.nextMidCo - self.bpoints[0].co).length < ((self.parent_pt.radius + self.parent_pt.next.radius)/4) + (self.bpoints[0].radius * connect_base_trim): - # Note /4 - is a bit odd, since /2 is correct, but /4 lets us have more tight joints by default - - - del self.bpoints[0] - self.bpoints[0].prev = None - - def boundsTrim(self): - ''' - depends on calcTwigBounds running first. - also assumes no children assigned yet! make sure this is always the case. - ''' - trim = False - for i, pt in enumerate(self.bpoints): - if not pt.inTwigBounds: - trim = True - break - - # We must have at least 2 points to be a valid branch. this will be a stump :/ - if not trim or i < 3: - self.bpoints = [] # - return - - # Shorten the point list - self.bpoints = self.bpoints[:i] - self.bpoints[-1].makeLast() - - def taper(self, twig_ob_bounds_prune_taper = 0.0): - l = float(len( self.bpoints )) - for i, pt in enumerate(self.bpoints): - pt.radius *= (((l-i)/l) + (twig_ob_bounds_prune_taper*(i/l)) ) - - def getParentBranch(self): - if not self.parent_pt: - return None - return self.parent_pt.branch - - def getParentQuadAngle(self): - ''' - The angle off we are from our parent quad, - ''' - # used to roll the parent so its faces us better - - # Warning this can be zero sometimes, see the try below for the error - parent_normal = self.getParentFaceCent() - self.parent_pt.nextMidCo - - - self_normal = self.bpoints[1].co - self.parent_pt.co - # We only want the angle in relation to the parent points normal - # modify self_normal to make this so - cross = CrossVecs(self_normal, self.parent_pt.no) - self_normal = CrossVecs(self.parent_pt.no, cross) # CHECK - - #try: angle = AngleBetweenVecs(parent_normal, self_normal) - #except: return 0.0 - angle = AngleBetweenVecsSafe(parent_normal, self_normal) - - - # see if we need to rotate positive or negative - # USE DOT PRODUCT! - cross = CrossVecs(parent_normal, self_normal) - if AngleBetweenVecsSafe(cross, self.parent_pt.no) > 90: - angle = -angle - - return angle - - def getParentQuadIndex(self): - return self.parent_pt.children.index(self) - def getParentFaceCent(self): - return self.parent_pt.childPoint( self.getParentQuadIndex() ) - - def findClosest(self, co): - ''' - Find the closest point that can bare a child - ''' - - - ''' # this dosnt work, but could. - best = None - best_dist = 100000000 - for pt in self.bpoints: - if pt.next: - co_on_line, fac = ClosestPointOnLine(co, pt.co, pt.next.co) - print fac - if fac >= 0.0 and fac <= 1.0: - - return pt, (co-co_on_line).length - - return best, best_dist - ''' - best = None - best_dist = 100000000 - for pt in self.bpoints: - if pt.nextMidCo and pt.childCount < 4: - dist = (pt.nextMidCo-co).length - if dist < best_dist: - best = pt - best_dist = dist - - return best, best_dist - - def inParentChain(self, brch): - ''' - See if this branch is a parent of self or in the chain - ''' - - self_parent_lookup = self.getParentBranch() - while self_parent_lookup: - if self_parent_lookup == brch: - return True - self_parent_lookup = self_parent_lookup.getParentBranch() - - return False - - def transform(self, mat, loc=None, scale=None): - if scale==None: - scale = (xyzup * mat).length - - for pt in self.bpoints: - if loc: - pt.co = (pt.co * mat) + loc - else: - pt.co = pt.co * mat - pt.radius *= scale - - for pt in self.bpoints: - self.calcPointExtras() - - def translate(self, co): - ''' - Simply move the twig on the branch - ''' - ofs = self.bpoints[0].co-co - for pt in self.bpoints: - pt.co -= ofs - - def transformRecursive(self, tree, mat3x3, cent, scale=None): - - if scale==None: - # incase this is a translation matrix - scale = ((xyzup * mat3x3) - (Vector(0,0,0) * mat3x3)).length - - for pt in self.bpoints: pt.co = ((pt.co-cent) * mat3x3) + cent - #for pt in self.bpoints: pt.co = (pt.co * mat3x3) - for pt in self.bpoints: self.calcPointExtras() - - - for brch in tree.branches_all: - if brch.parent_pt: - if brch.parent_pt.branch == self: - - brch.transformRecursive(tree, mat3x3, cent, scale) - - ''' - for pt in self.bpoints: - for brch in pt.children: - if brch: - brch.transformRecursive(mat3x3, cent, scale) - ''' - def bestTwigSegment(self): - ''' - Return the most free part on the branch to place a new twig - return (sort_value, best_index, self) - ''' - - # loop up and down the branch - counding how far from the last parent segment we are - spacing1 = [0] * (len(self.bpoints)-1) - spacing2 = spacing1[:] - - step_from_parent = 0 - for i in xrange(len(spacing1)): # -1 because the last pt cant have kits - - if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False: - step_from_parent = 0 - else: - step_from_parent += 1 - - spacing1[i] += step_from_parent # -1 because the last pt cant have kits - - best_index = -1 - best_val = -1 - step_from_parent = 0 - for i in xrange(len(spacing1)-1, -1, -1): - - if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False: - step_from_parent = 0 - else: - step_from_parent += 1 - - spacing2[i] += step_from_parent - - # inTwigBounds is true by default, when twigBounds are used it can be false - if self.bpoints[i].childCount < 4 and self.bpoints[i].inTwigBounds: - # Dont allow to assign more verts then 4 - val = spacing1[i] * spacing2[i] - if val > best_val: - best_val = val - best_index = i - - #if best_index == -1: - # raise "Error" - - # This value is only used for sorting, so the lower the value - the sooner it gets a twig. - #sort_val = -best_val + (1/self.getLength()) - sort_val=self.getLength() - - return sort_val, best_index, self - - def evenPointDistrobution(self, factor=1.0, factor_joint=1.0): - ''' - Redistribute points that are not evenly distributed - factor is between 0.0 and 1.0 - ''' - - for pt in self.bpoints: - if pt.next and pt.prev and pt.childCount == 0 and pt.prev.childCount == 0: - w1 = pt.nextLength() - w2 = pt.prevLength() - wtot = w1+w2 - if wtot > 0.0: - w1=w1/wtot - #w2=w2/wtot - w1 = abs(w1-0.5)*2 # make this from 0.0 to 1.0, where 0 is the middle and 1.0 is as far out of the middle as possible. - # print "%.6f" % w1 - pt.smooth(w1*factor, w1*factor_joint) - - def fixOverlapError(self, joint_smooth=1.0): - # Keep fixing until no hasOverlapError left to fix. - - error = True - while error: - error = False - for pt in self.bpoints: - if pt.prev and pt.next: - if pt.hasOverlapError(): - if pt.smooth(1.0, joint_smooth): # if we cant fix then dont bother trying again. - error = True - - def evenJointDistrobution(self, joint_compression = 1.0): - # See if we need to evaluate this branch at all - if len(self.bpoints) <= 2: # Rare but in this case we cant do anything - return - has_children = False - for pt in self.bpoints: - if pt.childCount: - has_children = True - break - - if not has_children: - return - - # OK, we have children, so we have some work to do... - # center each segment - - # work out the median location of all points children. - for pt in self.bpoints: - pt.calcChildrenMidData() - pt.targetCos[:] = [] - - for pt in self.bpoints: - - if pt.childrenMidCo: - # Move this and the next segment to be around the child point. - # TODO - factor in the branch angle, be careful with this - close angles can have extreme values. - slide_dist = (pt.childrenMidCo - pt.co).length - (pt.childrenMidRadius * joint_compression) - co = pt.slideCo( slide_dist ) - if co: - pt.targetCos.append( co ) - - slide_dist = (pt.childrenMidRadius * joint_compression) - (pt.childrenMidCo - pt.next.co).length - co = pt.next.slideCo( slide_dist ) - if co: - pt.next.targetCos.append( co ) - - for pt in reversed(self.bpoints): - pt.applyTargetLocation() - - def collapsePoints(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, smooth_joint=1.0): - - collapse = True - while collapse: - collapse = False - pt = self.bpoints[0] - while pt: - # Collapse angles greater then 90. they are useually artifacts - - if pt.prev and pt.next and pt.prev.childCount == 0: - if (pt.radius + pt.prev.radius) != 0.0 and abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < seg_density_radius: - ang = AngleBetweenVecsSafe(pt.no, pt.prev.no) - if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle: - ## if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * seg_density: - if (pt.prev.nextMidCo-pt.co).length < seg_density or ang > 90: - pt_save = pt.prev - if pt.next.collapseUp(): # collapse this point - collapse = True - pt = pt_save # so we never reference a removed point - - if pt.childCount == 0 and pt.next: #if pt.childrenMidCo == None: - if (pt.radius + pt.next.radius) != 0.0 and abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < seg_density_radius: - ang = AngleBetweenVecsSafe(pt.no, pt.next.no) - if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle: - # do here because we only want to run this on points with no children, - # Are we closer theto eachother then the radius? - ## if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * seg_density: - if (pt.nextMidCo-pt.co).length < seg_density or ang > 90: - if pt.collapseDown(): - collapse = True - - pt = pt.next - ## self.checkPointList() - self.evenPointDistrobution(1.0, smooth_joint) - - for pt in self.bpoints: - pt.calcNormal() - pt.calcNextMidCo() - - # This is a bit dodgy - moving the branches around after placing can cause problems - """ - def branchReJoin(self): - ''' - Not needed but nice to run after collapsing incase segments moved a lot - ''' - if not self.parent_pt: - return # nothing to do - - # see if the next segment is closer now (after collapsing) - parent_pt = self.parent_pt - root_pt = self.bpoints[0] - - #try: - index = parent_pt.children.index(self) - #except: - #print "This is bad!, but not being able to re-join isnt that big a deal" - - current_dist = (parent_pt.nextMidCo - root_pt.co).length - - # TODO - Check size of new area is ok to move into - - if parent_pt.next and parent_pt.next.next and parent_pt.next.children[index] == None: - # We can go here if we want, see if its better - if current_dist > (parent_pt.next.nextMidCo - root_pt.co).length: - self.parent_pt.children[index] = None - self.parent_pt.childCount -= 1 - - self.parent_pt = parent_pt.next - self.parent_pt.children[index] = self - self.parent_pt.childCount += 1 - return - - if parent_pt.prev and parent_pt.prev.children[index] == None: - # We can go here if we want, see if its better - if current_dist > (parent_pt.prev.nextMidCo - root_pt.co).length: - self.parent_pt.children[index] = None - self.parent_pt.childCount -= 1 - - self.parent_pt = parent_pt.prev - self.parent_pt.children[index] = self - self.parent_pt.childCount += 1 - return - """ - - def checkPointList(self): - ''' - Error checking. use to check if collapsing worked. - ''' - p_link = self.bpoints[0] - i = 0 - while p_link: - if self.bpoints[i] != p_link: - raise "Error" - - if p_link.prev and p_link.prev != self.bpoints[i-1]: - raise "Error Prev" - - if p_link.next and p_link.next != self.bpoints[i+1]: - raise "Error Next" - - p_link = p_link.next - i+=1 - - def mixToNew(self, other, BLEND_MODE): - ''' - Generate a new branch based on 2 existing ones - These branches will point 'zup' - aurient 'xup' and have a tip length of 1.0 - ''' - - # Lets be lazy! - if the branches are different sizes- use the shortest. - # brch1 is always smaller - - brch1 = self - brch2 = other - if len(brch1.bpoints) > len(brch2.bpoints): - brch1, brch2 = brch2, brch1 - - if len(brch1.bpoints) == 1: - return None - - co_start = brch1.bpoints[0].co - cos1 = [ pt.co - co_start for pt in brch1.bpoints ] - - co_start = brch2.bpoints[0].co - if len(brch1.bpoints) == len(brch2.bpoints): - cos2 = [ pt.co - co_start for pt in brch2.bpoints ] - else: # truncate the points - cos2 = [ brch2.bpoints[i].co - co_start for i in xrange(len(brch1.bpoints)) ] - - scales = [] - for cos_ls in (cos1, cos2): - cross = CrossVecs(cos_ls[-1], zup) - mat = RotationMatrix(AngleBetweenVecsSafe(cos_ls[-1], zup), 3, 'r', cross) - cos_ls[:] = [co*mat for co in cos_ls] - - # point z-up - - # Now they are both pointing the same way aurient the curves to be rotated the same way - xy_nor = Vector(0,0,0) - for co in cos_ls: - xy_nor.x += co.x - xy_nor.y += co.y - cross = CrossVecs(xy_nor, xup) - - # Also scale them here so they are 1.0 tall always - scale = 1.0/(cos_ls[0]-cos_ls[-1]).length - mat = RotationMatrix(AngleBetweenVecsSafe(xy_nor, xup), 3, 'r', cross) * Matrix([scale,0,0],[0,scale,0],[0,0,scale]) - cos_ls[:] = [co*mat for co in cos_ls] - - scales.append(scale) - - # Make the new branch - new_brch = branch() - new_brch.type = BRANCH_TYPE_GROWN - for i in xrange(len(cos1)): - new_brch.bpoints.append( bpoint(new_brch, (cos1[i]+cos2[i])*0.5, Vector(), (brch1.bpoints[i].radius*scales[0] + brch2.bpoints[i].radius*scales[1])/2) ) - - new_brch.calcData() - return new_brch - - ''' - def toMesh(self): - pass - ''' - - - - -# No GUI code above this! ------------------------------------------------------ - -# PREFS - These can be saved on the object's id property. use 'tree2curve' slot -from Blender import Draw -import BPyWindow -ID_SLOT_NAME = 'Curve2Tree' - -EVENT_NONE = 0 -EVENT_EXIT = 1 -EVENT_UPDATE = 2 -EVENT_UPDATE_AND_UI = 2 -EVENT_REDRAW = 3 - - -# Prefs for each tree -PREFS = {} -PREFS['connect_sloppy'] = Draw.Create(1.5) -PREFS['connect_base_trim'] = Draw.Create(1.0) -PREFS['seg_density'] = Draw.Create(0.5) -PREFS['seg_density_angle'] = Draw.Create(20.0) -PREFS['seg_density_radius'] = Draw.Create(0.3) -PREFS['seg_joint_compression'] = Draw.Create(1.0) -PREFS['seg_joint_smooth'] = Draw.Create(2.0) -PREFS['image_main'] = Draw.Create('') -PREFS['do_uv'] = Draw.Create(0) -PREFS['uv_x_scale'] = Draw.Create(4.0) -PREFS['uv_y_scale'] = Draw.Create(1.0) -PREFS['do_material'] = Draw.Create(0) -PREFS['material_use_existing'] = Draw.Create(1) -PREFS['material_texture'] = Draw.Create(1) -PREFS['material_stencil'] = Draw.Create(1) -PREFS['do_subsurf'] = Draw.Create(1) -PREFS['do_cap_ends'] = Draw.Create(0) -PREFS['do_uv_keep_vproportion'] = Draw.Create(1) -PREFS['do_uv_vnormalize'] = Draw.Create(0) -PREFS['do_uv_uscale'] = Draw.Create(0) -PREFS['do_armature'] = Draw.Create(0) -PREFS['do_anim'] = Draw.Create(1) -try: PREFS['anim_tex'] = Draw.Create([tex for tex in bpy.data.textures][0].name) -except: PREFS['anim_tex'] = Draw.Create('') - -PREFS['anim_speed'] = Draw.Create(0.2) -PREFS['anim_magnitude'] = Draw.Create(0.2) -PREFS['anim_speed_size_scale'] = Draw.Create(1) -PREFS['anim_offset_scale'] = Draw.Create(1.0) - -PREFS['do_twigs_fill'] = Draw.Create(0) -PREFS['twig_fill_levels'] = Draw.Create(4) - -PREFS['twig_fill_rand_scale'] = Draw.Create(0.1) -PREFS['twig_fill_fork_angle_max'] = Draw.Create(180.0) -PREFS['twig_fill_radius_min'] = Draw.Create(0.001) -PREFS['twig_fill_radius_factor'] = Draw.Create(0.75) -PREFS['twig_fill_shape_type'] = Draw.Create(1) -PREFS['twig_fill_shape_rand'] = Draw.Create(0.5) -PREFS['twig_fill_shape_power'] = Draw.Create(0.5) - -PREFS['do_twigs'] = Draw.Create(0) -PREFS['twig_ratio'] = Draw.Create(2.0) -PREFS['twig_select_mode'] = Draw.Create(0) -PREFS['twig_select_factor'] = Draw.Create(0.5) -PREFS['twig_scale'] = Draw.Create(0.8) -PREFS['twig_scale_width'] = Draw.Create(1.0) -PREFS['twig_random_orientation'] = Draw.Create(180) -PREFS['twig_random_angle'] = Draw.Create(33) -PREFS['twig_recursive'] = Draw.Create(1) -PREFS['twig_recursive_limit'] = Draw.Create(3) -PREFS['twig_ob_bounds'] = Draw.Create('') # WATCH out, used for do_twigs_fill AND do_twigs -PREFS['twig_ob_bounds_prune'] = Draw.Create(1) -PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1.0) -PREFS['twig_placement_maxradius'] = Draw.Create(10.0) -PREFS['twig_placement_maxtwig'] = Draw.Create(4) -PREFS['twig_follow_parent'] = Draw.Create(0.0) -PREFS['twig_follow_x'] = Draw.Create(0.0) -PREFS['twig_follow_y'] = Draw.Create(0.0) -PREFS['twig_follow_z'] = Draw.Create(0.0) - -PREFS['do_leaf'] = Draw.Create(0) - -PREFS['leaf_branch_limit'] = Draw.Create(0.25) -PREFS['leaf_branch_limit_rand'] = Draw.Create(0.1) -PREFS['leaf_branch_density'] = Draw.Create(0.1) -PREFS['leaf_branch_pitch_angle'] = Draw.Create(0.0) -PREFS['leaf_branch_pitch_rand'] = Draw.Create(0.2) -PREFS['leaf_branch_roll_rand'] = Draw.Create(0.2) -PREFS['leaf_branch_angle'] = Draw.Create(75.0) -PREFS['leaf_rand_seed'] = Draw.Create(1.0) -PREFS['leaf_size'] = Draw.Create(0.5) -PREFS['leaf_size_rand'] = Draw.Create(0.5) - -PREFS['leaf_object'] = Draw.Create('') - -PREFS['do_variation'] = Draw.Create(0) -PREFS['variation_seed'] = Draw.Create(1) -PREFS['variation_orientation'] = Draw.Create(0.0) -PREFS['variation_scale'] = Draw.Create(0.0) - -GLOBAL_PREFS = {} -GLOBAL_PREFS['realtime_update'] = Draw.Create(0) - - -def getContextCurveObjects(): - sce = bpy.data.scenes.active - objects = [] - ob_act = sce.objects.active - for ob in sce.objects.context: - if ob == ob_act: ob_act = None - - if ob.type != 'Curve': - ob = ob.parent - if not ob or ob.type != 'Curve': - continue - objects.append(ob) - - # Alredy delt with - - - # Add the active, important when using localview or local layers - if ob_act: - ob = ob_act - if ob.type != 'Curve': - ob = ob.parent - if not ob or ob.type != 'Curve': - pass - else: - objects.append(ob) - - return objects - - -def Prefs2Dict(prefs, new_prefs): - ''' - Make a copy with no button settings - ''' - new_prefs.clear() - for key, val in prefs.items(): - try: new_prefs[key] = val.val - except: new_prefs[key] = val - return new_prefs - -def Dict2Prefs(prefs, new_prefs): - ''' - Make a copy with button settings - ''' - for key in prefs: # items would be nice for id groups - val = prefs[key] - ok = True - - try: - # If we have this setting allredy but its a different type, use the old setting (converting int's to floats for instance) - new_val = new_prefs[key] # this may fail, thats ok - if (type(new_val)==Blender.Types.ButtonType) and (type(new_val.val) != type(val)): - ok = False - except: - pass - - if ok: - try: - new_prefs[key] = Blender.Draw.Create( val ) - except: - new_prefs[key] = val - - return new_prefs - -def Prefs2IDProp(idprop, prefs): - new_prefs = {} - Prefs2Dict(prefs, new_prefs) - try: del idprop[ID_SLOT_NAME] - except: pass - - idprop[ID_SLOT_NAME] = new_prefs - -def IDProp2Prefs(idprop, prefs): - try: - prefs = idprop[ID_SLOT_NAME] - except: - return False - Dict2Prefs(prefs, PREFS) - return True - -def buildTree(ob_curve, single=False): - ''' - Must be a curve object, write to a child mesh - Must check this is a curve object! - ''' - print 'Curve2Tree, starting...' - # if were only doing 1 object, just use the current prefs - prefs = {} - - if single or not (IDProp2Prefs(ob_curve.properties, prefs)): - prefs = PREFS - - - # Check prefs are ok. - - - sce = bpy.data.scenes.active - - def getObChild(parent, obtype): - try: - return [ _ob for _ob in sce.objects if _ob.type == obtype if _ob.parent == parent ][0] - except: - return None - - def newObChild(parent, obdata): - - ob_new = bpy.data.scenes.active.objects.new(obdata) - # ob_new.Layers = parent.Layers - - # new object settings - parent.makeParent([ob_new]) - ob_new.setMatrix(Matrix()) - ob_new.sel = 0 - return ob_new - - def hasModifier(modtype): - return len([mod for mod in ob_mesh.modifiers if mod.type == modtype]) > 0 - - - sce = bpy.data.scenes.active - - if PREFS['image_main'].val: - try: image = bpy.data.images[PREFS['image_main'].val] - except: image = None - else: image = None - - # Get the mesh child - - print '\treading blenders curves...', - time1 = Blender.sys.time() - - t = tree() - t.fromCurve(ob_curve) - if not t.branches_all: - return # Empty curve? - may as well not throw an error - - time2 = Blender.sys.time() # time print - """ - print '%.4f sec' % (time2-time1) - if PREFS['do_twigs'].val: - print '\tbuilding twigs...', - t.buildTwigs(ratio=PREFS['twig_ratio'].val) - time3 = Blender.sys.time() # time print - print '%.4f sec' % (time3 - time2) - """ - if 0: pass - else: - time3 = Blender.sys.time() # time print - - print '\tconnecting branches...', - - twig_ob_bounds = getObFromName(PREFS['twig_ob_bounds'].val) - - t.buildConnections(\ - sloppy = PREFS['connect_sloppy'].val,\ - connect_base_trim = PREFS['connect_base_trim'].val,\ - do_twigs = PREFS['do_twigs'].val,\ - twig_ratio = PREFS['twig_ratio'].val,\ - twig_select_mode = PREFS['twig_select_mode'].val,\ - twig_select_factor = PREFS['twig_select_factor'].val,\ - twig_scale = PREFS['twig_scale'].val,\ - twig_scale_width = PREFS['twig_scale_width'].val,\ - twig_random_orientation = PREFS['twig_random_orientation'].val,\ - twig_random_angle = PREFS['twig_random_angle'].val,\ - twig_recursive = PREFS['twig_recursive'].val,\ - twig_recursive_limit = PREFS['twig_recursive_limit'].val,\ - twig_ob_bounds = twig_ob_bounds,\ - twig_ob_bounds_prune = PREFS['twig_ob_bounds_prune'].val,\ - twig_ob_bounds_prune_taper = PREFS['twig_ob_bounds_prune_taper'].val,\ - twig_placement_maxradius = PREFS['twig_placement_maxradius'].val,\ - twig_placement_maxtwig = PREFS['twig_placement_maxtwig'].val,\ - twig_follow_parent = PREFS['twig_follow_parent'].val,\ - twig_follow_x = PREFS['twig_follow_x'].val,\ - twig_follow_y = PREFS['twig_follow_y'].val,\ - twig_follow_z = PREFS['twig_follow_z'].val,\ - do_variation = PREFS['do_variation'].val,\ - variation_seed = PREFS['variation_seed'].val,\ - variation_orientation = PREFS['variation_orientation'].val,\ - variation_scale = PREFS['variation_scale'].val,\ - do_twigs_fill = PREFS['do_twigs_fill'].val,\ - twig_fill_levels = PREFS['twig_fill_levels'].val,\ - twig_fill_rand_scale = PREFS['twig_fill_rand_scale'].val,\ - twig_fill_fork_angle_max = PREFS['twig_fill_fork_angle_max'].val,\ - twig_fill_radius_min = PREFS['twig_fill_radius_min'].val,\ - twig_fill_radius_factor = PREFS['twig_fill_radius_factor'].val,\ - twig_fill_shape_type = PREFS['twig_fill_shape_type'].val,\ - twig_fill_shape_rand = PREFS['twig_fill_shape_rand'].val,\ - twig_fill_shape_power = PREFS['twig_fill_shape_power'].val,\ - ) - - time4 = Blender.sys.time() # time print - print '%.4f sec' % (time4-time3) - print '\toptimizing point spacing...', - - t.optimizeSpacing(\ - seg_density=PREFS['seg_density'].val,\ - seg_density_angle=PREFS['seg_density_angle'].val,\ - seg_density_radius=PREFS['seg_density_radius'].val,\ - joint_compression = PREFS['seg_joint_compression'].val,\ - joint_smooth = PREFS['seg_joint_smooth'].val\ - ) - - time5 = Blender.sys.time() # time print - print '%.4f sec' % (time5-time4) - print '\tbuilding mesh...', - - ob_mesh = getObChild(ob_curve, 'Mesh') - if not ob_mesh: - # New object - mesh = bpy.data.meshes.new('tree_' + ob_curve.name) - ob_mesh = newObChild(ob_curve, mesh) - # do subsurf later - - else: - # Existing object - mesh = ob_mesh.getData(mesh=1) - ob_mesh.setMatrix(Matrix()) - - # Do we need a do_uv_blend_layer? - if PREFS['do_material'].val and PREFS['material_stencil'].val and PREFS['material_texture'].val: - do_uv_blend_layer = True - else: - do_uv_blend_layer = False - - mesh = t.toMesh(mesh,\ - do_uv = PREFS['do_uv'].val,\ - uv_image = image,\ - do_uv_keep_vproportion = PREFS['do_uv_keep_vproportion'].val,\ - do_uv_vnormalize = PREFS['do_uv_vnormalize'].val,\ - do_uv_uscale = PREFS['do_uv_uscale'].val,\ - uv_x_scale = PREFS['uv_x_scale'].val,\ - uv_y_scale = PREFS['uv_y_scale'].val,\ - do_uv_blend_layer = do_uv_blend_layer,\ - do_cap_ends = PREFS['do_cap_ends'].val - ) - - if PREFS['do_leaf'].val: - ob_leaf_dupliface = getObChild(ob_mesh, 'Mesh') - if not ob_leaf_dupliface: # New object - mesh_leaf = bpy.data.meshes.new('leaf_' + ob_curve.name) - ob_leaf_dupliface = newObChild(ob_mesh, mesh_leaf) - else: - mesh_leaf = ob_leaf_dupliface.getData(mesh=1) - ob_leaf_dupliface.setMatrix(Matrix()) - - leaf_object = getObFromName(PREFS['leaf_object'].val) - - mesh_leaf = t.toLeafMesh(mesh_leaf,\ - leaf_branch_limit = PREFS['leaf_branch_limit'].val,\ - leaf_branch_limit_rand = PREFS['leaf_branch_limit_rand'].val,\ - leaf_size = PREFS['leaf_size'].val,\ - leaf_size_rand = PREFS['leaf_size_rand'].val,\ - leaf_branch_density = PREFS['leaf_branch_density'].val,\ - leaf_branch_pitch_angle = PREFS['leaf_branch_pitch_angle'].val,\ - leaf_branch_pitch_rand = PREFS['leaf_branch_pitch_rand'].val,\ - leaf_branch_roll_rand = PREFS['leaf_branch_roll_rand'].val,\ - leaf_branch_angle = PREFS['leaf_branch_angle'].val,\ - leaf_rand_seed = PREFS['leaf_rand_seed'].val,\ - leaf_object = leaf_object,\ - ) - - if leaf_object: - ob_leaf_dupliface.enableDupFaces = True - ob_leaf_dupliface.enableDupFacesScale = True - ob_leaf_dupliface.makeParent([leaf_object], 1) - else: - ob_leaf_dupliface.enableDupFaces = False - - mesh.calcNormals() - - if PREFS['do_material'].val: - - materials = mesh.materials - if PREFS['material_use_existing'].val and materials: - t.material = materials[0] - else: - t.material = bpy.data.materials.new(ob_curve.name) - mesh.materials = [t.material] - - if PREFS['material_texture'].val: - - # Set up the base image texture - t.texBase = bpy.data.textures.new('base_' + ob_curve.name) - t.material.setTexture(0, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) - t.texBase.type = Blender.Texture.Types.IMAGE - if image: - t.texBase.image = image - t.texBaseMTex = t.material.getTextures()[0] - t.texBaseMTex.uvlayer = 'base' - - if PREFS['material_stencil'].val: - # Set up the blend texture - t.texBlend = bpy.data.textures.new('blend_' + ob_curve.name) - t.material.setTexture(1, t.texBlend, Blender.Texture.TexCo.UV, 0) # map to None - t.texBlend.type = Blender.Texture.Types.BLEND - t.texBlend.flags |= Blender.Texture.Flags.FLIPBLEND - t.texBlendMTex = t.material.getTextures()[1] - t.texBlendMTex.stencil = True - t.texBlendMTex.uvlayer = 'blend' - - - # Now make the texture for the stencil to blend, can reuse texBase here, jus tdifferent settings for the mtex - t.material.setTexture(2, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL) - t.texJoinMTex = t.material.getTextures()[2] - t.texJoinMTex.uvlayer = 'join' - - # Add a UV layer for blending - - - - - time6 = Blender.sys.time() # time print - print '%.4f sec' % (time6-time5) - - # Do armature stuff.... - if PREFS['do_armature'].val: - - print '\tbuilding armature & animation...', - - ob_arm = getObChild(ob_curve, 'Armature') - if ob_arm: - armature = ob_arm.data - ob_arm.setMatrix(Matrix()) - else: - armature = bpy.data.armatures.new() - ob_arm = newObChild(ob_curve, armature) - - t.toArmature(ob_arm, armature) - - # Add the modifier. - if not hasModifier(Blender.Modifier.Types.ARMATURE): - mod = ob_mesh.modifiers.append(Blender.Modifier.Types.ARMATURE) - - # TODO - assigne object anyway, even if an existing modifier exists. - mod[Blender.Modifier.Settings.OBJECT] = ob_arm - - if PREFS['do_anim'].val: - try: - tex = bpy.data.textures[PREFS['anim_tex'].val] - except: - tex = None - Blender.Draw.PupMenu('error no texture, cannot animate bones') - - if tex: - t.toAction(ob_arm, tex,\ - anim_speed = PREFS['anim_speed'].val,\ - anim_magnitude = PREFS['anim_magnitude'].val,\ - anim_speed_size_scale= PREFS['anim_speed_size_scale'].val,\ - anim_offset_scale=PREFS['anim_offset_scale'].val - ) - - time7 = Blender.sys.time() # time print - print '%.4f sec\n' % (time7-time6) - else: - time7 = Blender.sys.time() # time print - - print 'done in %.4f sec' % (time7 - time1) - - # Add subsurf last it needed. so armature skinning is done first. - # Do subsurf? - if PREFS['do_subsurf'].val: - if not hasModifier(Blender.Modifier.Types.SUBSURF): - mod = ob_mesh.modifiers.append(Blender.Modifier.Types.SUBSURF) - - #ob_mesh.makeDisplayList() - #mesh.update() - bpy.data.scenes.active.update() - -def do_pref_read(e=0,v=0, quiet=False): - ''' - We dont care about e and v values, only there because its a callback - ''' - sce = bpy.data.scenes.active - ob = sce.objects.active - - if not ob: - if not quiet: - Blender.Draw.PupMenu('No active curve object') - return - - if ob.type != 'Curve': - ob = ob.parent - - if ob == None or ob.type != 'Curve': - if not quiet: - Blender.Draw.PupMenu('No active curve object') - return - - if not IDProp2Prefs(ob.properties, PREFS): - if not quiet: - Blender.Draw.PupMenu('Curve object has no settings stored on it') - return - - Blender.Draw.Redraw() - -def do_pref_write(e,v): - - objects = getContextCurveObjects() - if not objects: - Blender.Draw.PupMenu('No curve objects selected') - return - - for ob in objects: - Prefs2IDProp(ob.properties, PREFS) - -def do_pref_clear(e,v): - objects = getContextCurveObjects() - if not objects: - Blender.Draw.PupMenu('No curve objects selected') - return - - for ob in objects: - try: del ob.properties[ID_SLOT_NAME] - except: pass - -def do_tex_check(e,v): - if not v: return - try: - bpy.data.textures[v] - except: - PREFS['anim_tex'].val = '' - Draw.PupMenu('Texture dosnt exist!') - Draw.Redraw() - -def do_ob_check(e,v): - if not v: return - try: - bpy.data.objects[v] - except: - # PREFS['twig_ob_bounds'].val = '' - Draw.PupMenu('Object dosnt exist!') - Draw.Redraw() - -def do_group_check(e,v): - if not v: return - try: - bpy.data.groups[v] - except: - # PREFS['leaf_object'].val = '' - Draw.PupMenu('dosnt exist!') - Draw.Redraw() - -# Button callbacks -def do_active_image(e,v): - img = bpy.data.images.active - if img: - PREFS['image_main'].val = img.name - else: - PREFS['image_main'].val = '' - -# Button callbacks -def do_tree_generate__real(): - sce = bpy.data.scenes.active - objects = getContextCurveObjects() - - if not objects: - Draw.PupMenu('Select one or more curve objects or a mesh/armature types with curve parents') - - is_editmode = Blender.Window.EditMode() - if is_editmode: - Blender.Window.EditMode(0, '', 0) - Blender.Window.WaitCursor(1) - - for ob in objects: - buildTree(ob, len(objects)==1) - - if is_editmode: - Blender.Window.EditMode(1, '', 0) - - Blender.Window.RedrawAll() - - Blender.Window.WaitCursor(0) - - -# Profile -# Had to do this to get it to work in ubuntu "sudo aptitude install python-profiler" -''' -import hotshot -import profile -from hotshot import stats -''' -def do_tree_generate(e,v): - - do_tree_generate__real() - ''' - prof = hotshot.Profile("hotshot_edi_stats") - prof.runcall(do_tree_generate__real) - prof.close() - s = stats.load("hotshot_edi_stats") - s.sort_stats("time").print_stats() - ''' - if GLOBALS['non_bez_error']: - Blender.Draw.PupMenu('Error%t|Nurbs and Poly curve types cant be used!') - GLOBALS['non_bez_error'] = 0 - -def do_tree_help(e,v): - url = 'http://wiki.blender.org/index.php/Scripts/Manual/Wizards/TreeFromCurves' - print 'Trying to open web browser with documentation at this address...' - print '\t' + url - - try: - import webbrowser - webbrowser.open(url) - except: - print '...could not open a browser window.' - - -def evt(e,val): - pass - -def bevt(e): - - if e==EVENT_NONE: - return - - if e == EVENT_UPDATE or e == EVENT_UPDATE_AND_UI: - if GLOBAL_PREFS['realtime_update'].val: - do_tree_generate(0,0) # values dont matter - - if e == EVENT_REDRAW or e == EVENT_UPDATE_AND_UI: - Draw.Redraw() - if e == EVENT_EXIT: - Draw.Exit() - pass - -def gui(): - MARGIN = 4 - rect = BPyWindow.spaceRect() - but_width = int((rect[2]-MARGIN*2)/4.0) # 72 - # Clamp - if but_width>100: but_width = 100 - but_height = 17 - - x=MARGIN - y=rect[3]-but_height-MARGIN - xtmp = x - - Blender.Draw.BeginAlign() - PREFS['do_twigs_fill'] = Draw.Toggle('Fill Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs_fill'].val, 'Generate child branches based existing branches'); xtmp += but_width*2; - if PREFS['do_twigs_fill'].val: - - PREFS['twig_fill_levels'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_levels'].val, 1, 32, 'How many generations to make for filled twigs'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - # WARNING USED IN 2 PLACES!! - see below - PREFS['twig_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64, 'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2; - PREFS['twig_fill_rand_scale'] = Draw.Number('Randomize Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_rand_scale'].val, 0.0, 1.0, 'Randomize twig scale from the bounding mesh'); xtmp += but_width*2; - - y-=but_height - xtmp = x - - PREFS['twig_fill_radius_min'] = Draw.Number('Min Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_min'].val, 0.0, 1.0, 'Radius at endpoints of all twigs'); xtmp += but_width*2; - PREFS['twig_fill_radius_factor'] = Draw.Number('Inherit Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_factor'].val, 0.0, 1.0, 'What attaching to branches, scale the radius by this value for filled twigs, 0.0 for fixed width twigs.'); xtmp += but_width*2; - - y-=but_height - xtmp = x - - #PREFS['twig_fill_shape_type'] = Draw.Number('Shape Type', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val, 0.0, 1.0, 'Shape used for the fork'); xtmp += but_width*2; - PREFS['twig_fill_shape_type'] = Draw.Menu('Join Type%t|Even%x0|Smooth One Child%x1|Smooth Both Children%x2',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val, 'Select the wat twigs '); xtmp += but_width*2; - PREFS['twig_fill_fork_angle_max'] = Draw.Number('Shape Max Ang', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_fork_angle_max'].val, 0.0, 180.0, 'Maximum fork angle'); xtmp += but_width*2; - - y-=but_height - xtmp = x - - PREFS['twig_fill_shape_rand'] = Draw.Number('Shape Rand', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_rand'].val, 0.0, 1.0, 'Randomize the shape of forks'); xtmp += but_width*2; - PREFS['twig_fill_shape_power'] = Draw.Number('Shape Strength', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_power'].val, 0.0, 1.0, 'Strength of curves'); xtmp += but_width*2; - - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - - - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREFS['do_twigs'] = Draw.Toggle('Grow Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val, 'Generate child branches based existing branches'); xtmp += but_width*2; - if PREFS['do_twigs'].val: - - PREFS['twig_ratio'] = Draw.Number('Twig Multiply', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_ratio'].val, 0.01, 500.0, 'How many twigs to generate per branch'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - PREFS['twig_select_mode'] = Draw.Menu('Branch Selection Method%t|From Short%x0|From Long%x1|From Straight%x2|From Bent%x3|',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_select_mode'].val, 'Select branches to use as twigs based on this attribute'); xtmp += but_width*2; - PREFS['twig_select_factor'] = Draw.Number('From Factor', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_select_factor'].val, 0.0, 16, 'Select branches, lower value is more strict and will give you less variation'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - PREFS['twig_recursive'] = Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val, 'Recursively add twigs into eachother'); xtmp += but_width*2; - PREFS['twig_recursive_limit'] = Draw.Number('Generations', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_recursive_limit'].val, 0.0, 16, 'Number of generations allowed, 0 is inf'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - - PREFS['twig_scale'] = Draw.Number('Twig Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale'].val, 0.01, 10.0, 'Scale down twigs in relation to their parents each generation'); xtmp += but_width*2; - PREFS['twig_scale_width'] = Draw.Number('Twig Scale Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale_width'].val, 0.01, 20.0, 'Scale the twig length only (not thickness)'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - - PREFS['twig_random_orientation'] = Draw.Number('Rand Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_orientation'].val, 0.0, 360.0, 'Random rotation around the parent'); xtmp += but_width*2; - PREFS['twig_random_angle'] = Draw.Number('Rand Angle', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_angle'].val, 0.0, 360.0, 'Random rotation to the parent joint'); xtmp += but_width*2; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - - PREFS['twig_placement_maxradius'] = Draw.Number('Place Max Radius', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0, 'Only place twigs on branches below this radius'); xtmp += but_width*2; - PREFS['twig_placement_maxtwig'] = Draw.Number('Place Max Count', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxtwig'].val, 0.0, 50.0, 'Limit twig placement to this many per branch'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['twig_follow_parent'] = Draw.Number('ParFollow', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_parent'].val, 0.0, 10.0, 'Follow the parent branch'); xtmp += but_width; - PREFS['twig_follow_x'] = Draw.Number('Grav X', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_x'].val, -10.0, 10.0, 'Twigs gravitate on the X axis'); xtmp += but_width; - PREFS['twig_follow_y'] = Draw.Number('Grav Y', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_y'].val, -10.0, 10.0, 'Twigs gravitate on the Y axis'); xtmp += but_width; - PREFS['twig_follow_z'] = Draw.Number('Grav Z', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_z'].val, -10.0, 10.0, 'Twigs gravitate on the Z axis'); xtmp += but_width; - - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - # WARNING USED IN 2 PLACES!! - PREFS['twig_ob_bounds'] = Draw.String('OB Bound: ', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64, 'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2; - - if PREFS['twig_ob_bounds_prune'].val: - but_width_tmp = but_width - else: - but_width_tmp = but_width*2 - - PREFS['twig_ob_bounds_prune'] = Draw.Toggle('Prune',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['twig_ob_bounds_prune'].val, 'Prune twigs to the mesh object bounds'); xtmp += but_width_tmp; - if PREFS['twig_ob_bounds_prune'].val: - PREFS['twig_ob_bounds_prune_taper'] = Draw.Number('Taper', EVENT_UPDATE_AND_UI, xtmp, y, but_width, but_height, PREFS['twig_ob_bounds_prune_taper'].val, 0.0, 1.0, 'Taper pruned branches to a point'); xtmp += but_width; - - #PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; - #Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - - - Blender.Draw.BeginAlign() - PREFS['do_leaf'] = Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_leaf'].val, 'Generate leaves using duplifaces'); xtmp += but_width*2; - - if PREFS['do_leaf'].val: - - PREFS['leaf_object'] = Draw.String('OB: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_object'].val, 64, 'Use this object as a leaf', do_ob_check); xtmp += but_width*2; - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['leaf_size'] = Draw.Number('Size', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0, 'size of the leaf'); xtmp += but_width*2; - PREFS['leaf_size_rand'] = Draw.Number('Randsize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size_rand'].val, 0.0, 1.0, 'randomize the leaf size'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - # Dont use yet - PREFS['leaf_branch_limit'] = Draw.Number('Branch Limit', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit'].val, 0.0, 1.0, 'Maximum thichness where a branch can bare leaves, higher value to place leaves on bigger branches'); xtmp += but_width*2; - PREFS['leaf_branch_limit_rand'] = Draw.Number('Limit Random', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit_rand'].val, 0.0, 1.0, 'Randomize the allowed minimum branch width to place leaves'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['leaf_branch_density'] = Draw.Number('Density', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_density'].val, 0.0, 1.0, 'Chance each segment has of baring a leaf, use a high value for more leaves'); xtmp += but_width*2; - PREFS['leaf_branch_angle'] = Draw.Number('Angle From Branch', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_angle'].val, 0.0, 90.0, 'angle the leaf is from the branch direction'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['leaf_rand_seed'] = Draw.Number('Random Seed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_rand_seed'].val, 0.0, 10000.0, 'Set the seed for leaf random values'); xtmp += but_width*2; - PREFS['leaf_branch_pitch_angle'] = Draw.Number('Pitch Angle', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_angle'].val, -180, 180.0, 'Change the pitch rotation of leaves, negative angle to point down'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['leaf_branch_pitch_rand'] = Draw.Number('Random Pitch', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_rand'].val, 0.0, 1.0, 'Randomize the leaf rotation (up-down/pitch)'); xtmp += but_width*2; - PREFS['leaf_branch_roll_rand'] = Draw.Number('Random Roll', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_roll_rand'].val, 0.0, 1.0, 'Randomize the leaf rotation (roll/tilt/yaw)'); xtmp += but_width*2; - - - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - - Blender.Draw.BeginAlign() - if PREFS['do_uv'].val == 0: but_width_tmp = but_width*2 - else: but_width_tmp = but_width*4 - PREFS['do_uv'] = Draw.Toggle('Generate UVs',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_uv'].val, 'Calculate UVs coords'); xtmp += but_width_tmp; - - if PREFS['do_uv'].val: - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['do_uv_uscale'] = Draw.Toggle('U-Scale', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val, 'Scale the width according to the face size (will NOT tile)'); xtmp += but_width; - PREFS['do_uv_keep_vproportion'] = Draw.Toggle('V-Aspect', EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val, 'Correct the UV aspect with the branch width'); xtmp += but_width; - PREFS['do_uv_vnormalize'] = Draw.Toggle('V-Normaize', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val, 'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['uv_x_scale'] = Draw.Number('Scale U', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_x_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - PREFS['uv_y_scale'] = Draw.Number('Scale V', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val, 0.01, 10.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['image_main'] = Draw.String('IM: ', EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64, 'Image to apply to faces'); xtmp += but_width*3; - Draw.PushButton('Use Active', EVENT_UPDATE, xtmp, y, but_width, but_height, 'Get the image from the active image window', do_active_image); xtmp += but_width; - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - Blender.Draw.BeginAlign() - PREFS['do_material'] = Draw.Toggle('Generate Material',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_material'].val, 'Create material and textures (for seamless joints)'); xtmp += but_width*2; - - if PREFS['do_material'].val: - PREFS['material_use_existing'] = Draw.Toggle('ReUse Existing',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_use_existing'].val, 'Modify the textures of the existing material'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - y-=but_height - xtmp = x - - PREFS['material_texture'] = Draw.Toggle('Texture', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_texture'].val, 'Create an image texture for this material to use'); xtmp += but_width*2; - PREFS['material_stencil'] = Draw.Toggle('Blend Joints', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['material_stencil'].val, 'Use a 2 more texture and UV layers to blend the seams between joints'); xtmp += but_width*2; - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - Blender.Draw.BeginAlign() - if PREFS['do_armature'].val == 0: - but_width_tmp = but_width*2 - else: - but_width_tmp = but_width*4 - - Blender.Draw.BeginAlign() - PREFS['do_armature'] = Draw.Toggle('Generate Motion', EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_armature'].val, 'Generate Armatuer animation and apply to branches'); xtmp += but_width_tmp; - - # ---------- ---------- ---------- ---------- - if PREFS['do_armature'].val: - y-=but_height - xtmp = x - - PREFS['do_anim'] = Draw.Toggle('Texture Anim', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_anim'].val, 'Use a texture to animate the bones'); xtmp += but_width*2; - - if PREFS['do_anim'].val: - - PREFS['anim_tex'] = Draw.String('TEX: ', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_tex'].val, 64, 'Texture to use for the IPO Driver animation', do_tex_check); xtmp += but_width*2; - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['anim_speed'] = Draw.Number('Speed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_speed'].val, 0.001, 10.0, 'Animate the movement faster with a higher value'); xtmp += but_width*2; - PREFS['anim_magnitude'] = Draw.Number('Magnitude', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_magnitude'].val, 0.001, 10.0, 'Animate with more motion with a higher value'); xtmp += but_width*2; - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['anim_offset_scale'] = Draw.Number('Unique Offset Scale', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_offset_scale'].val, 0.001, 10.0, 'Use the curve object location as input into the texture so trees have more unique motion, a low value is less unique'); xtmp += but_width*4; - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - - PREFS['anim_speed_size_scale'] = Draw.Toggle('Branch Size Scales Speed', EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_speed_size_scale'].val, 'Use the branch size as a factor when calculating speed'); xtmp += but_width*4; - - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - - - - - # ---------- ---------- ---------- ---------- - - Blender.Draw.BeginAlign() - PREFS['do_variation'] = Draw.Toggle('Generate Variation', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_variation'].val, 'Create a variant by moving the branches'); xtmp += but_width*2; - - # ---------- ---------- ---------- ---------- - if PREFS['do_variation'].val: - PREFS['variation_seed'] = Draw.Number('Rand Seed', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_seed'].val, 1, 100000, 'Change this to get a different variation'); xtmp += but_width*2; - y-=but_height - xtmp = x - - - PREFS['variation_orientation'] = Draw.Number('Orientation', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_orientation'].val, 0, 1.0, 'Randomize rotation of the branch around its parent'); xtmp += but_width*2; - PREFS['variation_scale'] = Draw.Number('Scale', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_scale'].val, 0.0, 1.0, 'Randomize the scale of branches'); xtmp += but_width*2; - - Blender.Draw.EndAlign() - - y-=but_height+(MARGIN*2) - xtmp = x - - - - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREFS['seg_density'] = Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val, 0.05, 10.0, 'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4; - - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - PREFS['seg_density_angle'] = Draw.Number('Angle Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val, 0.0, 180.0, 'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2; - PREFS['seg_density_radius'] = Draw.Number('Radius Spacing', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val, 0.0, 1.0, 'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['seg_joint_compression'] = Draw.Number('Joint Width', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_compression'].val, 0.1, 2.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - PREFS['seg_joint_smooth'] = Draw.Number('Joint Smooth', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_smooth'].val, 0.0, 1.0, 'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2; - - y-=but_height - xtmp = x - # ---------- ---------- ---------- ---------- - - PREFS['connect_sloppy'] = Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val, 0.1, 3.0, 'Strictness when connecting branches'); xtmp += but_width*2; - PREFS['connect_base_trim'] = Draw.Number('Joint Bevel', EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val, 0.0, 2.0, 'low value for a tight join, hi for a smoother bevel'); xtmp += but_width*2; - Blender.Draw.EndAlign() - y-=but_height+MARGIN - xtmp = x - - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - PREFS['do_cap_ends'] = Draw.Toggle('Cap Ends',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_cap_ends'].val, 'Add faces onto branch endpoints'); xtmp += but_width*2; - PREFS['do_subsurf'] = Draw.Toggle('SubSurf',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_subsurf'].val, 'Enable subsurf for newly generated objects'); xtmp += but_width*2; - Blender.Draw.EndAlign() - y-=but_height+MARGIN - xtmp = x - - - # ---------- ---------- ---------- ---------- - Blender.Draw.BeginAlign() - Draw.PushButton('Read Active Prefs', EVENT_REDRAW, xtmp, y, but_width*2, but_height, 'Read the ID Property settings from the active curve object', do_pref_read); xtmp += but_width*2; - Draw.PushButton('Write Prefs to Sel', EVENT_NONE, xtmp, y, but_width*2, but_height, 'Save these settings in the ID Properties of all selected curve objects', do_pref_write); xtmp += but_width*2; - - y-=but_height - xtmp = x - - # ---------- ---------- ---------- ---------- - Draw.PushButton('Clear Prefs from Sel', EVENT_NONE, xtmp, y, but_width*4, but_height, 'Remove settings from the selected curve aaobjects', do_pref_clear); xtmp += but_width*4; - Blender.Draw.EndAlign() - - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - Blender.Draw.BeginAlign() - Draw.PushButton('Exit', EVENT_EXIT, xtmp, y, but_width, but_height, ''); xtmp += but_width; - Draw.PushButton('Help', EVENT_NONE, xtmp, y, but_width, but_height, '', do_tree_help); xtmp += but_width; - Draw.PushButton('Generate from selection', EVENT_REDRAW, xtmp, y, but_width*2, but_height, 'Generate mesh', do_tree_generate); xtmp += but_width*3; - Blender.Draw.EndAlign() - y-=but_height+MARGIN - xtmp = x - # ---------- ---------- ---------- ---------- - - GLOBAL_PREFS['realtime_update'] = Draw.Toggle('Automatic Update', EVENT_UPDATE, xtmp, y, but_width*4, but_height, GLOBAL_PREFS['realtime_update'].val, 'Update automatically when settings change'); xtmp += but_width*4; - - - -if __name__ == '__main__': - # Read the active objects prefs on load. if they exist - do_pref_read(quiet=True) - - Draw.Register(gui, evt, bevt) diff --git a/source/Makefile b/source/Makefile index 5ebff3bbbf5..cd8bf0e7cb4 100644 --- a/source/Makefile +++ b/source/Makefile @@ -148,9 +148,11 @@ ifneq ($(NAN_NO_KETSJI),true) COMLIB += $(OCGDIR)/gameengine/ketsji/KXNetwork/$(DEBUG_DIR)libKXNetwork.a COMLIB += $(OCGDIR)/gameengine/Network/$(DEBUG_DIR)libNetwork.a COMLIB += $(OCGDIR)/gameengine/Network/LoopBackNetwork/$(DEBUG_DIR)libLoopBackNetwork.a - COMLIB += $(NAN_BULLET2)/lib/libbullet2.a endif +# Required by cloth, not gameengine only anymore +COMLIB += $(NAN_BULLET2)/lib/$(DEBUG_DIR)libbullet2.a + COMLIB += $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a COMLIB += $(NAN_MEMUTIL)/lib/libmemutil.a COMLIB += $(NAN_BMFONT)/lib/$(DEBUG_DIR)libbmfont.a diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index af920e9762d..6575b8b873b 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -24,14 +24,14 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Daniel Genrich. * * ***** END GPL LICENSE BLOCK ***** */ #ifndef BKE_CLOTH_H #define BKE_CLOTH_H -#include "float.h" +#include <float.h> #include "BLI_linklist.h" #include "BKE_customdata.h" @@ -49,6 +49,9 @@ #include "BKE_collision.h" +#include "RE_raytrace.h" + + struct Object; struct MFace; @@ -102,7 +105,8 @@ typedef struct Cloth unsigned char old_solver_type; /* unused, only 1 solver here */ unsigned char pad2; short pad3; - struct BVH *tree; /* collision tree for this cloth object */ + struct BVHTree *bvhtree; /* collision tree for this cloth object */ + struct BVHTree *bvhselftree; /* collision tree for this cloth object */ struct MFace *mfaces; struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */ struct Implicit_Data *implicitEM; /* our implicit solver connects to this pointer */ @@ -171,17 +175,10 @@ ClothSpring; /* These are the bits used in SimSettings.flags. */ typedef enum { - //CLOTH_SIMSETTINGS_FLAG_RESET = ( 1 << 1 ), // The CM object requires a reinitializaiton. CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled - //CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT = ( 1 << 5 ), // true if tearing is enabled - //CLOTH_SIMSETTINGS_FLAG_EDITMODE = ( 1 << 6 ), // are we in editmode? -several things disabled - //CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE = ( 1 << 7 ), /* force cache freeing */ CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */ - //CLOTH_SIMSETTINGS_FLAG_LOADED = ( 1 << 9 ), /* did we just got load? */ - //CLOTH_SIMSETTINGS_FLAG_AUTOPROTECT = ( 1 << 10 ), /* is autoprotect enabled? */ - //CLOTH_SIMSETTINGS_FLAG_CCACHE_OUTDATED = (1 << 11), /* while protected, did cache get outdated? */ CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12) /* edit cache in editmode */ } CLOTH_SIMSETTINGS_FLAGS; @@ -208,6 +205,7 @@ typedef enum CLOTH_SPRING_FLAG_NEEDED = ( 1 << 2 ), // springs has values to be applied } CLOTH_SPRINGS_FLAGS; + ///////////////////////////////////////////////// // collision.c //////////////////////////////////////////////// @@ -246,7 +244,8 @@ DerivedMesh *clothModifier_do ( ClothModifierData *clmd,Object *ob, DerivedMesh void cloth_update_normals ( ClothVertex *verts, int nVerts, MFace *face, int totface ); // needed for collision.c -void bvh_update_from_cloth ( ClothModifierData *clmd, int moving ); +void bvhtree_update_from_cloth ( ClothModifierData *clmd, int moving ); +void bvhselftree_update_from_cloth ( ClothModifierData *clmd, int moving ); // needed for editmesh.c void cloth_write_cache ( Object *ob, ClothModifierData *clmd, float framenr ); diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 7328f9108e3..f0298950f8b 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -32,7 +32,7 @@ #define BKE_COLLISIONS_H #include <math.h> -#include "float.h" +#include <float.h> #include <stdlib.h> #include <string.h> @@ -47,6 +47,8 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "BLI_kdopbvh.h" + struct Object; struct Cloth; struct MFace; @@ -102,10 +104,16 @@ BVH; typedef void ( *CM_COLLISION_RESPONSE ) ( ModifierData *md1, ModifierData *md2, CollisionTree *tree1, CollisionTree *tree2 ); // needed for collision.c -int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision); +int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision ); //////////////////////////////////////// +/* COLLISION FLAGS */ +typedef enum +{ + COLLISION_IN_FUTURE = ( 1 << 1 ), +} COLLISION_FLAGS; + //////////////////////////////////////// // used for collisions in kdop.c and also collision.c @@ -119,10 +127,10 @@ typedef struct CollPair float normal[3]; float vector[3]; // unnormalized collision vector: p2-p1 float pa[3], pb[3]; // collision point p1 on face1, p2 on face2 - int lastsign; // indicates if the distance sign has changed, unused itm + int flag; float time; // collision time, from 0 up to 1 - unsigned int ap1, ap2, ap3, bp1, bp2, bp3; - unsigned int pointsb[4]; + int ap1, ap2, ap3, bp1, bp2, bp3; + int pointsb[4]; } CollPair; @@ -160,8 +168,9 @@ FaceCollPair; // NOTICE: mvert-routines for building + update the BVH are the most native ones // builds bounding volume hierarchy -void bvh_build (BVH *bvh); -BVH *bvh_build_from_mvert (MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon); +void bvh_build ( BVH *bvh ); +BVH *bvh_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ); +BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ); // frees the same void bvh_free ( BVH * bvh ); @@ -169,20 +178,21 @@ void bvh_free ( BVH * bvh ); // checks two bounding volume hierarchies for potential collisions and returns some list with those -// update bounding volumes, needs updated positions in bvh->current_xold (static) +// update bounding volumes, needs updated positions in bvh->current_xold (static) // and also bvh->current_x if moving==1 -void bvh_update_from_mvert(BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving); -void bvh_update(BVH * bvh, int moving); +void bvh_update_from_mvert ( BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving ); +void bvh_update ( BVH * bvh, int moving ); +void bvhtree_update_from_mvert ( BVHTree * bvhtree, MFace *faces, int numfaces, MVert *x, MVert *xnew, int numverts, int moving ); LinkNode *BLI_linklist_append_fast ( LinkNode **listp, void *ptr ); // move Collision modifier object inter-frame with step = [0,1] // defined in collisions.c -void collision_move_object(CollisionModifierData *collmd, float step, float prevstep); +void collision_move_object ( CollisionModifierData *collmd, float step, float prevstep ); // interface for collision functions -void collisions_compute_barycentric (float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3); -void interpolateOnTriangle(float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3); +void collisions_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 ); +void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3 ); ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_collisions.h b/source/blender/blenkernel/BKE_collisions.h new file mode 100644 index 00000000000..f0f6212d3f5 --- /dev/null +++ b/source/blender/blenkernel/BKE_collisions.h @@ -0,0 +1,130 @@ +/** + * BKE_cloth.h + * + * $Id: BKE_cloth.h,v 1.1 2007/08/01 02:07:27 daniel Exp $ + * + * ***** 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) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_COLLISIONS_H +#define BKE_COLLISIONS_H + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +/* types */ +#include "BLI_linklist.h" +#include "BKE_DerivedMesh.h" +#include "BKE_object.h" + +#include "DNA_modifier_types.h" + +// used in kdop.c and collision.c +typedef struct CollisionTree +{ + struct CollisionTree *nodes[4]; // 4 children --> quad-tree + struct CollisionTree *parent; + struct CollisionTree *nextLeaf; + struct CollisionTree *prevLeaf; + float bv[26]; // Bounding volume of all nodes / we have 7 axes on a 14-DOP + int point_index[4]; // supports up to 4 points in a leaf + int count_nodes; // how many nodes are used + int traversed; // how many nodes already traversed until this level? + int isleaf; +} +CollisionTree; + +typedef struct CollisionTree TreeNode; + +typedef struct BVH +{ + unsigned int numfaces; + unsigned int numverts; + MVert *xnew; // position of verts at time n + MVert *x; // position of verts at time n-1 + MFace *mfaces; // just a pointer to the original datastructure + struct LinkNode *tree; + CollisionTree *root; // TODO: saving the root --> is this really needed? YES! + CollisionTree *leaf_tree; /* Tail of the leaf linked list. */ + CollisionTree *leaf_root; /* Head of the leaf linked list. */ + float epsilon; /* epslion is used for inflation of the k-dop */ + int flags; /* bvhFlags */ + +} +BVH; + + +/* used for collisions in kdop.c and also collision.c*/ +typedef struct CollisionPair +{ + int point_indexA[4], point_indexB[4]; + float vector[3]; + float normal[3]; // has to be calculated from vector + float distance; + float pa[3], pb[3]; +} +CollisionPair; + + +///////////////////////////////////////////////// +// forward declarations +///////////////////////////////////////////////// + +// NOTICE: mvert-routines for building + update the BVH are the most native ones + +// builds bounding volume hierarchy +BVH *bvh_build_from_mvert (MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon); +BVH *bvh_build_from_float3 (MFace *mfaces, unsigned int numfaces, float (*x)[3], unsigned int numverts, float epsilon); +BVH *bvh_build_from_float4 (MFace *mfaces, unsigned int numfaces, float (*x)[4], unsigned int numverts, float epsilon); + +// frees the same +void bvh_free ( BVH *bvh ); + +// checks two bounding volume hierarchies for potential collisions and returns some list with those +int bvh_traverse(CollisionTree *tree1, CollisionTree *tree2, LinkNode **collision_list); + +// update bounding volumes, needs updated positions in bvh->x +void bvh_update_from_mvert(BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving); +void bvh_update_from_float3(BVH * bvh, float (*x)[3], unsigned int numverts, float (*xnew)[3], int moving); +void bvh_update_from_float4(BVH * bvh, float (*x)[4], unsigned int numverts, float (*xnew)[4], int moving); + +LinkNode *BLI_linklist_append_fast (LinkNode **listp, void *ptr); + +// move Collision modifier object inter-frame with step = [0,1] +// defined in collisions.c +void collision_move_object(CollisionModifierData *collmd, float step, float prevstep); + +// interface for collision functions +void collisions_compute_barycentric (float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3); +void interpolateOnTriangle(float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3); + +///////////////////////////////////////////////// + +#endif + diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 3763a659f2f..15816699285 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -31,6 +31,7 @@ #ifndef BKE_EFFECT_H #define BKE_EFFECT_H +#include "DNA_effect_types.h" #include "DNA_object_types.h" struct Effect; diff --git a/source/blender/blenkernel/BKE_sph.h b/source/blender/blenkernel/BKE_sph.h new file mode 100644 index 00000000000..9fa42f5acb2 --- /dev/null +++ b/source/blender/blenkernel/BKE_sph.h @@ -0,0 +1,69 @@ +/** + * ***** 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) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef BKE_SPH_H +#define BKE_SPH_H + + +#include "BKE_DerivedMesh.h" +#include "BKE_utildefines.h" + +#include "BLI_linklist.h" + +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +void sph_init(SphModifierData *sphmd); +void sph_free_modifier (SphModifierData *sphmd); +DerivedMesh *sphModifier_do(SphModifierData *sphmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc); +int sph_init_all (SphModifierData *sphmd, DerivedMesh *dm, Object *ob); + + +/* SIMULATION FLAGS: goal flags,.. */ +/* These are the bits used in SimSettings.flags. */ +// first 16 (short) flags are used for fluid type identification +typedef enum +{ + SPH_SIMSETTINGS_FLAG_FLUID = ( 1 << 0 ), // Fluid object? + SPH_SIMSETTINGS_FLAG_OBSTACLE = ( 1 << 1 ), // Obstacle? + SPH_SIMSETTINGS_FLAG_DOMAIN = ( 1 << 2 ), // Fluid domain + + SPH_SIMSETTINGS_FLAG_GHOSTS = ( 1 << 16 ), // use ghost particles? + SPH_SIMSETTINGS_FLAG_OFFLINE = ( 1 << 17 ), // do offline simulation? + SPH_SIMSETTINGS_FLAG_MULTIRES = ( 1 << 18 ), // use multires? + SPH_SIMSETTINGS_FLAG_VORTICITY = ( 1 << 19 ), // use vorticity enhancement? + SPH_SIMSETTINGS_FLAG_BAKING = ( 1 << 20 ), // is domain baking? + SPH_SIMSETTINGS_FLAG_INIT = ( 1 << 21 ), // inited? +} SPH_SIMSETTINGS_FLAGS; + + +#endif //BKE_SPH_H + + + diff --git a/source/blender/blenkernel/CCGSubSurf.h b/source/blender/blenkernel/CCGSubSurf.h new file mode 100644 index 00000000000..a8269b7ada0 --- /dev/null +++ b/source/blender/blenkernel/CCGSubSurf.h @@ -0,0 +1,152 @@ +/* $Id: CCGSubSurf.h 12931 2007-12-17 18:20:48Z theeth $ */ + +typedef void* CCGMeshHDL; +typedef void* CCGVertHDL; +typedef void* CCGEdgeHDL; +typedef void* CCGFaceHDL; + +typedef struct _CCGVert CCGVert; +typedef struct _CCGEdge CCGEdge; +typedef struct _CCGFace CCGFace; + +typedef struct _CCGMeshIFC CCGMeshIFC; +struct _CCGMeshIFC { + int vertUserSize, edgeUserSize, faceUserSize; + + int vertDataSize; +}; + +/***/ + +typedef void* CCGAllocatorHDL; + +typedef struct _CCGAllocatorIFC CCGAllocatorIFC; +struct _CCGAllocatorIFC { + void* (*alloc) (CCGAllocatorHDL a, int numBytes); + void* (*realloc) (CCGAllocatorHDL a, void *ptr, int newSize, int oldSize); + void (*free) (CCGAllocatorHDL a, void *ptr); + void (*release) (CCGAllocatorHDL a); +}; + +/***/ + +typedef enum { + eCCGError_None = 0, + + eCCGError_InvalidSyncState, + eCCGError_InvalidValue, +} CCGError; + +/***/ + +typedef struct _CCGSubSurf CCGSubSurf; + +CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator); +void ccgSubSurf_free (CCGSubSurf *ss); + +CCGError ccgSubSurf_sync (CCGSubSurf *ss); + +CCGError ccgSubSurf_initFullSync (CCGSubSurf *ss); +CCGError ccgSubSurf_initPartialSync (CCGSubSurf *ss); + +CCGError ccgSubSurf_syncVert (CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r); +CCGError ccgSubSurf_syncEdge (CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r); +CCGError ccgSubSurf_syncFace (CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r); + +CCGError ccgSubSurf_syncVertDel (CCGSubSurf *ss, CCGVertHDL vHDL); +CCGError ccgSubSurf_syncEdgeDel (CCGSubSurf *ss, CCGEdgeHDL eHDL); +CCGError ccgSubSurf_syncFaceDel (CCGSubSurf *ss, CCGFaceHDL fHDL); + +CCGError ccgSubSurf_processSync (CCGSubSurf *ss); + +CCGError ccgSubSurf_setSubdivisionLevels (CCGSubSurf *ss, int subdivisionLevels); + +CCGError ccgSubSurf_setAllowEdgeCreation (CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData); +void ccgSubSurf_getAllowEdgeCreation (CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r); + +void ccgSubSurf_getUseAgeCounts (CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r); +CCGError ccgSubSurf_setUseAgeCounts (CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset); + +CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, int normalDataOffset); + +/***/ + +int ccgSubSurf_getNumVerts (CCGSubSurf *ss); +int ccgSubSurf_getNumEdges (CCGSubSurf *ss); +int ccgSubSurf_getNumFaces (CCGSubSurf *ss); + +int ccgSubSurf_getSubdivisionLevels (CCGSubSurf *ss); +int ccgSubSurf_getEdgeSize (CCGSubSurf *ss); +int ccgSubSurf_getEdgeLevelSize (CCGSubSurf *ss, int level); +int ccgSubSurf_getGridSize (CCGSubSurf *ss); +int ccgSubSurf_getGridLevelSize (CCGSubSurf *ss, int level); + +CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v); +CCGVertHDL ccgSubSurf_getVertVertHandle (CCGSubSurf *ss, CCGVert *v); +int ccgSubSurf_getVertNumFaces (CCGSubSurf *ss, CCGVert *v); +CCGFace* ccgSubSurf_getVertFace (CCGSubSurf *ss, CCGVert *v, int index); +int ccgSubSurf_getVertNumEdges (CCGSubSurf *ss, CCGVert *v); +CCGEdge* ccgSubSurf_getVertEdge (CCGSubSurf *ss, CCGVert *v, int index); + +int ccgSubSurf_getVertAge (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertUserData (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertData (CCGSubSurf *ss, CCGVert *v); +void* ccgSubSurf_getVertLevelData (CCGSubSurf *ss, CCGVert *v, int level); + +CCGEdge* ccgSubSurf_getEdge (CCGSubSurf *ss, CCGEdgeHDL e); +CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle (CCGSubSurf *ss, CCGEdge *e); +int ccgSubSurf_getEdgeNumFaces (CCGSubSurf *ss, CCGEdge *e); +CCGFace* ccgSubSurf_getEdgeFace (CCGSubSurf *ss, CCGEdge *e, int index); +CCGVert* ccgSubSurf_getEdgeVert0 (CCGSubSurf *ss, CCGEdge *e); +CCGVert* ccgSubSurf_getEdgeVert1 (CCGSubSurf *ss, CCGEdge *e); +float ccgSubSurf_getEdgeCrease (CCGSubSurf *ss, CCGEdge *e); + +int ccgSubSurf_getEdgeAge (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeUserData (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeDataArray (CCGSubSurf *ss, CCGEdge *e); +void* ccgSubSurf_getEdgeData (CCGSubSurf *ss, CCGEdge *e, int x); +void* ccgSubSurf_getEdgeLevelData (CCGSubSurf *ss, CCGEdge *e, int x, int level); + +CCGFace* ccgSubSurf_getFace (CCGSubSurf *ss, CCGFaceHDL f); +CCGFaceHDL ccgSubSurf_getFaceFaceHandle (CCGSubSurf *ss, CCGFace *f); +int ccgSubSurf_getFaceNumVerts (CCGSubSurf *ss, CCGFace *f); +CCGVert* ccgSubSurf_getFaceVert (CCGSubSurf *ss, CCGFace *f, int index); +CCGEdge* ccgSubSurf_getFaceEdge (CCGSubSurf *ss, CCGFace *f, int index); +int ccgSubSurf_getFaceEdgeIndex (CCGSubSurf *ss, CCGFace *f, CCGEdge *e); + +int ccgSubSurf_getFaceAge (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceUserData (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceCenterData (CCGSubSurf *ss, CCGFace *f); +void* ccgSubSurf_getFaceGridEdgeDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex); +void* ccgSubSurf_getFaceGridEdgeData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x); +void* ccgSubSurf_getFaceGridDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex); +void* ccgSubSurf_getFaceGridData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y); + +int ccgSubSurf_getNumFinalVerts (CCGSubSurf *ss); +int ccgSubSurf_getNumFinalEdges (CCGSubSurf *ss); +int ccgSubSurf_getNumFinalFaces (CCGSubSurf *ss); + +/***/ + +typedef struct _CCGVertIterator CCGVertIterator; +typedef struct _CCGEdgeIterator CCGEdgeIterator; +typedef struct _CCGFaceIterator CCGFaceIterator; + +CCGVertIterator* ccgSubSurf_getVertIterator (CCGSubSurf *ss); +CCGEdgeIterator* ccgSubSurf_getEdgeIterator (CCGSubSurf *ss); +CCGFaceIterator* ccgSubSurf_getFaceIterator (CCGSubSurf *ss); + +CCGVert* ccgVertIterator_getCurrent (CCGVertIterator *vi); +int ccgVertIterator_isStopped (CCGVertIterator *vi); +void ccgVertIterator_next (CCGVertIterator *vi); +void ccgVertIterator_free (CCGVertIterator *vi); + +CCGEdge* ccgEdgeIterator_getCurrent (CCGEdgeIterator *ei); +int ccgEdgeIterator_isStopped (CCGEdgeIterator *ei); +void ccgEdgeIterator_next (CCGEdgeIterator *ei); +void ccgEdgeIterator_free (CCGEdgeIterator *ei); + +CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi); +int ccgFaceIterator_isStopped (CCGFaceIterator *fi); +void ccgFaceIterator_next (CCGFaceIterator *fi); +void ccgFaceIterator_free (CCGFaceIterator *fi); diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 1bb98239a68..4f77e4f42a7 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -10,6 +10,7 @@ incs += ' #/intern/iksolver/extern ../blenloader ../quicktime' incs += ' #/extern/bullet2/src' incs += ' #/intern/bmfont' incs += ' #/intern/opennl/extern' +incs += ' #/intern/sph/extern' incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_OPENGL_INC'] diff --git a/source/blender/blenkernel/bmesh_private.h b/source/blender/blenkernel/bmesh_private.h new file mode 100644 index 00000000000..ad90398bf66 --- /dev/null +++ b/source/blender/blenkernel/bmesh_private.h @@ -0,0 +1,71 @@ +/** + * BME_private.h jan 2007 + * + * low level, 'private' function prototypes for bmesh kernel. + * + * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. 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) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BMESH_PRIVATE +#define BMESH_PRIVATE + +#include "BKE_bmesh.h" + +/*ALLOCATION/DEALLOCATION*/ +struct BME_Vert *BME_addvertlist(struct BME_Mesh *bm, struct BME_Vert *example); +struct BME_Edge *BME_addedgelist(struct BME_Mesh *bm, struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Edge *example); +struct BME_Poly *BME_addpolylist(struct BME_Mesh *bm, struct BME_Poly *example); +struct BME_Loop *BME_create_loop(struct BME_Mesh *bm, struct BME_Vert *v, struct BME_Edge *e, struct BME_Poly *f, struct BME_Loop *example); + +void BME_free_vert(struct BME_Mesh *bm, struct BME_Vert *v); +void BME_free_edge(struct BME_Mesh *bm, struct BME_Edge *e); +void BME_free_poly(struct BME_Mesh *bm, struct BME_Poly *f); +void BME_free_loop(struct BME_Mesh *bm, struct BME_Loop *l); +void BME_delete_loop(struct BME_Mesh *bm, struct BME_Loop *l); + +/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/ +void BME_cycle_append(void *h, void *nt); +int BME_cycle_remove(void *h, void *remn); +int BME_cycle_validate(int len, void *h); +/*DISK CYCLE MANAGMENT*/ +int BME_disk_append_edge(struct BME_Edge *e, struct BME_Vert *v); +void BME_disk_remove_edge(struct BME_Edge *e, struct BME_Vert *v); +/*RADIAL CYCLE MANAGMENT*/ +void BME_radial_append(struct BME_Edge *e, struct BME_Loop *l); +void BME_radial_remove_loop(struct BME_Loop *l, struct BME_Edge *e); + +/*MISC FUNCTIONS*/ +int BME_edge_swapverts(struct BME_Edge *e, struct BME_Vert *orig, struct BME_Vert *new); /*relink edge*/ +int BME_disk_hasedge(struct BME_Vert *v, struct BME_Edge *e); + +/*Error reporting. Shouldnt be called by tools ever.*/ +void BME_error(void); +#endif diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 09a51bb37a4..4fb8eeda78d 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -45,6 +45,10 @@ #include "BKE_pointcache.h" +#include "BLI_kdopbvh.h" + +#include <time.h> + #ifdef _WIN32 void tstart ( void ) {} @@ -76,6 +80,40 @@ double tval() } #endif + +/* Util macros */ +#define TO_STR(a) #a +#define JOIN(a,b) a##b + +/* Benchmark macros */ +#if 1 + +#define BENCH(a) \ + do { \ + clock_t _clock_init = clock(); \ + (a); \ + printf("%s: %fms\n", #a, (float)(clock()-_clock_init)*1000/CLOCKS_PER_SEC); \ +} while(0) + +#define BENCH_VAR(name) clock_t JOIN(_bench_step,name) = 0, JOIN(_bench_total,name) = 0 +#define BENCH_BEGIN(name) JOIN(_bench_step, name) = clock() +#define BENCH_END(name) JOIN(_bench_total,name) += clock() - JOIN(_bench_step,name) +#define BENCH_RESET(name) JOIN(_bench_total, name) = 0 +#define BENCH_REPORT(name) printf("%s: %fms\n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC) + +#else + +#define BENCH(a) (a) +#define BENCH_VAR(name) +#define BENCH_BEGIN(name) +#define BENCH_END(name) +#define BENCH_RESET(name) +#define BENCH_REPORT(name) + +#endif + + + /* Our available solvers. */ // 255 is the magic reserved number, so NEVER try to put 255 solvers in here! // 254 = MAX! @@ -151,13 +189,14 @@ void cloth_init ( ClothModifierData *clmd ) clmd->sim_parms->goalfrict = 0.0f; } - -BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon) +BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) { - unsigned int i = 0; - BVH *bvh=NULL; + int i; + BVHTree *bvhtree; Cloth *cloth = clmd->clothObject; - ClothVertex *verts = NULL; + ClothVertex *verts; + MFace *mfaces; + float co[12]; if(!clmd) return NULL; @@ -168,69 +207,171 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon) return NULL; verts = cloth->verts; + mfaces = cloth->mfaces; // in the moment, return zero if no faces there - if(!cloth->numfaces) + if(!cloth->numverts) return NULL; - bvh = MEM_callocN(sizeof(BVH), "BVH"); - if (bvh == NULL) + // create quadtree with k=26 + bvhtree = BLI_bvhtree_new(cloth->numverts, epsilon, 4, 6); + + // fill tree + for(i = 0; i < cloth->numverts; i++, verts++) { - printf("bvh: Out of memory.\n"); - return NULL; + VECCOPY(&co[0*3], verts->xold); + + BLI_bvhtree_insert(bvhtree, i, co, 1); } - // springs = cloth->springs; - // numsprings = cloth->numsprings; + // balance tree + BLI_bvhtree_balance(bvhtree); + + return bvhtree; +} + +BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) +{ + int i; + BVHTree *bvhtree; + Cloth *cloth = clmd->clothObject; + ClothVertex *verts; + MFace *mfaces; + float co[12]; - bvh->epsilon = epsilon; - bvh->numfaces = cloth->numfaces; - bvh->mfaces = cloth->mfaces; + if(!clmd) + return NULL; - bvh->numverts = cloth->numverts; + cloth = clmd->clothObject; + + if(!cloth) + return NULL; - bvh->current_x = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_x" ); + verts = cloth->verts; + mfaces = cloth->mfaces; - if (bvh->current_x == NULL) - { - printf("bvh: Out of memory.\n"); - MEM_freeN(bvh); + // in the moment, return zero if no faces there + if(!cloth->numfaces) return NULL; - } - for(i = 0; i < bvh->numverts; i++) + // create quadtree with k=26 + bvhtree = BLI_bvhtree_new(cloth->numfaces, epsilon, 4, 26); + + // fill tree + for(i = 0; i < cloth->numfaces; i++, mfaces++) { - VECCOPY(bvh->current_x[i].co, verts[i].tx); + VECCOPY(&co[0*3], verts[mfaces->v1].xold); + VECCOPY(&co[1*3], verts[mfaces->v2].xold); + VECCOPY(&co[2*3], verts[mfaces->v3].xold); + + if(mfaces->v4) + VECCOPY(&co[3*3], verts[mfaces->v4].xold); + + BLI_bvhtree_insert(bvhtree, i, co, (mfaces->v4 ? 4 : 3)); } - bvh_build (bvh); + // balance tree + BLI_bvhtree_balance(bvhtree); - return bvh; + return bvhtree; } -void bvh_update_from_cloth(ClothModifierData *clmd, int moving) -{ +void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving) +{ unsigned int i = 0; Cloth *cloth = clmd->clothObject; - BVH *bvh = cloth->tree; + BVHTree *bvhtree = cloth->bvhtree; ClothVertex *verts = cloth->verts; + MFace *mfaces; + float co[12], co_moving[12]; + int ret = 0; - if(!bvh) + if(!bvhtree) return; - if(cloth->numverts!=bvh->numverts) - return; + mfaces = cloth->mfaces; - if(cloth->verts) + // update vertex position in bvh tree + if(verts && mfaces) { - for(i = 0; i < bvh->numverts; i++) + for(i = 0; i < cloth->numfaces; i++, mfaces++) { - VECCOPY(bvh->current_x[i].co, verts[i].tx); - VECCOPY(bvh->current_xold[i].co, verts[i].txold); + VECCOPY(&co[0*3], verts[mfaces->v1].txold); + VECCOPY(&co[1*3], verts[mfaces->v2].txold); + VECCOPY(&co[2*3], verts[mfaces->v3].txold); + + if(mfaces->v4) + VECCOPY(&co[3*3], verts[mfaces->v4].txold); + + // copy new locations into array + if(moving) + { + // update moving positions + VECCOPY(&co_moving[0*3], verts[mfaces->v1].tx); + VECCOPY(&co_moving[1*3], verts[mfaces->v2].tx); + VECCOPY(&co_moving[2*3], verts[mfaces->v3].tx); + + if(mfaces->v4) + VECCOPY(&co_moving[3*3], verts[mfaces->v4].tx); + + ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, (mfaces->v4 ? 4 : 3)); + } + else + { + ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, (mfaces->v4 ? 4 : 3)); + } + + // check if tree is already full + if(!ret) + break; } + + BLI_bvhtree_update_tree(bvhtree); } +} + +void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving) +{ + unsigned int i = 0; + Cloth *cloth = clmd->clothObject; + BVHTree *bvhtree = cloth->bvhselftree; + ClothVertex *verts = cloth->verts; + MFace *mfaces; + float co[12], co_moving[12]; + int ret = 0; - bvh_update(bvh, moving); + if(!bvhtree) + return; + + mfaces = cloth->mfaces; + + // update vertex position in bvh tree + if(verts && mfaces) + { + for(i = 0; i < cloth->numverts; i++, verts++) + { + VECCOPY(&co[0*3], verts->txold); + + // copy new locations into array + if(moving) + { + // update moving positions + VECCOPY(&co_moving[0*3], verts->tx); + + ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1); + } + else + { + ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1); + } + + // check if tree is already full + if(!ret) + break; + } + + BLI_bvhtree_update_tree(bvhtree); + } } int modifiers_indexInObject(Object *ob, ModifierData *md_seek); @@ -358,15 +499,15 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul Mat4MulVecfl(ob->obmat, verts->xconst); } - tstart(); + // tstart(); /* call the solver. */ if(solvers [clmd->sim_parms->solver_type].solver) - ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors); + BENCH(ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors)); - tend(); + // tend(); - /* printf ( "Cloth simulation time: %f\n", ( float ) tval() ); */ + // printf ( "Cloth simulation time: %f\n", ( float ) tval() ); return ret; } @@ -541,8 +682,11 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd ) cloth->numsprings = 0; // free BVH collision tree - if ( cloth->tree ) - bvh_free ( ( BVH * ) cloth->tree ); + if ( cloth->bvhtree ) + BLI_bvhtree_free ( cloth->bvhtree ); + + if ( cloth->bvhselftree ) + BLI_bvhtree_free ( cloth->bvhselftree ); // we save our faces for collision objects if ( cloth->mfaces ) @@ -611,8 +755,11 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd ) cloth->numsprings = 0; // free BVH collision tree - if ( cloth->tree ) - bvh_free ( ( BVH * ) cloth->tree ); + if ( cloth->bvhtree ) + BLI_bvhtree_free ( cloth->bvhtree ); + + if ( cloth->bvhselftree ) + BLI_bvhtree_free ( cloth->bvhselftree ); // we save our faces for collision objects if ( cloth->mfaces ) @@ -751,6 +898,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d ClothVertex *verts = NULL; float tnull[3] = {0,0,0}; Cloth *cloth = NULL; + float maxdist = 0; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) @@ -810,6 +958,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d VECCOPY ( verts->xold, verts->x ); VECCOPY ( verts->xconst, verts->x ); VECCOPY ( verts->txold, verts->x ); + VECCOPY ( verts->tx, verts->x ); VecMulf ( verts->v, 0.0f ); verts->impulse_count = 0; @@ -819,8 +968,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d // apply / set vertex groups // has to be happen before springs are build! cloth_apply_vgroup (clmd, dm); - - + if ( !cloth_build_springs ( clmd, dm ) ) { cloth_free_modifier ( ob, clmd ); @@ -845,12 +993,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d if(!first) implicit_set_positions(clmd); - clmd->clothObject->tree = bvh_build_from_cloth ( clmd, clmd->coll_parms->epsilon ); + clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, clmd->coll_parms->epsilon ); + + for(i = 0; i < dm->getNumVerts(dm); i++) + { + maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0)); + } + + clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); return 1; } - static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ) { unsigned int numverts = dm->getNumVerts ( dm ); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index e244ccca306..37784b43cf9 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -41,7 +41,6 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_object.h" -#include "BKE_cloth.h" #include "BKE_modifier.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" @@ -49,6 +48,38 @@ #include "Bullet-C-Api.h" +#include "BLI_kdopbvh.h" +#include "BKE_collision.h" + +#ifdef _WIN32 +static void start ( void ) +{} +static void end ( void ) +{ +} +static double val() +{ + return 0; +} +#else +#include <sys/time.h> +static void mystart ( struct timeval *start, struct timezone *z ) +{ + gettimeofday ( start, z ); +} +static void myend ( struct timeval *end, struct timezone *z ) +{ + gettimeofday ( end,z ); +} +static double myval ( struct timeval *start, struct timeval *end ) +{ + double t1, t2; + t1 = ( double ) start->tv_sec + ( double ) start->tv_usec/ ( 1000*1000 ); + t2 = ( double ) end->tv_sec + ( double ) end->tv_usec/ ( 1000*1000 ); + return t2-t1; +} +#endif + /*********************************** Collision modifier code start ***********************************/ @@ -66,58 +97,80 @@ void collision_move_object ( CollisionModifierData *collmd, float step, float pr VECADDS ( collmd->current_xnew[i].co, collmd->x[i].co, tv, step ); VECSUB ( collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co ); } - bvh_update_from_mvert ( collmd->bvh, collmd->current_x, collmd->numverts, collmd->current_xnew, 1 ); + bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 ); } -/* build bounding volume hierarchy from mverts (see kdop.c for whole BVH code) */ -BVH *bvh_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ) +BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ) { - BVH *bvh=NULL; - - bvh = MEM_callocN ( sizeof ( BVH ), "BVH" ); - if ( bvh == NULL ) - { - printf ( "bvh: Out of memory.\n" ); - return NULL; - } - - // in the moment, return zero if no faces there - if ( !numfaces ) - return NULL; + BVHTree *tree; + float co[12]; + int i; + MFace *tface = mfaces; - bvh->epsilon = epsilon; - bvh->numfaces = numfaces; - bvh->mfaces = mfaces; + tree = BLI_bvhtree_new ( numfaces*2, epsilon, 4, 26 ); - // we have no faces, we save seperate points - if ( !mfaces ) + // fill tree + for ( i = 0; i < numfaces; i++, tface++ ) { - bvh->numfaces = numverts; - } + VECCOPY ( &co[0*3], x[tface->v1].co ); + VECCOPY ( &co[1*3], x[tface->v2].co ); + VECCOPY ( &co[2*3], x[tface->v3].co ); + if ( tface->v4 ) + VECCOPY ( &co[3*3], x[tface->v4].co ); - bvh->numverts = numverts; - bvh->current_x = MEM_dupallocN ( x ); + BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) ); + } - bvh_build ( bvh ); + // balance tree + BLI_bvhtree_balance ( tree ); - return bvh; + return tree; } -void bvh_update_from_mvert ( BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving ) +void bvhtree_update_from_mvert ( BVHTree * bvhtree, MFace *faces, int numfaces, MVert *x, MVert *xnew, int numverts, int moving ) { - if ( !bvh ) - return; + int i; + MFace *mfaces = faces; + float co[12], co_moving[12]; + int ret = 0; - if ( numverts!=bvh->numverts ) + if ( !bvhtree ) return; if ( x ) - memcpy ( bvh->current_xold, x, sizeof ( MVert ) * numverts ); + { + for ( i = 0; i < numfaces; i++, mfaces++ ) + { + VECCOPY ( &co[0*3], x[mfaces->v1].co ); + VECCOPY ( &co[1*3], x[mfaces->v2].co ); + VECCOPY ( &co[2*3], x[mfaces->v3].co ); + if ( mfaces->v4 ) + VECCOPY ( &co[3*3], x[mfaces->v4].co ); + + // copy new locations into array + if ( moving && xnew ) + { + // update moving positions + VECCOPY ( &co_moving[0*3], xnew[mfaces->v1].co ); + VECCOPY ( &co_moving[1*3], xnew[mfaces->v2].co ); + VECCOPY ( &co_moving[2*3], xnew[mfaces->v3].co ); + if ( mfaces->v4 ) + VECCOPY ( &co_moving[3*3], xnew[mfaces->v4].co ); + + ret = BLI_bvhtree_update_node ( bvhtree, i, co, co_moving, ( mfaces->v4 ? 4 : 3 ) ); + } + else + { + ret = BLI_bvhtree_update_node ( bvhtree, i, co, NULL, ( mfaces->v4 ? 4 : 3 ) ); + } - if ( xnew ) - memcpy ( bvh->current_x, xnew, sizeof ( MVert ) * numverts ); + // check if tree is already full + if ( !ret ) + break; + } - bvh_update ( bvh, moving ); + BLI_bvhtree_update_tree ( bvhtree ); + } } /*********************************** @@ -125,47 +178,48 @@ Collision modifier code end ***********************************/ /** - * gsl_poly_solve_cubic - - * - * copied from SOLVE_CUBIC.C --> GSL - */ +* gsl_poly_solve_cubic - +* +* copied from SOLVE_CUBIC.C --> GSL +*/ -/* DG: debug hint! don't forget that all functions were "fabs", "sinf", etc before */ -#define mySWAP(a,b) { float tmp = b ; b = a ; a = tmp ; } +#define mySWAP(a,b) do { double tmp = b ; b = a ; a = tmp ; } while(0) -int gsl_poly_solve_cubic ( float a, float b, float c, float *x0, float *x1, float *x2 ) +int +gsl_poly_solve_cubic (double a, double b, double c, + double *x0, double *x1, double *x2) { - float q = ( a * a - 3 * b ); - float r = ( 2 * a * a * a - 9 * a * b + 27 * c ); + double q = (a * a - 3 * b); + double r = (2 * a * a * a - 9 * a * b + 27 * c); - float Q = q / 9; - float R = r / 54; + double Q = q / 9; + double R = r / 54; - float Q3 = Q * Q * Q; - float R2 = R * R; + double Q3 = Q * Q * Q; + double R2 = R * R; - float CR2 = 729 * r * r; - float CQ3 = 2916 * q * q * q; + double CR2 = 729 * r * r; + double CQ3 = 2916 * q * q * q; - if ( R == 0 && Q == 0 ) + if (R == 0 && Q == 0) { *x0 = - a / 3 ; *x1 = - a / 3 ; *x2 = - a / 3 ; return 3 ; } - else if ( CR2 == CQ3 ) + else if (CR2 == CQ3) { /* this test is actually R2 == Q3, written in a form suitable - for exact computation with integers */ + for exact computation with integers */ - /* Due to finite precision some float roots may be missed, and - considered to be a pair of complex roots z = x +/- epsilon i - close to the real axis. */ + /* Due to finite precision some double roots may be missed, and + considered to be a pair of complex roots z = x +/- epsilon i + close to the real axis. */ - float sqrtQ = sqrt ( Q ); + double sqrtQ = sqrt (Q); - if ( R > 0 ) + if (R > 0) { *x0 = -2 * sqrtQ - a / 3; *x1 = sqrtQ - a / 3; @@ -179,72 +233,88 @@ int gsl_poly_solve_cubic ( float a, float b, float c, float *x0, float *x1, floa } return 3 ; } - else if ( CR2 < CQ3 ) /* equivalent to R2 < Q3 */ + else if (CR2 < CQ3) /* equivalent to R2 < Q3 */ { - float sqrtQ = sqrt ( Q ); - float sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; - float theta = acos ( R / sqrtQ3 ); - float norm = -2 * sqrtQ; - *x0 = norm * cos ( theta / 3 ) - a / 3; - *x1 = norm * cos ( ( theta + 2.0 * M_PI ) / 3 ) - a / 3; - *x2 = norm * cos ( ( theta - 2.0 * M_PI ) / 3 ) - a / 3; + double sqrtQ = sqrt (Q); + double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; + double theta = acos (R / sqrtQ3); + double norm = -2 * sqrtQ; + *x0 = norm * cos (theta / 3) - a / 3; + *x1 = norm * cos ((theta + 2.0 * M_PI) / 3) - a / 3; + *x2 = norm * cos ((theta - 2.0 * M_PI) / 3) - a / 3; /* Sort *x0, *x1, *x2 into increasing order */ - if ( *x0 > *x1 ) - mySWAP ( *x0, *x1 ) ; + if (*x0 > *x1) + mySWAP(*x0, *x1) ; - if ( *x1 > *x2 ) + if (*x1 > *x2) { - mySWAP ( *x1, *x2 ) ; + mySWAP(*x1, *x2) ; - if ( *x0 > *x1 ) - mySWAP ( *x0, *x1 ) ; + if (*x0 > *x1) + mySWAP(*x0, *x1) ; } return 3; } else { - float sgnR = ( R >= 0 ? 1 : -1 ); - float A = -sgnR * pow ( ABS ( R ) + sqrt ( R2 - Q3 ), 1.0/3.0 ); - float B = Q / A ; + double sgnR = (R >= 0 ? 1 : -1); + double A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0/3.0); + double B = Q / A ; *x0 = A + B - a / 3; return 1; } } + /** - * gsl_poly_solve_quadratic - * - * copied from GSL - */ -int gsl_poly_solve_quadratic ( float a, float b, float c, float *x0, float *x1 ) +* gsl_poly_solve_quadratic +* +* copied from GSL +*/ +int +gsl_poly_solve_quadratic (double a, double b, double c, + double *x0, double *x1) { - float disc = b * b - 4 * a * c; + double disc = b * b - 4 * a * c; - if ( disc > 0 ) + if (a == 0) /* Handle linear case */ { - if ( b == 0 ) + if (b == 0) { - float r = ABS ( 0.5 * sqrt ( disc ) / a ); + return 0; + } + else + { + *x0 = -c / b; + return 1; + }; + } + + if (disc > 0) + { + if (b == 0) + { + double r = fabs (0.5 * sqrt (disc) / a); *x0 = -r; *x1 = r; } else { - float sgnb = ( b > 0 ? 1 : -1 ); - float temp = -0.5 * ( b + sgnb * sqrt ( disc ) ); - float r1 = temp / a ; - float r2 = c / temp ; + double sgnb = (b > 0 ? 1 : -1); + double temp = -0.5 * (b + sgnb * sqrt (disc)); + double r1 = temp / a ; + double r2 = c / temp ; - if ( r1 < r2 ) + if (r1 < r2) { *x0 = r1 ; *x1 = r2 ; - } - else + } + else { *x0 = r2 ; *x1 = r1 ; @@ -252,7 +322,7 @@ int gsl_poly_solve_quadratic ( float a, float b, float c, float *x0, float *x1 } return 2; } - else if ( disc == 0 ) + else if (disc == 0) { *x0 = -0.5 * b / a ; *x1 = -0.5 * b / a ; @@ -266,79 +336,88 @@ int gsl_poly_solve_quadratic ( float a, float b, float c, float *x0, float *x1 -/* - * See Bridson et al. "Robust Treatment of Collision, Contact and Friction for Cloth Animation" - * page 4, left column - */ -int cloth_get_collision_time ( float a[3], float b[3], float c[3], float d[3], float e[3], float f[3], float solution[3] ) +/* +* See Bridson et al. "Robust Treatment of Collision, Contact and Friction for Cloth Animation" +* page 4, left column +*/ +int cloth_get_collision_time ( double a[3], double b[3], double c[3], double d[3], double e[3], double f[3], double solution[3] ) { int num_sols = 0; - float g = -a[2] * c[1] * e[0] + a[1] * c[2] * e[0] + - a[2] * c[0] * e[1] - a[0] * c[2] * e[1] - - a[1] * c[0] * e[2] + a[0] * c[1] * e[2]; - - float h = -b[2] * c[1] * e[0] + b[1] * c[2] * e[0] - a[2] * d[1] * e[0] + - a[1] * d[2] * e[0] + b[2] * c[0] * e[1] - b[0] * c[2] * e[1] + - a[2] * d[0] * e[1] - a[0] * d[2] * e[1] - b[1] * c[0] * e[2] + - b[0] * c[1] * e[2] - a[1] * d[0] * e[2] + a[0] * d[1] * e[2] - - a[2] * c[1] * f[0] + a[1] * c[2] * f[0] + a[2] * c[0] * f[1] - - a[0] * c[2] * f[1] - a[1] * c[0] * f[2] + a[0] * c[1] * f[2]; - - float i = -b[2] * d[1] * e[0] + b[1] * d[2] * e[0] + - b[2] * d[0] * e[1] - b[0] * d[2] * e[1] - - b[1] * d[0] * e[2] + b[0] * d[1] * e[2] - - b[2] * c[1] * f[0] + b[1] * c[2] * f[0] - - a[2] * d[1] * f[0] + a[1] * d[2] * f[0] + - b[2] * c[0] * f[1] - b[0] * c[2] * f[1] + - a[2] * d[0] * f[1] - a[0] * d[2] * f[1] - - b[1] * c[0] * f[2] + b[0] * c[1] * f[2] - - a[1] * d[0] * f[2] + a[0] * d[1] * f[2]; - - float j = -b[2] * d[1] * f[0] + b[1] * d[2] * f[0] + - b[2] * d[0] * f[1] - b[0] * d[2] * f[1] - - b[1] * d[0] * f[2] + b[0] * d[1] * f[2]; + // x^0 - checked + double g = a[0] * c[1] * e[2] - a[0] * c[2] * e[1] + + a[1] * c[2] * e[0] - a[1] * c[0] * e[2] + + a[2] * c[0] * e[1] - a[2] * c[1] * e[0]; + + // x^1 + double h = -b[2] * c[1] * e[0] + b[1] * c[2] * e[0] - a[2] * d[1] * e[0] + + a[1] * d[2] * e[0] + b[2] * c[0] * e[1] - b[0] * c[2] * e[1] + + a[2] * d[0] * e[1] - a[0] * d[2] * e[1] - b[1] * c[0] * e[2] + + b[0] * c[1] * e[2] - a[1] * d[0] * e[2] + a[0] * d[1] * e[2] - + a[2] * c[1] * f[0] + a[1] * c[2] * f[0] + a[2] * c[0] * f[1] - + a[0] * c[2] * f[1] - a[1] * c[0] * f[2] + a[0] * c[1] * f[2]; + + // x^2 + double i = -b[2] * d[1] * e[0] + b[1] * d[2] * e[0] + + b[2] * d[0] * e[1] - b[0] * d[2] * e[1] - + b[1] * d[0] * e[2] + b[0] * d[1] * e[2] - + b[2] * c[1] * f[0] + b[1] * c[2] * f[0] - + a[2] * d[1] * f[0] + a[1] * d[2] * f[0] + + b[2] * c[0] * f[1] - b[0] * c[2] * f[1] + + a[2] * d[0] * f[1] - a[0] * d[2] * f[1] - + b[1] * c[0] * f[2] + b[0] * c[1] * f[2] - + a[1] * d[0] * f[2] + a[0] * d[1] * f[2]; + + // x^3 - checked + double j = -b[2] * d[1] * f[0] + b[1] * d[2] * f[0] + + b[2] * d[0] * f[1] - b[0] * d[2] * f[1] - + b[1] * d[0] * f[2] + b[0] * d[1] * f[2]; + + /* + printf("r1: %lf\n", a[0] * c[1] * e[2] - a[0] * c[2] * e[1]); + printf("r2: %lf\n", a[1] * c[2] * e[0] - a[1] * c[0] * e[2]); + printf("r3: %lf\n", a[2] * c[0] * e[1] - a[2] * c[1] * e[0]); + + printf("x1 x: %f, y: %f, z: %f\n", a[0], a[1], a[2]); + printf("x2 x: %f, y: %f, z: %f\n", c[0], c[1], c[2]); + printf("x3 x: %f, y: %f, z: %f\n", e[0], e[1], e[2]); + + printf("v1 x: %f, y: %f, z: %f\n", b[0], b[1], b[2]); + printf("v2 x: %f, y: %f, z: %f\n", d[0], d[1], d[2]); + printf("v3 x: %f, y: %f, z: %f\n", f[0], f[1], f[2]); + + printf("t^3: %lf, t^2: %lf, t^1: %lf, t^0: %lf\n", j, i, h, g); + */ // Solve cubic equation to determine times t1, t2, t3, when the collision will occur. - if ( ABS ( j ) > ALMOST_ZERO ) + if ( ABS ( j ) > DBL_EPSILON ) { i /= j; h /= j; g /= j; - num_sols = gsl_poly_solve_cubic ( i, h, g, &solution[0], &solution[1], &solution[2] ); } - else if ( ABS ( i ) > ALMOST_ZERO ) + else { num_sols = gsl_poly_solve_quadratic ( i, h, g, &solution[0], &solution[1] ); solution[2] = -1.0; } - else if ( ABS ( h ) > ALMOST_ZERO ) - { - solution[0] = -g / h; - solution[1] = solution[2] = -1.0; - num_sols = 1; - } - else if ( ABS ( g ) > ALMOST_ZERO ) - { - solution[0] = 0; - solution[1] = solution[2] = -1.0; - num_sols = 1; - } + + // printf("num_sols: %d, sol1: %lf, sol2: %lf, sol3: %lf\n", num_sols, solution[0], solution[1], solution[2]); // Discard negative solutions - if ( ( num_sols >= 1 ) && ( solution[0] < 0 ) ) + if ( ( num_sols >= 1 ) && ( solution[0] < DBL_EPSILON ) ) { --num_sols; solution[0] = solution[num_sols]; } - if ( ( num_sols >= 2 ) && ( solution[1] < 0 ) ) + if ( ( num_sols >= 2 ) && ( solution[1] < DBL_EPSILON ) ) { --num_sols; solution[1] = solution[num_sols]; } - if ( ( num_sols == 3 ) && ( solution[2] < 0 ) ) + if ( ( num_sols == 3 ) && ( solution[2] < DBL_EPSILON ) ) { --num_sols; } @@ -419,38 +498,37 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float VECADDMUL ( to, v3, w3 ); } -int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd ) + +int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) { int result = 0; - LinkNode *search = NULL; - CollPair *collpair = NULL; Cloth *cloth1; float w1, w2, w3, u1, u2, u3; float v1[3], v2[3], relativeVelocity[3]; float magrelVel; - float epsilon2 = collmd->bvh->epsilon; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); cloth1 = clmd->clothObject; - search = clmd->coll_parms->collision_list; - - while ( search ) + for ( ; collpair != collision_end; collpair++ ) { - collpair = search->link; + // only handle static collisions here + if ( collpair->flag & COLLISION_IN_FUTURE ) + continue; // compute barycentric coordinates for both collision points collision_compute_barycentric ( collpair->pa, - cloth1->verts[collpair->ap1].txold, - cloth1->verts[collpair->ap2].txold, - cloth1->verts[collpair->ap3].txold, - &w1, &w2, &w3 ); + cloth1->verts[collpair->ap1].txold, + cloth1->verts[collpair->ap2].txold, + cloth1->verts[collpair->ap3].txold, + &w1, &w2, &w3 ); // was: txold collision_compute_barycentric ( collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, - &u1, &u2, &u3 ); + collmd->current_x[collpair->bp1].co, + collmd->current_x[collpair->bp2].co, + collmd->current_x[collpair->bp3].co, + &u1, &u2, &u3 ); // Calculate relative "velocity". collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 ); @@ -530,70 +608,50 @@ int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifier result = 1; } - - search = search->next; } - - return result; } -int cloth_collision_response_moving_tris ( ClothModifierData *clmd, ClothModifierData *coll_clmd ) -{ - return 1; -} - - -int cloth_collision_response_moving_edges ( ClothModifierData *clmd, ClothModifierData *coll_clmd ) -{ - return 1; -} - -void cloth_collision_static ( ModifierData *md1, ModifierData *md2, CollisionTree *tree1, CollisionTree *tree2 ) +//Determines collisions on overlap, collisions are writen to collpair[i] and collision+number_collision_found is returned +CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap *overlap, CollPair *collpair ) { ClothModifierData *clmd = ( ClothModifierData * ) md1; CollisionModifierData *collmd = ( CollisionModifierData * ) md2; - CollPair *collpair = NULL; - Cloth *cloth1=NULL; - MFace *face1=NULL, *face2=NULL; - ClothVertex *verts1=NULL; + MFace *face1=NULL, *face2 = NULL; + ClothVertex *verts1 = clmd->clothObject->verts; double distance = 0; - float epsilon = clmd->coll_parms->epsilon; - float epsilon2 = ( ( CollisionModifierData * ) md2 )->bvh->epsilon; - unsigned int i = 0; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + int i; + + face1 = & ( clmd->clothObject->mfaces[overlap->indexA] ); + face2 = & ( collmd->mfaces[overlap->indexB] ); + // check all 4 possible collisions for ( i = 0; i < 4; i++ ) { - collpair = ( CollPair * ) MEM_callocN ( sizeof ( CollPair ), "cloth coll pair" ); - - cloth1 = clmd->clothObject; - - verts1 = cloth1->verts; - - face1 = & ( cloth1->mfaces[tree1->tri_index] ); - face2 = & ( collmd->mfaces[tree2->tri_index] ); - - // check all possible pairs of triangles if ( i == 0 ) { + // fill faceA collpair->ap1 = face1->v1; collpair->ap2 = face1->v2; collpair->ap3 = face1->v3; + // fill faceB collpair->bp1 = face2->v1; collpair->bp2 = face2->v2; collpair->bp3 = face2->v3; - } - - if ( i == 1 ) + else if ( i == 1 ) { if ( face1->v4 ) { - collpair->ap1 = face1->v3; + // fill faceA + collpair->ap1 = face1->v1; collpair->ap2 = face1->v4; - collpair->ap3 = face1->v1; + collpair->ap3 = face1->v3; + // fill faceB collpair->bp1 = face2->v1; collpair->bp2 = face2->v2; collpair->bp3 = face2->v3; @@ -601,386 +659,743 @@ void cloth_collision_static ( ModifierData *md1, ModifierData *md2, CollisionTre else i++; } - if ( i == 2 ) { if ( face2->v4 ) { + // fill faceA collpair->ap1 = face1->v1; collpair->ap2 = face1->v2; collpair->ap3 = face1->v3; - collpair->bp1 = face2->v3; + // fill faceB + collpair->bp1 = face2->v1; collpair->bp2 = face2->v4; - collpair->bp3 = face2->v1; + collpair->bp3 = face2->v3; } else - i+=2; + break; } - - if ( i == 3 ) + else if ( i == 3 ) { - if ( ( face1->v4 ) && ( face2->v4 ) ) + if ( face1->v4 && face2->v4 ) { - collpair->ap1 = face1->v3; + // fill faceA + collpair->ap1 = face1->v1; collpair->ap2 = face1->v4; - collpair->ap3 = face1->v1; + collpair->ap3 = face1->v3; - collpair->bp1 = face2->v3; + // fill faceB + collpair->bp1 = face2->v1; collpair->bp2 = face2->v4; - collpair->bp3 = face2->v1; + collpair->bp3 = face2->v3; } else - i++; + break; } - // calc SIPcode (?) - - if ( i < 4 ) - { - // calc distance + normal #ifdef WITH_BULLET - distance = plNearestPoints ( - verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa,collpair->pb,collpair->vector ); + // calc distance + normal + distance = plNearestPoints ( + verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa,collpair->pb,collpair->vector ); #else - // just be sure that we don't add anything - distance = 2.0 * ( epsilon + epsilon2 + ALMOST_ZERO ); + // just be sure that we don't add anything + distance = 2.0 * ( epsilon1 + epsilon2 + ALMOST_ZERO ); #endif - if ( distance <= ( epsilon + epsilon2 + ALMOST_ZERO ) ) - { - // printf("dist: %f\n", (float)distance); - - // collpair->face1 = tree1->tri_index; - // collpair->face2 = tree2->tri_index; - VECCOPY ( collpair->normal, collpair->vector ); - Normalize ( collpair->normal ); - - collpair->distance = distance; - BLI_linklist_prepend ( &clmd->coll_parms->collision_list, collpair ); + if ( distance <= ( epsilon1 + epsilon2 + ALMOST_ZERO ) ) + { + VECCOPY ( collpair->normal, collpair->vector ); + Normalize ( collpair->normal ); - } - else - { - MEM_freeN ( collpair ); - } + collpair->distance = distance; + collpair->flag = 0; } else { - MEM_freeN ( collpair ); + // check for collision in the future + collpair->flag |= COLLISION_IN_FUTURE; } + collpair++; } + return collpair; } -int cloth_are_edges_adjacent ( ClothModifierData *clmd, ClothModifierData *coll_clmd, EdgeCollPair *edgecollpair ) +int cloth_are_edges_adjacent ( ClothModifierData *clmd, CollisionModifierData *collmd, EdgeCollPair *edgecollpair ) { - Cloth *cloth1 = NULL, *cloth2 = NULL; - ClothVertex *verts1 = NULL, *verts2 = NULL; + Cloth *cloth1 = NULL; + ClothVertex *verts1 = NULL; float temp[3]; + MVert *verts2 = collmd->current_x; // old x cloth1 = clmd->clothObject; - cloth2 = coll_clmd->clothObject; - verts1 = cloth1->verts; - verts2 = cloth2->verts; - VECSUB ( temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p21].xold ); + VECSUB ( temp, verts1[edgecollpair->p11].txold, verts2[edgecollpair->p21].co ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) + return 1; + + VECSUB ( temp, verts1[edgecollpair->p11].txold, verts2[edgecollpair->p22].co ); if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - VECSUB ( temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p22].xold ); + VECSUB ( temp, verts1[edgecollpair->p12].txold, verts2[edgecollpair->p21].co ); if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - VECSUB ( temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p21].xold ); + VECSUB ( temp, verts1[edgecollpair->p12].txold, verts2[edgecollpair->p22].co ); if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - VECSUB ( temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p22].xold ); + VECSUB ( temp, verts1[edgecollpair->p11].txold, verts1[edgecollpair->p12].txold ); if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; + VECSUB ( temp, verts2[edgecollpair->p21].co, verts2[edgecollpair->p22].co ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) + return 1; + + return 0; } -void cloth_collision_moving_edges ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) +int cloth_collision_response_moving( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) { - EdgeCollPair edgecollpair; - Cloth *cloth1=NULL, *cloth2=NULL; - MFace *face1=NULL, *face2=NULL; - ClothVertex *verts1=NULL, *verts2=NULL; - unsigned int i = 0, j = 0, k = 0; - int numsolutions = 0; - float a[3], b[3], c[3], d[3], e[3], f[3], solution[3]; + int result = 0; + Cloth *cloth1; + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; + float magrelVel; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); cloth1 = clmd->clothObject; - cloth2 = coll_clmd->clothObject; - verts1 = cloth1->verts; - verts2 = cloth2->verts; + for ( ; collpair != collision_end; collpair++ ) + { + // compute barycentric coordinates for both collision points + collision_compute_barycentric ( collpair->pa, + cloth1->verts[collpair->ap1].txold, + cloth1->verts[collpair->ap2].txold, + cloth1->verts[collpair->ap3].txold, + &w1, &w2, &w3 ); - face1 = & ( cloth1->mfaces[tree1->tri_index] ); - face2 = & ( cloth2->mfaces[tree2->tri_index] ); + // was: txold + collision_compute_barycentric ( collpair->pb, + collmd->current_x[collpair->bp1].co, + collmd->current_x[collpair->bp2].co, + collmd->current_x[collpair->bp3].co, + &u1, &u2, &u3 ); - for ( i = 0; i < 5; i++ ) - { - if ( i == 0 ) - { - edgecollpair.p11 = face1->v1; - edgecollpair.p12 = face1->v2; - } - else if ( i == 1 ) - { - edgecollpair.p11 = face1->v2; - edgecollpair.p12 = face1->v3; - } - else if ( i == 2 ) + // Calculate relative "velocity". + collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 ); + + collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 ); + + VECSUB ( relativeVelocity, v2, v1 ); + + // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). + magrelVel = INPR ( relativeVelocity, collpair->normal ); + + // printf("magrelVel: %f\n", magrelVel); + + // Calculate masses of points. + // TODO + + // If v_n_mag < 0 the edges are approaching each other. + if ( magrelVel > ALMOST_ZERO ) { - if ( face1->v4 ) + // Calculate Impulse magnitude to stop all motion in normal direction. + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; + float vrel_t_pre[3]; + float temp[3]; + + // calculate tangential velocity + VECCOPY ( temp, collpair->normal ); + VecMulf ( temp, magrelVel ); + VECSUB ( vrel_t_pre, relativeVelocity, temp ); + + // Decrease in magnitude of relative tangential velocity due to coulomb friction + // in original formula "magrelVel" should be the "change of relative velocity in normal direction" + magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) ); + + // Apply friction impulse. + if ( magtangent > ALMOST_ZERO ) { - edgecollpair.p11 = face1->v3; - edgecollpair.p12 = face1->v4; + Normalize ( vrel_t_pre ); + + impulse = 2.0 * magtangent / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, vrel_t_pre, w1 * impulse ); + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, vrel_t_pre, w2 * impulse ); + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, vrel_t_pre, w3 * impulse ); } - else + + // Apply velocity stopping impulse + // I_c = m * v_N / 2.0 + // no 2.0 * magrelVel normally, but looks nicer DG + impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, collpair->normal, w1 * impulse ); + cloth1->verts[collpair->ap1].impulse_count++; + + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, collpair->normal, w2 * impulse ); + cloth1->verts[collpair->ap2].impulse_count++; + + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, collpair->normal, w3 * impulse ); + cloth1->verts[collpair->ap3].impulse_count++; + + // Apply repulse impulse if distance too short + // I_r = -min(dt*kd, m(0,1d/dt - v_n)) + /* + d = clmd->coll_parms->epsilon*8.0/9.0 + epsilon2*8.0/9.0 - collpair->distance; + if ( ( magrelVel < 0.1*d*clmd->sim_parms->stepsPerFrame ) && ( d > ALMOST_ZERO ) ) { - edgecollpair.p11 = face1->v3; - edgecollpair.p12 = face1->v1; - i+=5; // get out of here after this edge pair is handled + repulse = MIN2 ( d*1.0/clmd->sim_parms->stepsPerFrame, 0.1*d*clmd->sim_parms->stepsPerFrame - magrelVel ); + + // stay on the safe side and clamp repulse + if ( impulse > ALMOST_ZERO ) + repulse = MIN2 ( repulse, 5.0*impulse ); + repulse = MAX2 ( impulse, repulse ); + + impulse = repulse / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); // original 2.0 / 0.25 + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, collpair->normal, impulse ); + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, collpair->normal, impulse ); + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, collpair->normal, impulse ); } + */ + result = 1; } - else if ( i == 3 ) + } + return result; +} + +static float projectPointOntoLine(float *p, float *a, float *b) +{ + float ba[3], pa[3]; + VECSUB(ba, b, a); + VECSUB(pa, p, a); + return INPR(pa, ba) / INPR(ba, ba); +} + +static void calculateEENormal(float *np1, float *np2, float *np3, float *np4,float *out_normal) +{ + float line1[33], line2[3]; + float length; + + VECSUB(line1, np2, np1); + VECSUB(line2, np3, np1); + + Crossf(out_normal, line1, line2); + length = Normalize(out_normal); + if (length <= FLT_EPSILON) + { // lines are collinear + VECSUB(out_normal, np2, np1); + Normalize(out_normal); + } +} + +static void findClosestPointsEE(float *x1, float *x2, float *x3, float *x4, float *w1, float *w2) +{ + float temp[3], temp2[3]; + + double a, b, c, e, f; + + VECSUB(temp, x2, x1); + a = INPR(temp, temp); + + VECSUB(temp2, x4, x3); + b = -INPR(temp, temp2); + + c = INPR(temp2, temp2); + + VECSUB(temp2, x3, x1); + e = INPR(temp, temp2); + + VECSUB(temp, x4, x3); + f = -INPR(temp, temp2); + + *w1 = (e * c - b * f) / (a * c - b * b); + *w2 = (f - b * *w1) / c; + +} + +// calculates the distance of 2 edges +float edgedge_distance(float np11[3], float np12[3], float np21[3], float np22[3], float *out_a1, float *out_a2, float *out_normal) +{ + float line1[3], line2[3], cross[3]; + float length; + float temp[3], temp2[3]; + float dist_a1, dist_a2; + + VECSUB(line1, np12, np11); + VECSUB(line2, np22, np21); + + Crossf(cross, line1, line2); + length = INPR(cross, cross); + + if (length < FLT_EPSILON) + { + *out_a2 = projectPointOntoLine(np11, np21, np22); + if ((*out_a2 >= -FLT_EPSILON) && (*out_a2 <= 1.0 + FLT_EPSILON)) { - if ( face1->v4 ) + *out_a1 = 0; + calculateEENormal(np11, np12, np21, np22, out_normal); + VECSUB(temp, np22, np21); + VecMulf(temp, *out_a2); + VECADD(temp2, temp, np21); + VECADD(temp2, temp2, np11); + return INPR(temp2, temp2); + } + + CLAMP(*out_a2, 0.0, 1.0); + if (*out_a2 > .5) + { // == 1.0 + *out_a1 = projectPointOntoLine(np22, np11, np12); + if ((*out_a1 >= -FLT_EPSILON) && (*out_a1 <= 1.0 + FLT_EPSILON)) { - edgecollpair.p11 = face1->v4; - edgecollpair.p12 = face1->v1; + calculateEENormal(np11, np12, np21, np22, out_normal); + + // return (np22 - (np11 + (np12 - np11) * out_a1)).lengthSquared(); + VECSUB(temp, np12, np11); + VecMulf(temp, *out_a1); + VECADD(temp2, temp, np11); + VECSUB(temp2, np22, temp2); + return INPR(temp2, temp2); + } + } + else + { // == 0.0 + *out_a1 = projectPointOntoLine(np21, np11, np12); + if ((*out_a1 >= -FLT_EPSILON) && (*out_a1 <= 1.0 + FLT_EPSILON)) + { + calculateEENormal(np11, np11, np21, np22, out_normal); + + // return (np21 - (np11 + (np12 - np11) * out_a1)).lengthSquared(); + VECSUB(temp, np12, np11); + VecMulf(temp, *out_a1); + VECADD(temp2, temp, np11); + VECSUB(temp2, np21, temp2); + return INPR(temp2, temp2); } - else - continue; - } - else - { - edgecollpair.p11 = face1->v3; - edgecollpair.p12 = face1->v1; } - - for ( j = 0; j < 5; j++ ) + CLAMP(*out_a1, 0.0, 1.0); + calculateEENormal(np11, np12, np21, np22, out_normal); + if(*out_a1 > .5) { - if ( j == 0 ) + if(*out_a2 > .5) { - edgecollpair.p21 = face2->v1; - edgecollpair.p22 = face2->v2; + VECSUB(temp, np12, np22); } - else if ( j == 1 ) + else { - edgecollpair.p21 = face2->v2; - edgecollpair.p22 = face2->v3; + VECSUB(temp, np12, np21); } - else if ( j == 2 ) + } + else + { + if(*out_a2 > .5) { - if ( face2->v4 ) - { - edgecollpair.p21 = face2->v3; - edgecollpair.p22 = face2->v4; - } - else - { - edgecollpair.p21 = face2->v3; - edgecollpair.p22 = face2->v1; - } - } - else if ( j == 3 ) - { - if ( face2->v4 ) - { - edgecollpair.p21 = face2->v4; - edgecollpair.p22 = face2->v1; - } - else - continue; + VECSUB(temp, np11, np22); } else { - edgecollpair.p21 = face2->v3; - edgecollpair.p22 = face2->v1; + VECSUB(temp, np11, np21); } + } + return INPR(temp, temp); + } + else + { + + // If the lines aren't parallel (but coplanar) they have to intersect - if ( !cloth_are_edges_adjacent ( clmd, coll_clmd, &edgecollpair ) ) - { - VECSUB ( a, verts1[edgecollpair.p12].xold, verts1[edgecollpair.p11].xold ); - VECSUB ( b, verts1[edgecollpair.p12].v, verts1[edgecollpair.p11].v ); - VECSUB ( c, verts1[edgecollpair.p21].xold, verts1[edgecollpair.p11].xold ); - VECSUB ( d, verts1[edgecollpair.p21].v, verts1[edgecollpair.p11].v ); - VECSUB ( e, verts2[edgecollpair.p22].xold, verts1[edgecollpair.p11].xold ); - VECSUB ( f, verts2[edgecollpair.p22].v, verts1[edgecollpair.p11].v ); - - numsolutions = cloth_get_collision_time ( a, b, c, d, e, f, solution ); - - for ( k = 0; k < numsolutions; k++ ) - { - if ( ( solution[k] >= 0.0 ) && ( solution[k] <= 1.0 ) ) - { - //float out_collisionTime = solution[k]; - - // TODO: check for collisions + findClosestPointsEE(np11, np12, np21, np22, out_a1, out_a2); - // TODO: put into (edge) collision list + // If both points are on the finite edges, we're done. + if (*out_a1 >= 0.0 && *out_a1 <= 1.0 && *out_a2 >= 0.0 && *out_a2 <= 1.0) + { + float p1[3], p2[3]; + + // p1= np11 + (np12 - np11) * out_a1; + VECSUB(temp, np12, np11); + VecMulf(temp, *out_a1); + VECADD(p1, np11, temp); + + // p2 = np21 + (np22 - np21) * out_a2; + VECSUB(temp, np22, np21); + VecMulf(temp, *out_a2); + VECADD(p2, np21, temp); + + calculateEENormal(np11, np12, np21, np22, out_normal); + VECSUB(temp, p1, p2); + return INPR(temp, temp); + } - // printf("Moving edge found!\n"); - } - } - } + + /* + * Clamp both points to the finite edges. + * The one that moves most during clamping is one part of the solution. + */ + dist_a1 = *out_a1; + CLAMP(dist_a1, 0.0, 1.0); + dist_a2 = *out_a2; + CLAMP(dist_a2, 0.0, 1.0); + + // Now project the "most clamped" point on the other line. + if (dist_a1 > dist_a2) + { + /* keep out_a1 */ + float p1[3]; + + // p1 = np11 + (np12 - np11) * out_a1; + VECSUB(temp, np12, np11); + VecMulf(temp, *out_a1); + VECADD(p1, np11, temp); + + *out_a2 = projectPointOntoLine(p1, np21, np22); + CLAMP(*out_a2, 0.0, 1.0); + + calculateEENormal(np11, np12, np21, np22, out_normal); + + // return (p1 - (np21 + (np22 - np21) * out_a2)).lengthSquared(); + VECSUB(temp, np22, np21); + VecMulf(temp, *out_a2); + VECADD(temp, temp, np21); + VECSUB(temp, p1, temp); + return INPR(temp, temp); + } + else + { + /* keep out_a2 */ + float p2[3]; + + // p2 = np21 + (np22 - np21) * out_a2; + VECSUB(temp, np22, np21); + VecMulf(temp, *out_a2); + VECADD(p2, np21, temp); + + *out_a1 = projectPointOntoLine(p2, np11, np12); + CLAMP(*out_a1, 0.0, 1.0); + + calculateEENormal(np11, np12, np21, np22, out_normal); + + // return ((np11 + (np12 - np11) * out_a1) - p2).lengthSquared(); + VECSUB(temp, np12, np11); + VecMulf(temp, *out_a1); + VECADD(temp, temp, np11); + VECSUB(temp, temp, p2); + return INPR(temp, temp); } } + + printf("Error in edgedge_distance: end of function\n"); + return 0; } -void cloth_collision_moving_tris ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) +int cloth_collision_moving_edges ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair ) { - CollPair collpair; - Cloth *cloth1=NULL, *cloth2=NULL; - MFace *face1=NULL, *face2=NULL; - ClothVertex *verts1=NULL, *verts2=NULL; + EdgeCollPair edgecollpair; + Cloth *cloth1=NULL; + ClothVertex *verts1=NULL; unsigned int i = 0, j = 0, k = 0; int numsolutions = 0; - float a[3], b[3], c[3], d[3], e[3], f[3], solution[3]; + double x1[3], v1[3], x2[3], v2[3], x3[3], v3[3]; + double solution[3]; + MVert *verts2 = collmd->current_x; // old x + MVert *velocity2 = collmd->current_v; // velocity + float mintime = FLT_MAX; + float distance; + float triA[3][3], triB[3][3]; + int result = 0; - for ( i = 0; i < 2; i++ ) + cloth1 = clmd->clothObject; + verts1 = cloth1->verts; + + for(i = 0; i < 9; i++) { - cloth1 = clmd->clothObject; - cloth2 = coll_clmd->clothObject; + // 9 edge - edge possibilities - verts1 = cloth1->verts; - verts2 = cloth2->verts; + if(i == 0) // cloth edge: 1-2; coll edge: 1-2 + { + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap2; - face1 = & ( cloth1->mfaces[tree1->tri_index] ); - face2 = & ( cloth2->mfaces[tree2->tri_index] ); + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp2; + } + else if(i == 1) // cloth edge: 1-2; coll edge: 2-3 + { + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap2; - // check all possible pairs of triangles - if ( i == 0 ) + edgecollpair.p21 = collpair->bp2; + edgecollpair.p22 = collpair->bp3; + } + else if(i == 2) // cloth edge: 1-2; coll edge: 1-3 { - collpair.ap1 = face1->v1; - collpair.ap2 = face1->v2; - collpair.ap3 = face1->v3; - - collpair.pointsb[0] = face2->v1; - collpair.pointsb[1] = face2->v2; - collpair.pointsb[2] = face2->v3; - collpair.pointsb[3] = face2->v4; + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap2; + + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp3; } + else if(i == 3) // cloth edge: 2-3; coll edge: 1-2 + { + edgecollpair.p11 = collpair->ap2; + edgecollpair.p12 = collpair->ap3; - if ( i == 1 ) + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp2; + } + else if(i == 4) // cloth edge: 2-3; coll edge: 2-3 { - if ( face1->v4 ) - { - collpair.ap1 = face1->v3; - collpair.ap2 = face1->v4; - collpair.ap3 = face1->v1; - - collpair.pointsb[0] = face2->v1; - collpair.pointsb[1] = face2->v2; - collpair.pointsb[2] = face2->v3; - collpair.pointsb[3] = face2->v4; - } - else - i++; + edgecollpair.p11 = collpair->ap2; + edgecollpair.p12 = collpair->ap3; + + edgecollpair.p21 = collpair->bp2; + edgecollpair.p22 = collpair->bp3; } + else if(i == 5) // cloth edge: 2-3; coll edge: 1-3 + { + edgecollpair.p11 = collpair->ap2; + edgecollpair.p12 = collpair->ap3; - // calc SIPcode (?) + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp3; + } + else if(i ==6) // cloth edge: 1-3; coll edge: 1-2 + { + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap3; - if ( i < 2 ) + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp2; + } + else if(i ==7) // cloth edge: 1-3; coll edge: 2-3 { - VECSUB ( a, verts1[collpair.ap2].xold, verts1[collpair.ap1].xold ); - VECSUB ( b, verts1[collpair.ap2].v, verts1[collpair.ap1].v ); - VECSUB ( c, verts1[collpair.ap3].xold, verts1[collpair.ap1].xold ); - VECSUB ( d, verts1[collpair.ap3].v, verts1[collpair.ap1].v ); + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap3; - for ( j = 0; j < 4; j++ ) - { - if ( ( j==3 ) && ! ( face2->v4 ) ) - break; + edgecollpair.p21 = collpair->bp2; + edgecollpair.p22 = collpair->bp3; + } + else if(i == 8) // cloth edge: 1-3; coll edge: 1-3 + { + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap3; - VECSUB ( e, verts2[collpair.pointsb[j]].xold, verts1[collpair.ap1].xold ); - VECSUB ( f, verts2[collpair.pointsb[j]].v, verts1[collpair.ap1].v ); + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp3; + } - numsolutions = cloth_get_collision_time ( a, b, c, d, e, f, solution ); + if((edgecollpair.p11 == 3) && (edgecollpair.p12 == 6)) + printf("Ahier!\n"); + if((edgecollpair.p11 == 6) && (edgecollpair.p12 == 3)) + printf("Ahier!\n"); - for ( k = 0; k < numsolutions; k++ ) + if ( !cloth_are_edges_adjacent ( clmd, collmd, &edgecollpair ) ) + { + // printf("Collision between:\n"); + // printf("p11: %d, p12: %d, p21: %d, p22: %d\n", edgecollpair.p11, edgecollpair.p12, edgecollpair.p21, edgecollpair.p22); + + // always put coll points in p21/p22 + VECSUB ( x1, verts1[edgecollpair.p12].txold, verts1[edgecollpair.p11].txold ); + VECSUB ( v1, verts1[edgecollpair.p12].tv, verts1[edgecollpair.p11].tv ); + + VECSUB ( x2, verts2[edgecollpair.p21].co, verts1[edgecollpair.p11].txold ); + VECSUB ( v2, velocity2[edgecollpair.p21].co, verts1[edgecollpair.p11].tv ); + + VECSUB ( x3, verts2[edgecollpair.p22].co, verts1[edgecollpair.p11].txold ); + VECSUB ( v3, velocity2[edgecollpair.p22].co, verts1[edgecollpair.p11].tv ); + + numsolutions = cloth_get_collision_time ( x1, v1, x2, v2, x3, v3, solution ); + + for ( k = 0; k < numsolutions; k++ ) + { + // printf("sol %d: %lf\n", k, solution[k]); + if ( ( solution[k] >= ALMOST_ZERO ) && ( solution[k] <= 1.0 ) && ( solution[k] > ALMOST_ZERO)) { - if ( ( solution[k] >= 0.0 ) && ( solution[k] <= 1.0 ) ) + float a,b; + float out_normal[3]; + float distance; + float impulse = 0; + float I_mag; + float m1, m2; + + // move verts + VECADDS(triA[0], verts1[edgecollpair.p11].txold, verts1[edgecollpair.p11].tv, mintime); + VECADDS(triA[1], verts1[edgecollpair.p12].txold, verts1[edgecollpair.p12].tv, mintime); + + VECADDS(triB[0], collmd->current_x[edgecollpair.p21].co, collmd->current_v[edgecollpair.p21].co, mintime); + VECADDS(triB[1], collmd->current_x[edgecollpair.p22].co, collmd->current_v[edgecollpair.p22].co, mintime); + + // TODO: check for collisions + distance = edgedge_distance(triA[0], triA[1], triB[0], triB[1], &a, &b, out_normal); + + if ((distance <= clmd->coll_parms->epsilon + BLI_bvhtree_getepsilon ( collmd->bvhtree ) + ALMOST_ZERO) && (INPR(out_normal, out_normal) > 0)) { - //float out_collisionTime = solution[k]; + float vrel_1_to_2[3], temp[3], temp2[3], out_normalVelocity; + float desiredVn; - // TODO: check for collisions + VECCOPY(vrel_1_to_2, verts1[edgecollpair.p11].tv); + VecMulf(vrel_1_to_2, 1.0 - a); + VECCOPY(temp, verts1[edgecollpair.p12].tv); + VecMulf(temp, a); - // TODO: put into (point-face) collision list + VECADD(vrel_1_to_2, vrel_1_to_2, temp); + + VECCOPY(temp, verts1[edgecollpair.p21].tv); + VecMulf(temp, 1.0 - b); + VECCOPY(temp2, verts1[edgecollpair.p22].tv); + VecMulf(temp2, b); + VECADD(temp, temp, temp2); + + VECSUB(vrel_1_to_2, vrel_1_to_2, temp); + + out_normalVelocity = INPR(vrel_1_to_2, out_normal); + + if(out_normalVelocity < 0.0) + { + out_normalVelocity*= -1.0; + VecMulf(out_normal, -1.0); + } - // printf("Moving found!\n"); + /* Inelastic repulsion impulse. */ + // Calculate which normal velocity we need. + desiredVn = (out_normalVelocity * (float)solution[k] - (.1 * (clmd->coll_parms->epsilon + BLI_bvhtree_getepsilon ( collmd->bvhtree )) - sqrt(distance)) - ALMOST_ZERO); + + // Now calculate what impulse we need to reach that velocity. + I_mag = (out_normalVelocity - desiredVn) / 2.0; // / (1/m1 + 1/m2); + + // Finally apply that impulse. + impulse = (2.0 * -I_mag) / (a*a + (1.0-a)*(1.0-a) + b*b + (1.0-b)*(1.0-b)); + + VECADDMUL ( verts1[edgecollpair.p11].impulse, out_normal, (1.0-a) * impulse ); + verts1[edgecollpair.p11].impulse_count++; + + VECADDMUL ( verts1[edgecollpair.p12].impulse, out_normal, a * impulse ); + verts1[edgecollpair.p12].impulse_count++; + + // return true; + result = 1; + break; } - } + else + { + // missing from collision.hpp + } + mintime = MIN2(mintime, (float)solution[k]); - // TODO: check borders for collisions + break; + } } - } } + return result; } -void cloth_collision_moving ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) +int cloth_collision_moving_tris ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair ) { - // TODO: check for adjacent - cloth_collision_moving_edges ( clmd, coll_clmd, tree1, tree2 ); + EdgeCollPair edgecollpair; + Cloth *cloth1=NULL; + ClothVertex *verts1=NULL; + unsigned int i = 0, j = 0, k = 0; + int numsolutions = 0; + double x1[3], v1[3], x2[3], v2[3], x3[3], v3[3]; + double solution[3]; + MVert *verts2 = collmd->current_x; // old x + MVert *velocity2 = collmd->current_v; // velocity + float mintime = FLT_MAX; + float distance; + float triA[3][3], triB[3][3]; + int result = 0; - cloth_collision_moving_tris ( clmd, coll_clmd, tree1, tree2 ); - cloth_collision_moving_tris ( coll_clmd, clmd, tree2, tree1 ); -} + cloth1 = clmd->clothObject; + verts1 = cloth1->verts; -void cloth_free_collision_list ( ClothModifierData *clmd ) -{ - // free collision list - if ( clmd->coll_parms->collision_list ) + for(i = 0; i < 9; i++) { - LinkNode *search = clmd->coll_parms->collision_list; - while ( search ) + // 9 edge - edge possibilities + + if(i == 0) { - CollPair *coll_pair = search->link; + edgecollpair.p11 = collpair->ap1; + edgecollpair.p12 = collpair->ap2; - MEM_freeN ( coll_pair ); - search = search->next; + edgecollpair.p21 = collpair->bp1; + edgecollpair.p22 = collpair->bp2; } - BLI_linklist_free ( clmd->coll_parms->collision_list,NULL ); + } + + return result; +} + +int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +{ + int result = 0; + Cloth *cloth1; + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; + float magrelVel; + float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); + + cloth1 = clmd->clothObject; + + for ( ; collpair != collision_end; collpair++ ) + { + // only handle moving collisions here + if (!( collpair->flag & COLLISION_IN_FUTURE )) + continue; - clmd->coll_parms->collision_list = NULL; + cloth_collision_moving_edges ( clmd, collmd, collpair); + // cloth_collision_moving_tris ( clmd, collmd, collpair); } + + return 1; } int cloth_bvh_objcollisions_do ( ClothModifierData * clmd, CollisionModifierData *collmd, float step, float dt ) { Cloth *cloth = clmd->clothObject; - BVH *cloth_bvh= ( BVH * ) cloth->tree; + BVHTree *cloth_bvh= ( BVHTree * ) cloth->bvhtree; long i=0, j = 0, numfaces = 0, numverts = 0; ClothVertex *verts = NULL; + CollPair *collisions = NULL, *collisions_index = NULL; int ret = 0; - unsigned int result = 0; + int result = 0; float tnull[3] = {0,0,0}; + BVHTreeOverlap *overlap = NULL; + numfaces = clmd->clothObject->numfaces; numverts = clmd->clothObject->numverts; verts = cloth->verts; - if ( collmd->bvh ) + if ( collmd->bvhtree ) { /* get pointer to bounding volume hierarchy */ - BVH *coll_bvh = collmd->bvh; + BVHTree *coll_bvh = collmd->bvhtree; /* move object to position (step) in time */ collision_move_object ( collmd, step + dt, step ); /* search for overlapping collision pairs */ - bvh_traverse ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, cloth_bvh->root, coll_bvh->root, step, cloth_collision_static, 0 ); + overlap = BLI_bvhtree_overlap ( cloth_bvh, coll_bvh, &result ); + + collisions = ( CollPair* ) MEM_mallocN ( sizeof ( CollPair ) * result*4, "collision array" ); //*4 since cloth_collision_static can return more than 1 collision + collisions_index = collisions; + + for ( i = 0; i < result; i++ ) + { + collisions_index = cloth_collision ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, overlap+i, collisions_index ); + } + + if ( overlap ) + MEM_freeN ( overlap ); } else { @@ -994,29 +1409,50 @@ int cloth_bvh_objcollisions_do ( ClothModifierData * clmd, CollisionModifierData { result = 0; - if ( collmd->bvh ) - result += cloth_collision_response_static ( clmd, collmd ); + if ( collmd->bvhtree ) + { + result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index ); + + // apply impulses in parallel + if ( result ) + { + for ( i = 0; i < numverts; i++ ) + { + // calculate "velocities" (just xnew = xold + v; no dt in v) + if ( verts[i].impulse_count ) + { + VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); + VECCOPY ( verts[i].impulse, tnull ); + verts[i].impulse_count = 0; + + ret++; + } + } + } + + result += cloth_collision_moving ( clmd, collmd, collisions, collisions_index ); - // apply impulses in parallel - if ( result ) - for ( i = 0; i < numverts; i++ ) + // apply impulses in parallel + if ( result ) { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if ( verts[i].impulse_count ) + for ( i = 0; i < numverts; i++ ) { - VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); - VECCOPY ( verts[i].impulse, tnull ); - verts[i].impulse_count = 0; + // calculate "velocities" (just xnew = xold + v; no dt in v) + if ( verts[i].impulse_count ) + { + VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); + VECCOPY ( verts[i].impulse, tnull ); + verts[i].impulse_count = 0; - ret++; + ret++; + } } } - if ( !result ) - break; + } } - cloth_free_collision_list ( clmd ); + if ( collisions ) MEM_freeN ( collisions ); return ret; } @@ -1028,22 +1464,22 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) CollisionModifierData *collmd=NULL; Cloth *cloth=NULL; Object *coll_ob=NULL; - BVH *cloth_bvh=NULL; - long i=0, j = 0, numfaces = 0, numverts = 0; + BVHTree *cloth_bvh=NULL; + long i=0, j = 0, k = 0, numfaces = 0, numverts = 0; unsigned int result = 0, rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; - int ret = 0; + int ret = 0, ret2 = 0; ClothModifierData *tclmd; int collisions = 0, count = 0; - if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->tree ) ) + if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->bvhtree ) ) { return 0; } cloth = clmd->clothObject; verts = cloth->verts; - cloth_bvh = ( BVH * ) cloth->tree; + cloth_bvh = ( BVHTree * ) cloth->bvhtree; numfaces = clmd->clothObject->numfaces; numverts = clmd->clothObject->numverts; @@ -1052,12 +1488,13 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) //////////////////////////////////////////////////////////// // update cloth bvh - bvh_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) + bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function) + bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) do { result = 0; - clmd->coll_parms->collision_list = NULL; + ret2 = 0; // check all collision objects for ( base = G.scene->base.first; base; base = base->next ) @@ -1086,6 +1523,7 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) continue; ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); + ret2 += ret; } } } @@ -1096,6 +1534,7 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) continue; ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); + ret2 += ret; } } rounds++; @@ -1126,97 +1565,121 @@ int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) //////////////////////////////////////////////////////////// if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { + + MFace *mface = cloth->mfaces; + BVHTreeOverlap *overlap = NULL; + collisions = 1; verts = cloth->verts; // needed for openMP - for ( count = 0; count < clmd->coll_parms->self_loop_count; count++ ) + numfaces = clmd->clothObject->numfaces; + numverts = clmd->clothObject->numverts; + + verts = cloth->verts; + + if ( cloth->bvhselftree ) { - if ( collisions ) + // search for overlapping collision pairs + overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result ); + +// #pragma omp parallel for private(k, i, j) schedule(static) + for ( k = 0; k < result; k++ ) { - collisions = 0; -#pragma omp parallel for private(i,j, collisions) shared(verts, ret) - for ( i = 0; i < cloth->numverts; i++ ) + float temp[3]; + float length = 0; + float mindistance; + + i = overlap[k].indexA; + j = overlap[k].indexB; + + mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); + + if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + { + if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + continue; + } + } + + VECSUB ( temp, verts[i].tx, verts[j].tx ); + + if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; + + // check for adjacent points (i must be smaller j) + if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) + { + continue; + } + + length = Normalize ( temp ); + + if ( length < mindistance ) { - for ( j = i + 1; j < cloth->numverts; j++ ) + float correction = mindistance - length; + + if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, -correction ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + } + else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) { - float temp[3]; - float length = 0; - float mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); - - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) - { - if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - continue; - } - } - - VECSUB ( temp, verts[i].tx, verts[j].tx ); - - if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; - - // check for adjacent points (i must be smaller j) - if ( BLI_edgehash_haskey ( cloth->edgehash, i, j ) ) - { - continue; - } - - length = Normalize ( temp ); - - if ( length < mindistance ) - { - float correction = mindistance - length; - - if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, -correction ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - } - else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) - { - VecMulf ( temp, correction ); - VECADD ( verts[i].tx, verts[i].tx, temp ); - } - else - { - VecMulf ( temp, -correction*0.5 ); - VECADD ( verts[j].tx, verts[j].tx, temp ); - - VECSUB ( verts[i].tx, verts[i].tx, temp ); - } - - collisions = 1; - - if ( !ret ) - { -#pragma omp critical - { - ret = 1; - } - } - } + VecMulf ( temp, correction ); + VECADD ( verts[i].tx, verts[i].tx, temp ); + } + else + { + VecMulf ( temp, -correction*0.5 ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + + VECSUB ( verts[i].tx, verts[i].tx, temp ); } + ret = 1; + ret2 += ret; + } + else + { + // check for approximated time collisions } } + + if ( overlap ) + MEM_freeN ( overlap ); + } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// // SELFCOLLISIONS: update velocities //////////////////////////////////////////////////////////// - if ( ret ) + if ( ret2 ) { for ( i = 0; i < cloth->numverts; i++ ) { - if ( ! ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) + if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) + { VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); + } } } //////////////////////////////////////////////////////////// } } - while ( result && ( clmd->coll_parms->loop_count>rounds ) ); + while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) ); return MIN2 ( ret, 1 ); } + + +/* +if ( verts[i].impulse_count ) +{ + VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); + VECCOPY ( verts[i].impulse, tnull ); + verts[i].impulse_count = 0; + + ret++; +} +*/
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/kdop.c b/source/blender/blenkernel/intern/kdop.c deleted file mode 100644 index 3189fe960ad..00000000000 --- a/source/blender/blenkernel/intern/kdop.c +++ /dev/null @@ -1,860 +0,0 @@ -/* kdop.c -* -* -* ***** BEGIN GPL LICENSE BLOCK ***** -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* The Original Code is Copyright (C) Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): none yet. -* -* ***** END GPL LICENSE BLOCK ***** -*/ - -#include "MEM_guardedalloc.h" - -#include "BKE_cloth.h" - -#include "DNA_cloth_types.h" -#include "DNA_mesh_types.h" -#include "DNA_scene_types.h" - -#include "BKE_deform.h" -#include "BKE_DerivedMesh.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_effect.h" -#include "BKE_global.h" -#include "BKE_object.h" -#include "BKE_modifier.h" -#include "BKE_utildefines.h" - -#ifdef _OPENMP -#include <omp.h> -#endif - - -//////////////////////////////////////////////////////////////////////// -// Additional fastened appending function -// It uses the link to the last inserted node as start value -// for searching the end of the list -// NEW: in compare to the original function, this one returns -// the reference to the last inserted node -//////////////////////////////////////////////////////////////////////// -LinkNode *BLI_linklist_append_fast(LinkNode **listp, void *ptr) { - LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink"); - LinkNode *node = *listp; - - nlink->link = ptr; - nlink->next = NULL; - - if(node == NULL){ - *listp = nlink; - } else { - while(node->next != NULL){ - node = node->next; - } - node->next = nlink; - } - return nlink; -} - - - -//////////////////////////////////////////////////////////////////////// -// Bounding Volume Hierarchy Definition -// -// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below -// Notes: You have to choose the type at compile time ITM -// Notes: You can choose the tree type --> binary, quad, octree, choose below -//////////////////////////////////////////////////////////////////////// - -static float KDOP_AXES[13][3] = -{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0}, -{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0}, -{0, 1.0, -1.0} -}; - -///////////// choose bounding volume here! ///////////// - -#define KDOP_26 - - - -#ifdef KDOP_26 -#define KDOP_END 13 -#define KDOP_START 0 -#endif - -#ifdef KDOP_18 -#define KDOP_END 13 -#define KDOP_START 7 -#endif - -#ifdef KDOP_14 -#define KDOP_END 7 -#define KDOP_START 0 -#endif - -// this is basicly some AABB -#ifdef KDOP_8 -#define KDOP_END 4 -#define KDOP_START 0 -#endif - -// this is basicly some OBB -#ifdef KDOP_6 -#define KDOP_END 3 -#define KDOP_START 0 -#endif - -////////////////////////////////////////////////////////////////////////////////////////////////////// -// Introsort -// with permission deriven from the following Java code: -// http://ralphunden.net/content/tutorials/a-guide-to-introsort/ -// and he derived it from the SUN STL -////////////////////////////////////////////////////////////////////////////////////////////////////// -static int size_threshold = 16; -/* -* Common methods for all algorithms -*/ -DO_INLINE void bvh_exchange(CollisionTree **a, int i, int j) -{ - CollisionTree *t=a[i]; - a[i]=a[j]; - a[j]=t; -} -DO_INLINE int floor_lg(int a) -{ - return (int)(floor(log(a)/log(2))); -} - -/* -* Insertion sort algorithm -*/ -void bvh_insertionsort(CollisionTree **a, int lo, int hi, int axis) -{ - int i,j; - CollisionTree *t; - for (i=lo; i < hi; i++) - { - j=i; - t = a[i]; - while((j!=lo) && (t->bv[axis] < (a[j-1])->bv[axis])) - { - a[j] = a[j-1]; - j--; - } - a[j] = t; - } -} - -static int bvh_partition(CollisionTree **a, int lo, int hi, CollisionTree * x, int axis) -{ - int i=lo, j=hi; - while (1) - { - while ((a[i])->bv[axis] < x->bv[axis]) i++; - j=j-1; - while (x->bv[axis] < (a[j])->bv[axis]) j=j-1; - if(!(i < j)) - return i; - bvh_exchange(a, i,j); - i++; - } -} - -/* -* Heapsort algorithm -*/ -static void bvh_downheap(CollisionTree **a, int i, int n, int lo, int axis) -{ - CollisionTree * d = a[lo+i-1]; - int child; - while (i<=n/2) - { - child = 2*i; - if ((child < n) && ((a[lo+child-1])->bv[axis] < (a[lo+child])->bv[axis])) - { - child++; - } - if (!(d->bv[axis] < (a[lo+child-1])->bv[axis])) break; - a[lo+i-1] = a[lo+child-1]; - i = child; - } - a[lo+i-1] = d; -} - -static void bvh_heapsort(CollisionTree **a, int lo, int hi, int axis) -{ - int n = hi-lo, i; - for (i=n/2; i>=1; i=i-1) - { - bvh_downheap(a, i,n,lo, axis); - } - for (i=n; i>1; i=i-1) - { - bvh_exchange(a, lo,lo+i-1); - bvh_downheap(a, 1,i-1,lo, axis); - } -} - -static CollisionTree *bvh_medianof3(CollisionTree **a, int lo, int mid, int hi, int axis) // returns Sortable -{ - if ((a[mid])->bv[axis] < (a[lo])->bv[axis]) - { - if ((a[hi])->bv[axis] < (a[mid])->bv[axis]) - return a[mid]; - else - { - if ((a[hi])->bv[axis] < (a[lo])->bv[axis]) - return a[hi]; - else - return a[lo]; - } - } - else - { - if ((a[hi])->bv[axis] < (a[mid])->bv[axis]) - { - if ((a[hi])->bv[axis] < (a[lo])->bv[axis]) - return a[lo]; - else - return a[hi]; - } - else - return a[mid]; - } -} -/* -* Quicksort algorithm modified for Introsort -*/ -void bvh_introsort_loop (CollisionTree **a, int lo, int hi, int depth_limit, int axis) -{ - int p; - - while (hi-lo > size_threshold) - { - if (depth_limit == 0) - { - bvh_heapsort(a, lo, hi, axis); - return; - } - depth_limit=depth_limit-1; - p=bvh_partition(a, lo, hi, bvh_medianof3(a, lo, lo+((hi-lo)/2)+1, hi-1, axis), axis); - bvh_introsort_loop(a, p, hi, depth_limit, axis); - hi=p; - } -} - -DO_INLINE void bvh_sort(CollisionTree **a0, int begin, int end, int axis) -{ - if (begin < end) - { - CollisionTree **a=a0; - bvh_introsort_loop(a, begin, end, 2*floor_lg(end-begin), axis); - bvh_insertionsort(a, begin, end, axis); - } -} -DO_INLINE void bvh_sort_along_axis(CollisionTree **face_list, int start, int end, int axis) -{ - bvh_sort(face_list, start, end, axis); -} -//////////////////////////////////////////////////////////////////////////////////////////////// -void bvh_free(BVH * bvh) -{ - LinkNode *search = NULL; - CollisionTree *tree = NULL; - - if (bvh) - { - - search = bvh->tree; - - while(search) - { - LinkNode *next= search->next; - tree = search->link; - - MEM_freeN(tree); - - search = next; - } - - BLI_linklist_free(bvh->tree,NULL); - bvh->tree = NULL; - - if(bvh->current_x) - MEM_freeN(bvh->current_x); - if(bvh->current_xold) - MEM_freeN(bvh->current_xold); - - MEM_freeN(bvh); - bvh = NULL; - } -} - -// only supports x,y,z axis in the moment -// but we should use a plain and simple function here for speed sake -DO_INLINE int bvh_largest_axis(float *bv) -{ - float middle_point[3]; - - middle_point[0] = (bv[1]) - (bv[0]); // x axis - middle_point[1] = (bv[3]) - (bv[2]); // y axis - middle_point[2] = (bv[5]) - (bv[4]); // z axis - if (middle_point[0] > middle_point[1]) - { - if (middle_point[0] > middle_point[2]) - return 1; // max x axis - else - return 5; // max z axis - } - else - { - if (middle_point[1] > middle_point[2]) - return 3; // max y axis - else - return 5; // max z axis - } -} - -// depends on the fact that the BVH's for each face is already build -DO_INLINE void bvh_calc_DOP_hull_from_faces(BVH * bvh, CollisionTree **tri, int numfaces, float *bv) -{ - float newmin,newmax; - int i, j; - - if(numfaces >0) - { - // for all Axes. - for (i = KDOP_START; i < KDOP_END; i++) - { - bv[(2 * i)] = (tri [0])->bv[(2 * i)]; - bv[(2 * i) + 1] = (tri [0])->bv[(2 * i) + 1]; - } - } - - for (j = 0; j < numfaces; j++) - { - // for all Axes. - for (i = KDOP_START; i < KDOP_END; i++) - { - newmin = (tri [j])->bv[(2 * i)]; - if ((newmin < bv[(2 * i)])) - { - bv[(2 * i)] = newmin; - } - - newmax = (tri [j])->bv[(2 * i) + 1]; - if ((newmax > bv[(2 * i) + 1])) - { - bv[(2 * i) + 1] = newmax; - } - } - } -} - -DO_INLINE void bvh_calc_DOP_hull_static(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree) -{ - MFace *tempMFace = bvh->mfaces; - float *tempBV = bv; - float newminmax; - int i, j, k; - - for (j = 0; j < numfaces; j++) - { - tempMFace = bvh->mfaces + (tri [j])->tri_index; - // 3 or 4 vertices per face. - for (k = 0; k < 4; k++) - { - int temp = 0; - // If this is a triangle. - if (k == 3 && !tempMFace->v4) - continue; - // TODO: other name for "temp" this gets all vertices of a face - if (k == 0) - temp = tempMFace->v1; - else if (k == 1) - temp = tempMFace->v2; - else if (k == 2) - temp = tempMFace->v3; - else if (k == 3) - temp = tempMFace->v4; - // for all Axes. - for (i = KDOP_START; i < KDOP_END; i++) - { - newminmax = INPR(bvh->current_xold[temp].co, KDOP_AXES[i]); - if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0)) - tempBV[(2 * i)] = newminmax; - if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0)) - tempBV[(2 * i) + 1] = newminmax; - } - } - - /* calculate normal of this face */ - /* (code copied from cdderivedmesh.c) */ - /* - if(tempMFace->v4) - CalcNormFloat4(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co, - bvh->current_xold[tempMFace->v3].co, bvh->current_xold[tempMFace->v4].co, tree->normal); - else - CalcNormFloat(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co, - bvh->current_xold[tempMFace->v3].co, tree->normal); - - tree->alpha = 0; - */ - } -} - -DO_INLINE void bvh_calc_DOP_hull_moving(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree) -{ - MFace *tempMFace = bvh->mfaces; - float *tempBV = bv; - float newminmax; - int i, j, k; - - /* TODO: calculate normals */ - - for (j = 0; j < numfaces; j++) - { - tempMFace = bvh->mfaces + (tri [j])->tri_index; - // 3 or 4 vertices per face. - for (k = 0; k < 4; k++) - { - int temp = 0; - // If this is a triangle. - if (k == 3 && !tempMFace->v4) - continue; - // TODO: other name for "temp" this gets all vertices of a face - if (k == 0) - temp = tempMFace->v1; - else if (k == 1) - temp = tempMFace->v2; - else if (k == 2) - temp = tempMFace->v3; - else if (k == 3) - temp = tempMFace->v4; - // for all Axes. - for (i = KDOP_START; i < KDOP_END; i++) - { - newminmax = INPR(bvh->current_xold[temp].co, KDOP_AXES[i]); - if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0)) - tempBV[(2 * i)] = newminmax; - if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0)) - tempBV[(2 * i) + 1] = newminmax; - - newminmax = INPR(bvh->current_x[temp].co, KDOP_AXES[i]); - if ((newminmax < tempBV[(2 * i)]) || (k == 0 && j == 0)) - tempBV[(2 * i)] = newminmax; - if ((newminmax > tempBV[(2 * i) + 1])|| (k == 0 && j == 0)) - tempBV[(2 * i) + 1] = newminmax; - } - } - } -} - -static void bvh_div_env_node(BVH *bvh, CollisionTree *tree, CollisionTree **face_list, unsigned int start, unsigned int end, int lastaxis, LinkNode *nlink) -{ - int i = 0; - CollisionTree *newtree = NULL; - int laxis = 0, max_nodes=4; - unsigned int tstart, tend; - LinkNode *nlink1 = nlink; - LinkNode *tnlink; - tree->traversed = 0; - // Determine which axis to split along - laxis = bvh_largest_axis(tree->bv); - - // Sort along longest axis - if(laxis!=lastaxis) - bvh_sort_along_axis(face_list, start, end, laxis); - - // maximum is 4 since we have a quad tree - max_nodes = MIN2((end-start + 1 ),4); - - for (i = 0; i < max_nodes; i++) - { - tree->count_nodes++; - - if(end-start+1 > 4) - { - int quarter = ((float)((float)(end - start + 1) / 4.0f)); - tstart = start + i * quarter; - tend = tstart + quarter - 1; - - // be sure that we get all faces - if(i==3) - { - tend = end; - } - } - else - { - tend = tstart = start + i; - } - - // Build tree until 4 node left. - if ((tend-tstart + 1 ) > 1) - { - newtree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree"); - tnlink = BLI_linklist_append_fast(&nlink1->next, newtree); - - newtree->nodes[0] = newtree->nodes[1] = newtree->nodes[2] = newtree->nodes[3] = NULL; - newtree->count_nodes = 0; - newtree->parent = tree; - newtree->isleaf = 0; - - tree->nodes[i] = newtree; - - nlink1 = tnlink; - - bvh_calc_DOP_hull_from_faces(bvh, &face_list[tstart], tend-tstart + 1, tree->nodes[i]->bv); - - bvh_div_env_node(bvh, tree->nodes[i], face_list, tstart, tend, laxis, nlink1); - } - else // ok, we have 1 left for this node - { - CollisionTree *tnode = face_list[tstart]; - tree->nodes[i] = tnode; - tree->nodes[i]->parent = tree; - } - } - return; -} - -/* function cannot be directly called - needs alloced bvh */ -void bvh_build (BVH *bvh) -{ - unsigned int i = 0, j = 0, k = 0; - CollisionTree **face_list=NULL; - CollisionTree *tree=NULL; - LinkNode *nlink = NULL; - - bvh->flags = 0; - bvh->leaf_tree = NULL; - bvh->leaf_root = NULL; - bvh->tree = NULL; - - if(!bvh->current_x) - { - bvh_free(bvh); - return; - } - - bvh->current_xold = MEM_dupallocN(bvh->current_x); - - tree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree"); - - if (tree == NULL) - { - printf("bvh_build: Out of memory for nodes.\n"); - bvh_free(bvh); - return; - } - - BLI_linklist_append(&bvh->tree, tree); - - nlink = bvh->tree; - - bvh->root = bvh->tree->link; - bvh->root->isleaf = 0; - bvh->root->parent = NULL; - bvh->root->nodes[0] = bvh->root->nodes[1] = bvh->root->nodes[1] = bvh->root->nodes[3] = NULL; - - if(bvh->numfaces<=1) - { - bvh->root->tri_index = 0; // Why that? --> only one face there - bvh->root->isleaf = 1; - bvh->root->traversed = 0; - bvh->root->count_nodes = 0; - bvh->leaf_root = bvh->root; - bvh->leaf_tree = bvh->root; - bvh->root->nextLeaf = NULL; - bvh->root->prevLeaf = NULL; - } - else - { - // create face boxes - face_list = MEM_callocN (bvh->numfaces * sizeof (CollisionTree *), "CollisionTree"); - if (face_list == NULL) - { - printf("bvh_build: Out of memory for face_list.\n"); - bvh_free(bvh); - return; - } - - // create face boxes - for(i = 0, k = 0; i < bvh->numfaces; i++) - { - LinkNode *tnlink; - - tree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree"); - // TODO: check succesfull alloc - - tnlink = BLI_linklist_append_fast(&nlink->next, tree); - - face_list[i] = tree; - tree->tri_index = i; - tree->isleaf = 1; - tree->nextLeaf = NULL; - tree->prevLeaf = bvh->leaf_tree; - tree->parent = NULL; - tree->count_nodes = 0; - - if(i==0) - { - bvh->leaf_tree = bvh->leaf_root = tree; - } - else - { - bvh->leaf_tree->nextLeaf = tree; - bvh->leaf_tree = bvh->leaf_tree->nextLeaf; - } - - tree->nodes[0] = tree->nodes[1] = tree->nodes[2] = tree->nodes[3] = NULL; - - bvh_calc_DOP_hull_static(bvh, &face_list[i], 1, tree->bv, tree); - - // inflate the bv with some epsilon - for (j = KDOP_START; j < KDOP_END; j++) - { - tree->bv[(2 * j)] -= bvh->epsilon; // minimum - tree->bv[(2 * j) + 1] += bvh->epsilon; // maximum - } - - nlink = tnlink; - } - - // build root bvh - bvh_calc_DOP_hull_from_faces(bvh, face_list, bvh->numfaces, bvh->root->bv); - - // This is the traversal function. - bvh_div_env_node(bvh, bvh->root, face_list, 0, bvh->numfaces-1, 0, nlink); - if (face_list) - MEM_freeN(face_list); - - } - -} - -// bvh_overlap - is it possbile for 2 bv's to collide ? -DO_INLINE int bvh_overlap(float *bv1, float *bv2) -{ - int i = 0; - for (i = KDOP_START; i < KDOP_END; i++) - { - // Minimum test. - if (bv1[(2 * i)] > bv2[(2 * i) + 1]) - { - return 0; - } - // Maxiumum test. - if (bv2[(2 * i)] > bv1[(2 * i) + 1]) - { - return 0; - } - } - - return 1; -} - -// bvh_overlap_self - is it possbile for 2 bv's to selfcollide ? -DO_INLINE int bvh_overlap_self(CollisionTree * tree1, CollisionTree * tree2) -{ - // printf("overlap: %f, q: %f\n", (saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha), saacos(INPR(tree1->normal, tree2->normal))); - - if((saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha) > M_PI) - { - return 1; - } - else - return 0; -} - -/** - * bvh_traverse - traverse two bvh trees looking for potential collisions. - * - * max collisions are n*n collisions --> every triangle collide with - * every other triangle that doesn't require any realloc, but uses - * much memory - */ -int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision) -{ - int i = 0, ret=0, overlap = 0; - - /* - // Shouldn't be possible - if(!tree1 || !tree2) - { - printf("Error: no tree there\n"); - return 0; -} - */ - - if(selfcollision) - overlap = bvh_overlap_self(tree1, tree2); - else - overlap = bvh_overlap(tree1->bv, tree2->bv); - - if (overlap) - { - // Check if this node in the first tree is a leaf - if (tree1->isleaf) - { - // Check if this node in the second tree a leaf - if (tree2->isleaf) - { - // Provide the collision response. - - if(collision_response) - collision_response (md1, md2, tree1, tree2); - return 1; - } - else - { - // Process the quad tree. - for (i = 0; i < 4; i++) - { - // Only traverse nodes that exist. - if (tree2->nodes[i] && bvh_traverse (md1, md2, tree1, tree2->nodes[i], step, collision_response, selfcollision)) - ret = 1; - } - } - } - else - { - // Process the quad tree. - for (i = 0; i < 4; i++) - { - // Only traverse nodes that exist. - if (tree1->nodes [i] && bvh_traverse (md1, md2, tree1->nodes[i], tree2, step, collision_response, selfcollision)) - ret = 1; - } - } - } - - return ret; -} -// bottom up update of bvh tree: -// join the 4 children here -void bvh_join(CollisionTree *tree) -{ - int i = 0, j = 0; - float max = 0; - - if (!tree) - return; - - for (i = 0; i < 4; i++) - { - if (tree->nodes[i]) - { - for (j = KDOP_START; j < KDOP_END; j++) - { - // update minimum - if ((tree->nodes[i]->bv[(2 * j)] < tree->bv[(2 * j)]) || (i == 0)) - { - tree->bv[(2 * j)] = tree->nodes[i]->bv[(2 * j)]; - } - // update maximum - if ((tree->nodes[i]->bv[(2 * j) + 1] > tree->bv[(2 * j) + 1])|| (i == 0)) - { - tree->bv[(2 * j) + 1] = tree->nodes[i]->bv[(2 * j) + 1]; - } - } - - /* for selfcollisions */ - /* - if(!i) - { - tree->alpha = tree->nodes[i]->alpha; - VECCOPY(tree->normal, tree->nodes[i]->normal); - } - else - { - tree->alpha += saacos(INPR(tree->normal, tree->nodes[i]->normal)) / 2.0; - VECADD(tree->normal, tree->normal, tree->nodes[i]->normal); - VecMulf(tree->normal, 0.5); - max = MAX2(max, tree->nodes[i]->alpha); - } - */ - - } - else - break; - } - - tree->alpha += max; -} - -// update static bvh -/* you have to update the bvh position before calling this function */ -void bvh_update(BVH * bvh, int moving) -{ - CollisionTree *leaf, *parent; - int traversecheck = 1; // if this is zero we don't go further - unsigned int j = 0; - - for (leaf = bvh->leaf_root; leaf; leaf = leaf->nextLeaf) - { - traversecheck = 1; - if ((leaf->parent) && (leaf->parent->traversed == leaf->parent->count_nodes)) - { - leaf->parent->traversed = 0; - } - if(!moving) - bvh_calc_DOP_hull_static(bvh, &leaf, 1, leaf->bv, leaf); - else - bvh_calc_DOP_hull_moving(bvh, &leaf, 1, leaf->bv, leaf); - - // inflate the bv with some epsilon - for (j = KDOP_START; j < KDOP_END; j++) - { - leaf->bv[(2 * j)] -= bvh->epsilon; // minimum - leaf->bv[(2 * j) + 1] += bvh->epsilon; // maximum - } - - for (parent = leaf->parent; parent; parent = parent->parent) - { - if (traversecheck) - { - parent->traversed++; // we tried to go up in hierarchy - if (parent->traversed < parent->count_nodes) - { - traversecheck = 0; - - if (parent->parent) - { - if (parent->parent->traversed == parent->parent->count_nodes) - { - parent->parent->traversed = 0; - } - } - break; // we do not need to check further - } - else - { - bvh_join(parent); - } - } - - } - } -} - diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index f9f17e7762d..067108ac8cb 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -58,6 +58,7 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_sph_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" @@ -90,6 +91,7 @@ #include "BKE_object.h" #include "BKE_mesh.h" #include "BKE_softbody.h" +#include "BKE_sph.h" #include "BKE_cloth.h" #include "BKE_material.h" #include "BKE_particle.h" @@ -5180,6 +5182,89 @@ static void clothModifier_freeData(ModifierData *md) } } +/* Smooth Particly Hydrodynamics */ + +static void sphModifier_initData(ModifierData *md) +{ + SphModifierData *sphmd = (SphModifierData*) md; + + sphmd->sim_parms = MEM_callocN(sizeof(SphSimSettings), "SPH sim parms"); + sphmd->coll_parms = MEM_callocN(sizeof(SphCollSettings), "SPH coll parms"); + + /* check for alloc failing */ + if(!sphmd->sim_parms || !sphmd->coll_parms) + return; + + sph_init(sphmd); +} + +static DerivedMesh *sphModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) +{ + SphModifierData *sphmd = (SphModifierData*) md; + DerivedMesh *result=NULL; + + /* check for alloc failing */ + if(!sphmd->sim_parms || !sphmd->coll_parms) + return derivedData; + + result = sphModifier_do(sphmd, ob, derivedData, useRenderParams, isFinalCalc); + + if(result) + { + CDDM_calc_normals(result); + return result; + } + + return derivedData; +} + +static void sphModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) +{ + SphModifierData *sphmd = (SphModifierData*) md; + + Base *base; + +} + +CustomDataMask sphModifier_requiredDataMask(ModifierData *md) +{ + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static void sphModifier_copyData(ModifierData *md, ModifierData *target) +{ + +} + + +static int sphModifier_dependsOnTime(ModifierData *md) +{ + return 1; +} + +static void sphModifier_freeData(ModifierData *md) +{ + SphModifierData *sphmd = (SphModifierData*) md; + + if (sphmd) + { + sph_free_modifier(sphmd); + + if(sphmd->sim_parms) + MEM_freeN(sphmd->sim_parms); + if(sphmd->coll_parms) + MEM_freeN(sphmd->coll_parms); + } +} + /* Collision */ static void collisionModifier_initData(ModifierData *md) @@ -5193,7 +5278,7 @@ static void collisionModifier_initData(ModifierData *md) collmd->current_v = NULL; collmd->time = -1; collmd->numverts = 0; - collmd->bvh = NULL; + collmd->bvhtree = NULL; } static void collisionModifier_freeData(ModifierData *md) @@ -5202,8 +5287,8 @@ static void collisionModifier_freeData(ModifierData *md) if (collmd) { - if(collmd->bvh) - bvh_free(collmd->bvh); + if(collmd->bvhtree) + BLI_bvhtree_free(collmd->bvhtree); if(collmd->x) MEM_freeN(collmd->x); if(collmd->xnew) @@ -5214,7 +5299,6 @@ static void collisionModifier_freeData(ModifierData *md) MEM_freeN(collmd->current_xnew); if(collmd->current_v) MEM_freeN(collmd->current_v); - if(collmd->mfaces) MEM_freeN(collmd->mfaces); @@ -5225,7 +5309,7 @@ static void collisionModifier_freeData(ModifierData *md) collmd->current_v = NULL; collmd->time = -1; collmd->numverts = 0; - collmd->bvh = NULL; + collmd->bvhtree = NULL; collmd->mfaces = NULL; } } @@ -5293,9 +5377,8 @@ static void collisionModifier_deformVerts( collmd->mfaces = dm->dupFaceArray(dm); collmd->numfaces = dm->getNumFaces(dm); - // TODO: epsilon // create bounding box hierarchy - collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft); + collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft); collmd->time = current_time; } @@ -5318,25 +5401,25 @@ static void collisionModifier_deformVerts( memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert)); /* check if GUI setting has changed for bvh */ - if(collmd->bvh) + if(collmd->bvhtree) { - if(ob->pd->pdef_sboft != collmd->bvh->epsilon) + if(ob->pd->pdef_sboft != BLI_bvhtree_getepsilon(collmd->bvhtree)) { - bvh_free(collmd->bvh); - collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); + BLI_bvhtree_free(collmd->bvhtree); + collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); } } - /* happens on file load (ONLY when i decomment changes in readfile.c */ - if(!collmd->bvh) + /* happens on file load (ONLY when i decomment changes in readfile.c) */ + if(!collmd->bvhtree) { - collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); + collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); } else { // recalc static bounding boxes - bvh_update_from_mvert(collmd->bvh, collmd->current_x, numverts, NULL, 0); + bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 ); } collmd->time = current_time; @@ -7137,6 +7220,18 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->requiredDataMask = bevelModifier_requiredDataMask; mti->applyModifier = bevelModifier_applyModifier; mti->applyModifierEM = bevelModifier_applyModifierEM; + + mti = INIT_TYPE(Sph); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_UsesPointCache; + mti->initData = sphModifier_initData; + mti->copyData = sphModifier_copyData; + mti->requiredDataMask = sphModifier_requiredDataMask; + mti->applyModifier = sphModifier_applyModifier; + mti->dependsOnTime = sphModifier_dependsOnTime; + mti->freeData = sphModifier_freeData; + mti->updateDepgraph = sphModifier_updateDepgraph; mti = INIT_TYPE(Displace); mti->type = eModifierTypeType_OnlyDeform; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5112fb08fe6..257e3317215 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -46,6 +46,7 @@ #include "DNA_curve_types.h" #include "DNA_group_types.h" #include "DNA_scene_types.h" +#include "DNA_sph_types.h" #include "DNA_texture_types.h" #include "BLI_rand.h" @@ -74,6 +75,7 @@ #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_scene.h" +#include "BKE_sph.h" #include "BSE_headerbuttons.h" @@ -4636,6 +4638,50 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", psys->totpart,activeParts,fileParts,readMask); elbeemDebugOut(debugStrBuffer); } // fluid sim particles done + else + { + // check for sph modifier + SphModifierData *sphmd = (SphModifierData *)modifiers_findByType(ob, eModifierType_Sph); + + // check for an sph object + if(sphmd) + { + // check for existing coordinates + if(sphmd->sim_parms->co) + { + int i = 0; + ParticleSettings *part = psys->part; + ParticleData *pa=0; + float null[3] = {0,0,0}; + + if(ob==G.obedit) // off... + return; + + part->totpart= sphmd->sim_parms->numpart; + part->sta=part->end = 1.0f; + part->lifetime = G.scene->r.efra + 1; + + /* initialize particles */ + realloc_particles(ob, psys, part->totpart); + initialize_all_particles(ob, psys, 0); + + printf("sphmd->sim_parms->numpart: %ld\n", sphmd->sim_parms->numpart); + + for(i = 0, pa=psys->particles; i < sphmd->sim_parms->numpart; i++, pa++) + { + pa->size = 0.01f; + VECCOPY(pa->state.co, sphmd->sim_parms->co + i*3); + VECCOPY(pa->state.vel, null); + + pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0f; + pa->state.rot[0] = 1.0; + pa->state.rot[1] = pa->state.rot[2] = pa->state.rot[3] = 0.0; + + pa->alive = PARS_ALIVE; + } + } + } + } #endif // DISABLE_ELBEEM } diff --git a/source/blender/blenkernel/intern/sph.c b/source/blender/blenkernel/intern/sph.c new file mode 100644 index 00000000000..3db1a361d5c --- /dev/null +++ b/source/blender/blenkernel/intern/sph.c @@ -0,0 +1,490 @@ +/* pw.c +* +* +* ***** 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) Blender Foundation +* All rights reserved. +* +* Contributor(s): Daniel Genrich +* +* ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include <malloc.h> + +#include "MEM_guardedalloc.h" + +#include "BKE_sph.h" + +#include "DNA_sph_types.h" + +#include "sph_extern.h" + +#include "DNA_effect_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_particle.h" + + +// necessary +#include "float.h" +#include "math.h" +#include "BLI_kdtree.h" +#include "BLI_arithb.h" + +// #include "omp.h" + +#ifdef _WIN32 +void ststart ( void ) +{} +void stend ( void ) +{ +} +double stval() +{ + return 0; +} +#else +#include <sys/time.h> + +static struct timeval _ststart, _stend; +static struct timezone stz; + +void ststart(void) +{ + gettimeofday(&_ststart, &stz); +} +void stend(void) +{ + gettimeofday(&_stend,&stz); +} +double stval() +{ + double t1, t2; + t1 = (double)_ststart.tv_sec + (double)_ststart.tv_usec/(1000*1000); + t2 = (double)_stend.tv_sec + (double)_stend.tv_usec/(1000*1000); + return t2-t1; +} +#endif + +void sph_init (SphModifierData *sphmd) +{ + /* fill modifier with standard settings */ + sphmd->sim_parms->timestep = 0.001; // 0.001 + sphmd->sim_parms->viscosity = 80000.0; + sphmd->sim_parms->incompressibility = 8000000.0; + sphmd->sim_parms->surfacetension = 8000.0; + sphmd->sim_parms->density = 1000.0; + sphmd->sim_parms->gravity[2] = -9.81; + sphmd->sim_parms->gravity[1] = 0.0; + sphmd->sim_parms->gravity[0] = 0.0; + sphmd->sim_parms->samplingdistance = 0.02; // length of one cell? 0.01 + sphmd->sim_parms->smoothinglength = 2.5; + sphmd->sim_parms->flags = SPH_SIMSETTINGS_FLAG_GHOSTS | SPH_SIMSETTINGS_FLAG_OFFLINE | SPH_SIMSETTINGS_FLAG_MULTIRES | SPH_SIMSETTINGS_FLAG_DOMAIN; + sphmd->sim_parms->computesurfaceevery = 5; // 30000000 + sphmd->sim_parms->fastmarchingevery = 5; + sphmd->sim_parms->dumppovrayevery = 300000; + sphmd->sim_parms->dumpimageevery = 30; + sphmd->sim_parms->totaltime = 0.01; // 40.0 + sphmd->sim_parms->tangentialfriction = 0.1; + sphmd->sim_parms->normalfriction = 0.95; + sphmd->sim_parms->initiallevel = 1; + sphmd->sim_parms->rotation_angle = 0.0; + + sphmd->sim_parms->rotation_axis[0] = 1.0; + sphmd->sim_parms->rotation_axis[1] = 1.0; + sphmd->sim_parms->rotation_axis[2] = 1.0; + + sphmd->sim_parms->rotation_center[0] = 0.0; + sphmd->sim_parms->rotation_center[1] = 0.0; + sphmd->sim_parms->rotation_center[2] = 0.0; + + sphmd->sim_parms->scenelowerbound[0] = -1.0; + sphmd->sim_parms->scenelowerbound[1] = -1.0; + sphmd->sim_parms->scenelowerbound[2] = -1.0; + + sphmd->sim_parms->sceneupperbound[0] = 1.0; + sphmd->sim_parms->sceneupperbound[1] = 1.0; + sphmd->sim_parms->sceneupperbound[2] = 1.0; + + sphmd->sim_parms->alpha = 2.0; + sphmd->sim_parms->beta = 3.0; + sphmd->sim_parms->gamma = 1.5; + + sphmd->sim_parms->numverts = 0; + sphmd->sim_parms->numtris = 0; + sphmd->sim_parms->verts = NULL; + sphmd->sim_parms->tris = NULL; + sphmd->sim_parms->normals = NULL; + + sphmd->sim_parms->resolution = 70; + + sphmd->sim_parms->co = NULL; + sphmd->sim_parms->r = NULL; + sphmd->sim_parms->numpart = 0; +} + +void sph_free_modifier (SphModifierData *sphmd) +{ + + // sph_free_cpp(sphmd); + + if(sphmd->sim_parms->verts) + free(sphmd->sim_parms->verts); + if(sphmd->sim_parms->tris) + free(sphmd->sim_parms->tris); + if(sphmd->sim_parms->normals) + free(sphmd->sim_parms->normals); + if(sphmd->sim_parms->co) + MEM_freeN(sphmd->sim_parms->co); + if(sphmd->sim_parms->r) + free(sphmd->sim_parms->r); + +} + + +DerivedMesh *sphModifier_do(SphModifierData *sphmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) +{ + SphSimSettings *sim_parms = sphmd->sim_parms; + DerivedMesh *result = NULL; + MVert *mvert = NULL; + MFace *mface = NULL; + int a = 0; + float mat[4][4], imat[4][4]; + Mat4CpyMat4(mat, ob->obmat); + Mat4Invert(imat, mat); + + // only domain is simulated + if(!(sim_parms->flags & SPH_SIMSETTINGS_FLAG_DOMAIN) && !(sim_parms->flags & SPH_SIMSETTINGS_FLAG_BAKING)) + { + return dm; + } + + ststart(); + + if(!(sim_parms->flags & SPH_SIMSETTINGS_FLAG_INIT)) + { + if(!sph_init_all (sphmd, dm, ob)) + { + sphmd->sim_parms->flags &= ~SPH_SIMSETTINGS_FLAG_INIT; + return dm; + } + } + + + + // sph_simulate_cpp(ob, sphmd, 1.0, NULL); + + stend(); + + printf ( "SPH simulation time: %f\n", ( float ) stval() ); + + if(sim_parms->numverts && sim_parms->numtris) + { + + + result = CDDM_new ( sim_parms->numverts, 0, sim_parms->numtris); + + // copy verts + mvert = CDDM_get_verts(result); + for(a=0; a<sim_parms->numverts; a++) { + MVert *mv = &mvert[a]; + float *vbCo = &sim_parms->verts[a*3]; + VECCOPY(mv->co, vbCo); + Mat4MulVecfl(imat, mv->co); + } + + mface = CDDM_get_faces(result); + for(a=0; a<sim_parms->numtris; a++) { + MFace *mf = &mface[a]; + int *tri = &sim_parms->tris[a*3]; + mf->v1 = tri[0]; + mf->v2 = tri[1]; + mf->v3 = tri[2]; + test_index_face(mf, NULL, 0, 3); + } + + CDDM_calc_edges ( result ); + CDDM_calc_normals ( result ); + + return result; + } + else + return dm; +} + +static void set_min_max(float *min, float *max, float *co) +{ + // also calc min + max of bounding box for 3d grid + min[0] = MIN2(min[0], co[0]); + min[1] = MIN2(min[1], co[1]); + min[2] = MIN2(min[2], co[2]); + + max[0] = MAX2(max[0], co[0]); + max[1] = MAX2(max[1], co[1]); + max[2] = MAX2(max[2], co[2]); +} + +long calc_distance_field(Object *ob, DerivedMesh *dm, SphModifierData *sphmd, float mat[4][4]) +{ + int numverts = dm->getNumVerts(dm); + int numfaces = dm->getNumFaces(dm); + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + int i, j, k; + KDTree *tree; + float co[3], co1[3], co2[3], co3[3], co4[3]; + int index; + float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}, slice, maxdir; + int resx, resy, resz; + int maxres = 20; + float *dist; + float *normals; + int totpart = 0; + float *cos = NULL; + int maxpart = 0; + + printf("calc_distance_field\n"); + + dist = MEM_callocN(maxres*maxres*maxres*sizeof(float), "distance_field"); + normals = MEM_callocN(numfaces*3*sizeof(float), "triangle_normals"); + + ///////////////////////////////////////////////// + // create + fill + balance kdtree + ///////////////////////////////////////////////// + tree = BLI_kdtree_new(numverts); + for(i = 0; i < numfaces; i++) + { + VECCOPY(co1, mvert[mface[i].v1].co); + Mat4MulVecfl(mat, co1); + set_min_max(min, max, co1); + VECCOPY(co2, mvert[mface[i].v2].co); + Mat4MulVecfl(mat, co2); + set_min_max(min, max, co2); + VECCOPY(co3, mvert[mface[i].v3].co); + Mat4MulVecfl(mat, co3); + set_min_max(min, max, co3); + + // calc triangle center + VECCOPY(co, co1); + VECADD(co, co, co2); + VECADD(co, co, co3); + if(mface[i].v4) + { + VECCOPY(co4, mvert[mface[i].v4].co); + Mat4MulVecfl(mat, co4); + set_min_max(min, max, co4); + VECADD(co, co, co4); + VecMulf(co, 0.25); + } + else + VecMulf(co, 1.0 / 3.0); + + if(mface[i].v4) + CalcNormFloat4(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co, &normals[i*3]); + else + CalcNormFloat(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, &normals[i*3]); + + BLI_kdtree_insert(tree, i, co, NULL); + } + BLI_kdtree_balance(tree); + ///////////////////////////////////////////////// + + // calculate slice height + width + maxdir = max[0] - min[0]; + maxdir = MAX2(max[1]-min[1], maxdir); + maxdir = MAX2(max[2]-min[2], maxdir); + slice = maxdir / (float)maxres; + resx = MIN2(maxres, ceil((max[0] - min[0]) / slice)); + resy = MIN2(maxres, ceil((max[1] - min[1]) / slice)); + resz = MIN2(maxres, ceil((max[2] - min[2]) / slice)); + + // adjust max + max[0] = min[0] + slice * resx; + max[1] = min[1] + slice * resy; + max[2] = min[2] + slice * resz; + + if(sphmd->sim_parms->co) + MEM_freeN(sphmd->sim_parms->co); + + cos = sphmd->sim_parms->co = MEM_callocN(sizeof(float)*3*resx*resy*resz, "sph_cos"); + // r = calloc(1, sizeof(float)*resx*resy*resz); + maxpart = sizeof(float)*3*resx*resy*resz; + +// #pragma omp parallel for private(i,j,k) schedule(static) + for(i = 0; i < resx; i ++) + { + for(j = 0; j < resy; j++) + { + for(k = 0; k < resz; k++) + { + KDTreeNearest nearest; + float tco[3]; + tco[0] = min[0] + slice * i + slice * 0.5; + tco[1] = min[1] + slice * j + slice * 0.5; + tco[2] = min[2] + slice * k + slice * 0.5; + + index = BLI_kdtree_find_nearest(tree, tco, NULL, &nearest); + + if(index != -1) + { + float t[3]; + float sgn; + + VECSUB(t, tco, nearest.co); + sgn = INPR(t, &normals[nearest.index*3]); + + if(sgn < 0.0) + sgn = -1.0; + else + sgn = 1.0; + + dist[(i*resy*resz)+(j*resz)+k] = sgn * nearest.dist; + + if((int)sgn < 0) + { + // create particle if inside object + VECCOPY(&cos[totpart*3], tco); + + totpart++; + } + + } + else + { + printf("Error: no nearest point!\n"); + } + } + } + } + printf("maxpart: %d, totpart: %d\n", maxpart, totpart); + + sphmd->sim_parms->numpart = totpart; + MEM_freeN(dist); + MEM_freeN(normals); + BLI_kdtree_free(tree); + return totpart; +} + +/* add constraints, inflows, fluid, ... */ +int sph_init_all (SphModifierData *sphmd, DerivedMesh *dm, Object *ob) +{ + Base *base=NULL; + Object *fobject = NULL; + SphModifierData *fsphmd = NULL; + int fluids = 0; // only one fluid object possible + DerivedMesh *fdm = NULL; + + sphmd->sim_parms->flags |= SPH_SIMSETTINGS_FLAG_INIT; + CDDM_calc_normals ( dm ); + + /* create C++ object */ + // sph_init_cpp(sphmd); + sphmd->sim_parms->numpart = calc_distance_field(ob, dm, sphmd, ob->obmat); + return 1; + + /* create fluid domain */ + // sph_set_domain(sphmd, dm, ob->obmat); + + // check for constraints, fluid, etc. but ignore domains + for ( base = G.scene->base.first; base; base = base->next ) + { + fobject = base->object; + fsphmd = ( SphModifierData * ) modifiers_findByType ( fobject, eModifierType_Sph ); + + // TODO I could check for linked groups, too + if ( !fsphmd ) + { + // TODO + } + else + { + if(fsphmd == sphmd) + continue; + + if(fsphmd->sim_parms) + { + // check for fluid + if(((short)fsphmd->sim_parms->flags == SPH_SIMSETTINGS_FLAG_FLUID) && (!fluids)) + { + // create fluids + // particles have to be created AFTER constraints + // TODO: no particles = crash + + // get derivedmesh from object + fdm = mesh_get_derived_final(fobject, CD_MASK_BAREMESH); + + // create fluid object + /* + if(!sph_add_particles(sphmd, fdm, fobject->obmat, fsphmd->sim_parms->resolution)) + { + fluids--; + } + */ + if(fdm) + fdm->release(fdm); + + fluids++; + } + else if((short)fsphmd->sim_parms->flags & SPH_SIMSETTINGS_FLAG_OBSTACLE) + { + + } + } + } + } + + if(!fluids) + return 0; + + return 1; +} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h new file mode 100644 index 00000000000..c1240da6c3a --- /dev/null +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -0,0 +1,63 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2006 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich, Andre Pinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#ifndef BLI_KDOPBVH_H +#define BLI_KDOPBVH_H + +#include <float.h> + +struct BVHTree; +typedef struct BVHTree BVHTree; + +typedef struct BVHTreeOverlap { + int indexA; + int indexB; +} BVHTreeOverlap; + +BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); +void BLI_bvhtree_free(BVHTree *tree); + +/* construct: first insert points, then call balance */ +int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints); +void BLI_bvhtree_balance(BVHTree *tree); + +/* update: first update points/nodes, then call update_tree to refit the bounding volumes */ +int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints); +void BLI_bvhtree_update_tree(BVHTree *tree); + +/* collision/overlap: check two trees if they overlap, alloc's *overlap with length of the int return value */ +BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result); + +float BLI_bvhtree_getepsilon(BVHTree *tree); + +#endif // BLI_KDOPBVH_H + + + + diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c new file mode 100644 index 00000000000..c884b97b182 --- /dev/null +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -0,0 +1,849 @@ +/* kdop.c +* +* +* ***** 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) Blender Foundation +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Daniel Genrich, Andre Pinto +* +* ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#include "math.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "BLI_kdopbvh.h" +#include "BLI_arithb.h" + +#ifdef _OPENMP +#include <omp.h> +#endif + +#include <time.h> + +/* Util macros */ +#define TO_STR(a) #a +#define JOIN(a,b) a##b + +/* Benchmark macros */ +#if 1 + +#define BENCH(a) \ + do { \ + clock_t _clock_init = clock(); \ + (a); \ + printf("%s: %fms\n", #a, (float)(clock()-_clock_init)*1000/CLOCKS_PER_SEC); \ +} while(0) + +#define BENCH_VAR(name) clock_t JOIN(_bench_step,name) = 0, JOIN(_bench_total,name) = 0 +#define BENCH_BEGIN(name) JOIN(_bench_step, name) = clock() +#define BENCH_END(name) JOIN(_bench_total,name) += clock() - JOIN(_bench_step,name) +#define BENCH_RESET(name) JOIN(_bench_total, name) = 0 +#define BENCH_REPORT(name) printf("%s: %fms\n", TO_STR(name), JOIN(_bench_total,name)*1000.0f/CLOCKS_PER_SEC) + +#else + +#define BENCH(a) (a) +#define BENCH_VAR(name) +#define BENCH_BEGIN(name) +#define BENCH_END(name) +#define BENCH_RESET(name) +#define BENCH_REPORT(name) + +#endif + + +typedef struct BVHNode +{ + struct BVHNode **children; // max 8 children + struct BVHNode *parent; // needed for bottom - top update + float *bv; // Bounding volume of all nodes, max 13 axis + int index; /* face, edge, vertex index */ + char totnode; // how many nodes are used, used for speedup + char traversed; // how many nodes already traversed until this level? + char main_axis; +} BVHNode; + +struct BVHTree +{ + BVHNode **nodes; + BVHNode *nodearray; /* pre-alloc branch nodes */ + BVHNode **nodechild; // pre-alloc childs for nodes + float *nodebv; // pre-alloc bounding-volumes for nodes + float epsilon; /* epslion is used for inflation of the k-dop */ + int totleaf; // leafs + int totbranch; + char tree_type; // type of tree (4 => quadtree) + char axis; // kdop type (6 => OBB, 7 => AABB, ...) + char start_axis, stop_axis; // KDOP_AXES array indices according to axis +}; + +typedef struct BVHOverlapData +{ + BVHTree *tree1, *tree2; + BVHTreeOverlap *overlap; + int i, max_overlap; /* i is number of overlaps */ +} BVHOverlapData; +//////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////// +// Bounding Volume Hierarchy Definition +// +// Notes: From OBB until 26-DOP --> all bounding volumes possible, just choose type below +// Notes: You have to choose the type at compile time ITM +// Notes: You can choose the tree type --> binary, quad, octree, choose below +//////////////////////////////////////////////////////////////////////// + +static float KDOP_AXES[13][3] = +{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0}, +{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0}, +{0, 1.0, -1.0} +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Introsort +// with permission deriven from the following Java code: +// http://ralphunden.net/content/tutorials/a-guide-to-introsort/ +// and he derived it from the SUN STL +////////////////////////////////////////////////////////////////////////////////////////////////////// +static int size_threshold = 16; +/* +* Common methods for all algorithms +*/ +static int floor_lg(int a) +{ + return (int)(floor(log(a)/log(2))); +} + +/* +* Insertion sort algorithm +*/ +static void bvh_insertionsort(BVHNode **a, int lo, int hi, int axis) +{ + int i,j; + BVHNode *t; + for (i=lo; i < hi; i++) + { + j=i; + t = a[i]; + while((j!=lo) && (t->bv[axis] < (a[j-1])->bv[axis])) + { + a[j] = a[j-1]; + j--; + } + a[j] = t; + } +} + +static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode * x, int axis) +{ + int i=lo, j=hi; + while (1) + { + while ((a[i])->bv[axis] < x->bv[axis]) i++; + j--; + while (x->bv[axis] < (a[j])->bv[axis]) j--; + if(!(i < j)) + return i; + SWAP( BVHNode* , a[i], a[j]); + i++; + } +} + +/* +* Heapsort algorithm +*/ +static void bvh_downheap(BVHNode **a, int i, int n, int lo, int axis) +{ + BVHNode * d = a[lo+i-1]; + int child; + while (i<=n/2) + { + child = 2*i; + if ((child < n) && ((a[lo+child-1])->bv[axis] < (a[lo+child])->bv[axis])) + { + child++; + } + if (!(d->bv[axis] < (a[lo+child-1])->bv[axis])) break; + a[lo+i-1] = a[lo+child-1]; + i = child; + } + a[lo+i-1] = d; +} + +static void bvh_heapsort(BVHNode **a, int lo, int hi, int axis) +{ + int n = hi-lo, i; + for (i=n/2; i>=1; i=i-1) + { + bvh_downheap(a, i,n,lo, axis); + } + for (i=n; i>1; i=i-1) + { + SWAP(BVHNode*, a[lo],a[lo+i-1]); + bvh_downheap(a, 1,i-1,lo, axis); + } +} + +static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis) // returns Sortable +{ + if ((a[mid])->bv[axis] < (a[lo])->bv[axis]) + { + if ((a[hi])->bv[axis] < (a[mid])->bv[axis]) + return a[mid]; + else + { + if ((a[hi])->bv[axis] < (a[lo])->bv[axis]) + return a[hi]; + else + return a[lo]; + } + } + else + { + if ((a[hi])->bv[axis] < (a[mid])->bv[axis]) + { + if ((a[hi])->bv[axis] < (a[lo])->bv[axis]) + return a[lo]; + else + return a[hi]; + } + else + return a[mid]; + } +} +/* +* Quicksort algorithm modified for Introsort +*/ +static void bvh_introsort_loop (BVHNode **a, int lo, int hi, int depth_limit, int axis) +{ + int p; + + while (hi-lo > size_threshold) + { + if (depth_limit == 0) + { + bvh_heapsort(a, lo, hi, axis); + return; + } + depth_limit=depth_limit-1; + p=bvh_partition(a, lo, hi, bvh_medianof3(a, lo, lo+((hi-lo)/2)+1, hi-1, axis), axis); + bvh_introsort_loop(a, p, hi, depth_limit, axis); + hi=p; + } +} + +static void sort(BVHNode **a0, int begin, int end, int axis) +{ + if (begin < end) + { + BVHNode **a=a0; + bvh_introsort_loop(a, begin, end, 2*floor_lg(end-begin), axis); + bvh_insertionsort(a, begin, end, axis); + } +} +void sort_along_axis(BVHTree *tree, int start, int end, int axis) +{ + sort(tree->nodes, start, end, axis); +} + +//after a call to this function you can expect one of: +// every node to left of a[n] are smaller or equal to it +// every node to the right of a[n] are greater or equal to it +int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int axis){ + int begin = _begin, end = _end, cut; + int i; + while(end-begin > 3) + { + cut = bvh_partition(a, begin, end, bvh_medianof3(a, begin, (begin+end)/2, end-1, axis), axis ); + if(cut <= n) + begin = cut; + else + end = cut; + } + bvh_insertionsort(a, begin, end, axis); + + return n; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +void BLI_bvhtree_free(BVHTree *tree) +{ + if(tree) + { + MEM_freeN(tree->nodes); + MEM_freeN(tree->nodearray); + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodechild); + MEM_freeN(tree); + } +} + +BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) +{ + BVHTree *tree; + int numbranches=0, i; + + // only support up to octree + if(tree_type > 8) + return NULL; + + tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree"); + + if(tree) + { + tree->epsilon = epsilon; + tree->tree_type = tree_type; + tree->axis = axis; + + if(axis == 26) + { + tree->start_axis = 0; + tree->stop_axis = 13; + } + else if(axis == 18) + { + tree->start_axis = 7; + tree->stop_axis = 13; + } + else if(axis == 14) + { + tree->start_axis = 0; + tree->stop_axis = 7; + } + else if(axis == 8) // AABB + { + tree->start_axis = 0; + tree->stop_axis = 4; + } + else if(axis == 6) // OBB + { + tree->start_axis = 0; + tree->stop_axis = 3; + } + else + { + MEM_freeN(tree); + return NULL; + } + + + // calculate max number of branches, our bvh kdop is "almost perfect" + for(i = 1; i <= (int)ceil((float)((float)log(maxsize)/(float)log(tree_type))); i++) + numbranches += (pow(tree_type, i) / tree_type); + + tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *)*(numbranches+maxsize + tree_type), "BVHNodes"); + + if(!tree->nodes) + { + MEM_freeN(tree); + return NULL; + } + + tree->nodebv = (float*)MEM_callocN(sizeof(float)* axis * (numbranches+maxsize + tree_type), "BVHNodeBV"); + if(!tree->nodebv) + { + MEM_freeN(tree->nodes); + MEM_freeN(tree); + } + + tree->nodechild = (BVHNode**)MEM_callocN(sizeof(BVHNode*) * tree_type * (numbranches+maxsize + tree_type), "BVHNodeBV"); + if(!tree->nodechild) + { + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodes); + MEM_freeN(tree); + } + + tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode)*(numbranches+maxsize + tree_type), "BVHNodeArray"); + + if(!tree->nodearray) + { + MEM_freeN(tree->nodechild); + MEM_freeN(tree->nodebv); + MEM_freeN(tree->nodes); + MEM_freeN(tree); + return NULL; + } + + //link the dynamic bv and child links + for(i=0; i< numbranches+maxsize + tree_type; i++) + { + tree->nodearray[i].bv = tree->nodebv + i * axis; + tree->nodearray[i].children = tree->nodechild + i * tree_type; + } + + } + + return tree; +} + + +static void create_kdop_hull(BVHTree *tree, BVHNode *node, float *co, int numpoints, int moving) +{ + float newminmax; + int i, k; + + // don't init boudings for the moving case + if(!moving) + { + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[2*i] = FLT_MAX; + node->bv[2*i + 1] = -FLT_MAX; + } + } + + for(k = 0; k < numpoints; k++) + { + // for all Axes. + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + newminmax = INPR(&co[k * 3], KDOP_AXES[i]); + if (newminmax < node->bv[2 * i]) + node->bv[2 * i] = newminmax; + if (newminmax > node->bv[(2 * i) + 1]) + node->bv[(2 * i) + 1] = newminmax; + } + } +} + +// depends on the fact that the BVH's for each face is already build +static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) +{ + float newmin,newmax; + int i, j; + float *bv = node->bv; + + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + bv[2*i] = FLT_MAX; + bv[2*i + 1] = -FLT_MAX; + } + + for (j = start; j < end; j++) + { + // for all Axes. + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + newmin = tree->nodes[j]->bv[(2 * i)]; + if ((newmin < bv[(2 * i)])) + bv[(2 * i)] = newmin; + + newmax = tree->nodes[j]->bv[(2 * i) + 1]; + if ((newmax > bv[(2 * i) + 1])) + bv[(2 * i) + 1] = newmax; + } + } +} + +int BLI_bvhtree_insert(BVHTree *tree, int index, float *co, int numpoints) +{ + BVHNode *node= NULL; + int i; + + // insert should only possible as long as tree->totbranch is 0 + if(tree->totbranch > 0) + return 0; + + if(tree->totleaf+1 >= MEM_allocN_len(tree->nodes)) + return 0; + + // TODO check if have enough nodes in array + + node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); + tree->totleaf++; + + create_kdop_hull(tree, node, co, numpoints, 0); + + // inflate the bv with some epsilon + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum + } + + node->index= index; + + return 1; +} + +// only supports x,y,z axis in the moment +// but we should use a plain and simple function here for speed sake +static char get_largest_axis(float *bv) +{ + float middle_point[3]; + + middle_point[0] = (bv[1]) - (bv[0]); // x axis + middle_point[1] = (bv[3]) - (bv[2]); // y axis + middle_point[2] = (bv[5]) - (bv[4]); // z axis + if (middle_point[0] > middle_point[1]) + { + if (middle_point[0] > middle_point[2]) + return 1; // max x axis + else + return 5; // max z axis + } + else + { + if (middle_point[1] > middle_point[2]) + return 3; // max y axis + else + return 5; // max z axis + } +} + +static void bvh_div_nodes(BVHTree *tree, BVHNode *node, int start, int end, char lastaxis) +{ + char laxis; + int i, tend; + BVHNode *tnode; + int slice = (end-start+tree->tree_type-1)/tree->tree_type; //division rounded up + + // Determine which axis to split along + laxis = get_largest_axis(node->bv); + + // split nodes along longest axis + for (i=0; start < end; start += slice, i++) //i counts the current child + { + tend = start + slice; + + if(tend > end) tend = end; + + if(tend-start == 1) // ok, we have 1 left for this node + { + node->children[i] = tree->nodes[start]; + node->children[i]->parent = node; + } + else + { + tnode = node->children[i] = tree->nodes[tree->totleaf + tree->totbranch] = &(tree->nodearray[tree->totbranch + tree->totleaf]); + tree->totbranch++; + tnode->parent = node; + + if(tend != end) + partition_nth_element(tree->nodes, start, end, tend, laxis); + refit_kdop_hull(tree, tnode, start, tend); + bvh_div_nodes(tree, tnode, start, tend, laxis); + } + node->totnode++; + } + + return; +} + +static void verify_tree(BVHTree *tree) +{ + int i, j, check = 0; + + // check the pointer list + for(i = 0; i < tree->totleaf; i++) + { + if(tree->nodes[i]->parent == NULL) + printf("Leaf has no parent: %d\n", i); + else + { + for(j = 0; j < tree->tree_type; j++) + { + if(tree->nodes[i]->parent->children[j] == tree->nodes[i]) + check = 1; + } + if(!check) + { + printf("Parent child relationship doesn't match: %d\n", i); + } + check = 0; + } + } + + // check the leaf list + for(i = 0; i < tree->totleaf; i++) + { + if(tree->nodearray[i].parent == NULL) + printf("Leaf has no parent: %d\n", i); + else + { + for(j = 0; j < tree->tree_type; j++) + { + if(tree->nodearray[i].parent->children[j] == &tree->nodearray[i]) + check = 1; + } + if(!check) + { + printf("Parent child relationship doesn't match: %d\n", i); + } + check = 0; + } + } + + printf("branches: %d, leafs: %d, total: %d\n", tree->totbranch, tree->totleaf, tree->totbranch + tree->totleaf); +} + +void BLI_bvhtree_balance(BVHTree *tree) +{ + BVHNode *node; + + if(tree->totleaf == 0) + return; + + // create root node + node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); + tree->totbranch++; + + // refit root bvh node + refit_kdop_hull(tree, tree->nodes[tree->totleaf], 0, tree->totleaf); + // create + balance tree + bvh_div_nodes(tree, tree->nodes[tree->totleaf], 0, tree->totleaf, 0); + + // verify_tree(tree); +} + +// overlap - is it possbile for 2 bv's to collide ? +static int tree_overlap(float *bv1, float *bv2, int start_axis, int stop_axis) +{ + float *bv1_end = bv1 + (stop_axis<<1); + + bv1 += start_axis<<1; + bv2 += start_axis<<1; + + // test all axis if min + max overlap + for (; bv1 != bv1_end; bv1+=2, bv2+=2) + { + if ((*(bv1) > *(bv2 + 1)) || (*(bv2) > *(bv1 + 1))) + return 0; + } + + return 1; +} + +static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) +{ + int j; + + if(tree_overlap(node1->bv, node2->bv, MIN2(data->tree1->start_axis, data->tree2->start_axis), MIN2(data->tree1->stop_axis, data->tree2->stop_axis))) + { + // check if node1 is a leaf + if(!node1->totnode) + { + // check if node2 is a leaf + if(!node2->totnode) + { + + if(node1 == node2) + { + return; + } + + if(data->i >= data->max_overlap) + { + // try to make alloc'ed memory bigger + data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap)*data->max_overlap*2); + + if(!data->overlap) + { + printf("Out of Memory in traverse\n"); + return; + } + data->max_overlap *= 2; + } + + // both leafs, insert overlap! + data->overlap[data->i].indexA = node1->index; + data->overlap[data->i].indexB = node2->index; + + data->i++; + } + else + { + for(j = 0; j < data->tree2->tree_type; j++) + { + if(node2->children[j]) + traverse(data, node1, node2->children[j]); + } + } + } + else + { + + for(j = 0; j < data->tree2->tree_type; j++) + { + if(node1->children[j]) + traverse(data, node1->children[j], node2); + } + } + } + return; +} + +BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) +{ + int j, total = 0; + BVHTreeOverlap *overlap = NULL, *to = NULL; + BVHOverlapData **data; + + // check for compatibility of both trees (can't compare 14-DOP with 18-DOP) + if((tree1->axis != tree2->axis) && ((tree1->axis == 14) || tree2->axis == 14)) + return 0; + + // fast check root nodes for collision before doing big splitting + traversal + if(!tree_overlap(tree1->nodes[tree1->totleaf]->bv, tree2->nodes[tree2->totleaf]->bv, MIN2(tree1->start_axis, tree2->start_axis), MIN2(tree1->stop_axis, tree2->stop_axis))) + return 0; + + data = MEM_callocN(sizeof(BVHOverlapData *)* tree1->tree_type, "BVHOverlapData_star"); + + for(j = 0; j < tree1->tree_type; j++) + { + data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData"); + + // init BVHOverlapData + data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap)*MAX2(tree1->totleaf, tree2->totleaf)); + data[j]->tree1 = tree1; + data[j]->tree2 = tree2; + data[j]->max_overlap = MAX2(tree1->totleaf, tree2->totleaf); + data[j]->i = 0; + } + +#pragma omp parallel for private(j) schedule(static) + for(j = 0; j < tree1->tree_type; j++) + { + traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]); + } + + for(j = 0; j < tree1->tree_type; j++) + total += data[j]->i; + + to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap)*total, "BVHTreeOverlap"); + + for(j = 0; j < tree1->tree_type; j++) + { + memcpy(to, data[j]->overlap, data[j]->i*sizeof(BVHTreeOverlap)); + to+=data[j]->i; + } + + for(j = 0; j < tree1->tree_type; j++) + { + free(data[j]->overlap); + MEM_freeN(data[j]); + } + MEM_freeN(data); + + (*result) = total; + return overlap; +} + + +// bottom up update of bvh tree: +// join the 4 children here +static void node_join(BVHTree *tree, BVHNode *node) +{ + int i, j; + + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[2*i] = FLT_MAX; + node->bv[2*i + 1] = -FLT_MAX; + } + + for (i = 0; i < tree->tree_type; i++) + { + if (node->children[i]) + { + for (j = tree->start_axis; j < tree->stop_axis; j++) + { + // update minimum + if (node->children[i]->bv[(2 * j)] < node->bv[(2 * j)]) + node->bv[(2 * j)] = node->children[i]->bv[(2 * j)]; + + // update maximum + if (node->children[i]->bv[(2 * j) + 1] > node->bv[(2 * j) + 1]) + node->bv[(2 * j) + 1] = node->children[i]->bv[(2 * j) + 1]; + } + } + else + break; + } +} + +// call before BLI_bvhtree_update_tree() +int BLI_bvhtree_update_node(BVHTree *tree, int index, float *co, float *co_moving, int numpoints) +{ + BVHNode *node= NULL; + int i = 0; + + // check if index exists + if(index > tree->totleaf) + return 0; + + node = tree->nodearray + index; + + create_kdop_hull(tree, node, co, numpoints, 0); + + if(co_moving) + create_kdop_hull(tree, node, co_moving, numpoints, 1); + + // inflate the bv with some epsilon + for (i = tree->start_axis; i < tree->stop_axis; i++) + { + node->bv[(2 * i)] -= tree->epsilon; // minimum + node->bv[(2 * i) + 1] += tree->epsilon; // maximum + } + + return 1; +} + +// call BLI_bvhtree_update_node() first for every node/point/triangle +void BLI_bvhtree_update_tree(BVHTree *tree) +{ + BVHNode *leaf, *parent; + + // reset tree traversing flag + for (leaf = tree->nodearray + tree->totleaf; leaf != tree->nodearray + tree->totleaf + tree->totbranch; leaf++) + leaf->traversed = 0; + + for (leaf = tree->nodearray; leaf != tree->nodearray + tree->totleaf; leaf++) + { + for (parent = leaf->parent; parent; parent = parent->parent) + { + parent->traversed++; // we tried to go up in hierarchy + if (parent->traversed < parent->totnode) + break; // we do not need to check further + else + node_join(tree, parent); + } + } +} + +float BLI_bvhtree_getepsilon(BVHTree *tree) +{ + return tree->epsilon; +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1cb8b10b087..629de595345 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3075,6 +3075,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) clmd->sim_parms= newdataadr(fd, clmd->sim_parms); clmd->coll_parms= newdataadr(fd, clmd->coll_parms); + clmd->point_cache= newdataadr(fd, clmd->point_cache); if(clmd->point_cache) @@ -3084,22 +3085,16 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) if(clmd->sim_parms->presets > 10) clmd->sim_parms->presets = 0; } + else + { + /* Collision modifier without parameters?? */ + + } } else if (md->type==eModifierType_Collision) { CollisionModifierData *collmd = (CollisionModifierData*) md; - /* - // TODO: CollisionModifier should use pointcache - // + have proper reset events before enabling this - collmd->x = newdataadr(fd, collmd->x); - collmd->xnew = newdataadr(fd, collmd->xnew); - collmd->mfaces = newdataadr(fd, collmd->mfaces); - - collmd->current_x = MEM_callocN(sizeof(MVert)*collmd->numverts,"current_x"); - collmd->current_xnew = MEM_callocN(sizeof(MVert)*collmd->numverts,"current_xnew"); - collmd->current_v = MEM_callocN(sizeof(MVert)*collmd->numverts,"current_v"); - */ collmd->x = NULL; collmd->xnew = NULL; @@ -3108,9 +3103,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) collmd->current_v = NULL; collmd->time = -1; collmd->numverts = 0; - collmd->bvh = NULL; + collmd->bvhtree = NULL; collmd->mfaces = NULL; - } else if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h index 7571d64be91..058e4243b96 100644 --- a/source/blender/include/butspace.h +++ b/source/blender/include/butspace.h @@ -297,6 +297,10 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la /* Cloth sim button defines */ #define B_CLOTH_CHANGEPREROLL 1480 +/* SPH sim button defines */ +#define B_SPH_BAKE 1490 + + /* *********************** */ #define B_WORLDBUTS 1600 diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index b7b43817474..b2d6e8e5756 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -35,6 +35,7 @@ typedef enum ModifierType { eModifierType_Cloth, eModifierType_Collision, eModifierType_Bevel, + eModifierType_Sph, NUM_MODIFIER_TYPES } ModifierType; @@ -374,6 +375,14 @@ typedef struct ClothModifierData { struct PointCache *point_cache; /* definition is in DNA_object_force.h */ } ClothModifierData; +typedef struct SphModifierData { + ModifierData modifier; + + struct SPH *sph; /* pointer to cpp sph sim */ + struct SphSimSettings *sim_parms; /* definition is in DNA_sph_types.h */ + struct SphCollSettings *coll_parms; /* definition is in DNA_sph_types.h */ +} SphModifierData; + typedef struct CollisionModifierData { ModifierData modifier; @@ -390,7 +399,7 @@ typedef struct CollisionModifierData { unsigned int numfaces; int pad; float time; /* cfra time of modifier */ - struct BVH *bvh; /* bounding volume hierarchy for this cloth object */ + struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ } CollisionModifierData; typedef enum { diff --git a/source/blender/makesdna/DNA_sph_types.h b/source/blender/makesdna/DNA_sph_types.h new file mode 100644 index 00000000000..add3053f612 --- /dev/null +++ b/source/blender/makesdna/DNA_sph_types.h @@ -0,0 +1,102 @@ +/** + * $Id: DNA_cloth_types.h,v 1.1 2007/08/01 02:28:34 daniel Exp $ + * + * ***** 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) 2006 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel (Genscher) + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef DNA_SPH_TYPES_H +#define DNA_SPH_TYPES_H + +// string scene, constraint, backup: missing +// string _file; +// string pov; +// string rendered; +typedef struct SphSimSettings +{ + int flags; // see pw_extern.h + float timestep; + float viscosity; + float incompressibility; /* how incompressible is the fluid? */ + float surfacetension; + float density; + float gravity[3]; /* gravity on the domain */ + float samplingdistance; + float smoothinglength; + + float controlviscosity; + int dumpimageevery; + int computesurfaceevery; + int fastmarchingevery; + int dumppovrayevery; + + float totaltime; + + float tangentialfriction; /* constraint tangential friction */ + float normalfriction; /* constraint normal friction */ + + float rotation_angle; + float rotation_axis[3]; + float rotation_center[3]; + float scenelowerbound[3]; + float sceneupperbound[3]; + + int initiallevel; + + float alpha; + float beta; + float gamma; + + /* needed for better direct resolution input for constraints, fluids,... */ + int resolution; /* can also be calculated by (Max-Min) / samplingdistance */ + int pad; + float *verts; + float *normals; + int *tris; + unsigned int numverts; + unsigned int numtris; + float *co; /* particle positions */ + float *r; /* particle radius */ + long numpart; + int pad2; +} +SphSimSettings; + +typedef struct SphCollSettings +{ + float epsilon; /* min distance for collisions. */ + float self_friction; /* Fiction/damping with self contact. */ + float friction; /* Friction/damping applied on contact with other object.*/ + short self_loop_count; /* How many iterations for the selfcollision loop */ + short loop_count; /* How many iterations for the collision loop. */ + struct LinkNode *collision_list; /* e.g. pointer to temp memory for collisions */ + int flags; /* collision flags defined in BKE_cloth.h */ + float selfepsilon; /* for selfcollision */ +} +SphCollSettings; + +#endif // DNA_SPH_TYPES_H diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 1365baf075a..d2f798d0b6e 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -985,7 +985,7 @@ static uiBlock *modifiers_add_menu(void *ob_v) /* Only allow adding through appropriate other interfaces */ if(ELEM3(i, eModifierType_Softbody, eModifierType_Hook, eModifierType_ParticleSystem)) continue; - if(ELEM(i, eModifierType_Cloth, eModifierType_Collision)) continue; + if(ELEM3(i, eModifierType_Cloth, eModifierType_Collision, eModifierType_Sph)) continue; if((mti->flags&eModifierTypeFlag_AcceptsCVs) || (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) { @@ -1813,6 +1813,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 31; } else if (md->type==eModifierType_Collision) { height = 31; + } else if (md->type==eModifierType_Sph) { + height = 31; } else if (md->type==eModifierType_Boolean) { height = 48; } else if (md->type==eModifierType_Array) { @@ -1843,7 +1845,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiButSetFunc(but, modifiers_applyModifier, ob, md); } - if (md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth)) { + if (md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth) && (md->type!=eModifierType_Sph)) { but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Copy", lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Duplicate the current modifier at the same position in the stack"); uiButSetFunc(but, modifiers_copyModifier, ob, md); } @@ -2235,6 +2237,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefBut(block, LABEL, 1, "See Soft Body panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); } else if (md->type==eModifierType_Cloth) { uiDefBut(block, LABEL, 1, "See Cloth panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); + } else if (md->type==eModifierType_Sph) { + uiDefBut(block, LABEL, 1, "See Sph panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); } else if (md->type==eModifierType_Collision) { uiDefBut(block, LABEL, 1, "See Collision panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, ""); } else if (md->type==eModifierType_Boolean) { diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c index fb36d103656..93e5603e97a 100644 --- a/source/blender/src/buttons_object.c +++ b/source/blender/src/buttons_object.c @@ -52,6 +52,8 @@ #include "BKE_utildefines.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_sph.h" + #include "BLI_blenlib.h" #include "BLI_arithb.h" @@ -107,6 +109,7 @@ #include "DNA_particle_types.h" #include "DNA_radio_types.h" #include "DNA_screen_types.h" +#include "DNA_sph_types.h" #include "DNA_sound_types.h" #include "DNA_texture_types.h" #include "DNA_userdef_types.h" @@ -135,6 +138,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_sound.h" +#include "BKE_sph.h" #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" @@ -2476,6 +2480,27 @@ void do_object_panels(unsigned short event) allqueue(REDRAWVIEW3D, 0); } break; + case B_SPH_BAKE: + { + SphModifierData *sphmd = (SphModifierData *)modifiers_findByType(ob, eModifierType_Sph); + int i = 0; + + if(sphmd && sphmd->sim_parms) + { + sphmd->sim_parms->flags |= SPH_SIMSETTINGS_FLAG_BAKING; + + // call baking function + for(i = 0; i < 1; i++) + { + CFRA++; + update_for_newframe(); + } + + sphmd->sim_parms->flags &= ~SPH_SIMSETTINGS_FLAG_BAKING; + + } + } + break; } } @@ -5677,6 +5702,116 @@ static void object_panel_cloth_III(Object *ob) } +static void object_sph__enabletoggle(void *ob_v, void *arg2) +{ + Object *ob = ob_v; + ModifierData *md = modifiers_findByType(ob, eModifierType_Sph); + + if (!md) { + // create particle modifier + ParticleSettings *part = psys_new_settings("PSys", G.main); + ParticleSystem *psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); + ParticleSystemModifierData *psmd; + + md = modifier_new(eModifierType_Sph); + BLI_addtail(&ob->modifiers, md); + + part->type = PART_FLUID; + psys->part = part; + psys->pointcache = BKE_ptcache_add(); + psys->flag |= PSYS_ENABLED; + BLI_addtail(&ob->particlesystem,psys); + md= modifier_new(eModifierType_ParticleSystem); + sprintf(md->name, "SphParticleSystem" ); + psmd= (ParticleSystemModifierData*) md; + psmd->psys=psys; + BLI_addtail(&ob->modifiers, md); + + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWVIEW3D, 0); + } + else { + Object *ob = ob_v; + ModifierData *md = modifiers_findByType(ob, eModifierType_Sph); + + if (!md) + return; + + BLI_remlink(&ob->modifiers, md); + + modifier_free(md); + + BIF_undo_push("Del modifier"); + + // ob->softflag |= OB_SB_RESET; + allqueue(REDRAWBUTSEDIT, 0); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWOOPS, 0); + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + object_handle_update(ob); + countall(); + } +} + +static void object_panel_sph(Object *ob) +{ + uiBlock *block=NULL; + uiBut *but=NULL; + static int val; + SphModifierData *sphmd = (SphModifierData *)modifiers_findByType(ob, eModifierType_Sph); + + block= uiNewBlock(&curarea->uiblocks, "object_sph", UI_EMBOSS, UI_HELV, curarea->win); + if(uiNewPanel(curarea, block, "Sph ", "Physics", 640, 0, 318, 204)==0) return; + uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); + + val = (sphmd ? 1:0); + + + but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Sph", 10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become Sph"); + uiButSetFunc(but, object_sph__enabletoggle, ob, NULL); + + + uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/ + + if(sphmd) + { + if(sphmd->sim_parms && (sphmd->sim_parms->flags & SPH_SIMSETTINGS_FLAG_DOMAIN)) + { + uiDefBut(block, BUT, B_SPH_BAKE, "BAKE",10, 180,300,20, NULL, 0.0, 0.0, 10, 0, "Perform simulation and output and surface&preview meshes for each frame."); + } + + uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Domain", 10, 160, 100, 20, (short *)&sphmd->sim_parms->flags, 15.0, SPH_SIMSETTINGS_FLAG_DOMAIN, 0.0, 0.0, " "); + uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Fluid", 110, 160, 100, 20, (short *)&sphmd->sim_parms->flags, 15.0, SPH_SIMSETTINGS_FLAG_FLUID, 0.0, 0.0, " "); + uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Obstacle", 210, 160, 100, 20, (short *)&sphmd->sim_parms->flags, 15.0, SPH_SIMSETTINGS_FLAG_OBSTACLE, 0.0, 0.0, " "); + + if(sphmd->sim_parms && (sphmd->sim_parms->flags & SPH_SIMSETTINGS_FLAG_DOMAIN)) + { + uiDefButBitI(block, TOG, SPH_SIMSETTINGS_FLAG_GHOSTS, REDRAWBUTSOBJECT, "Ghosts",10,140,100,20, &sphmd->sim_parms->flags, 0, 0, 0, 0, " "); + uiDefButBitI(block, TOG, SPH_SIMSETTINGS_FLAG_MULTIRES, REDRAWBUTSOBJECT, "Multires",110,140,100,20, &sphmd->sim_parms->flags, 0, 0, 0, 0, " "); + uiDefButBitI(block, TOG, SPH_SIMSETTINGS_FLAG_VORTICITY, REDRAWBUTSOBJECT, "Vorticity",210,140,100,20, &sphmd->sim_parms->flags, 0, 0, 0, 0, " "); + + // timestep + uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Timestep:",10,120,100,20, &sphmd->sim_parms->timestep, 0.0, 1.0, 0.0001f, 0, " "); + // totaltime + uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Totaltime:",110,120,100,20, &sphmd->sim_parms->totaltime, 0.0, 10000.0, 0.001f, 0, " "); + uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Sampling distance:",210,120,100,20, &sphmd->sim_parms->samplingdistance, 0.0, 1.0, 0.0001f, 0, " "); + uiDefButF(block, NUM, REDRAWBUTSOBJECT, "Smoothing Length:",10,100,100,20, &sphmd->sim_parms->smoothinglength, 0.0, 10.0, 0.1f, 0, " "); + + uiDefButI(block, NUM, REDRAWBUTSOBJECT, "Surface:",110,100,100,20, &sphmd->sim_parms->computesurfaceevery, 0.0, 1000.0, 1.0, 0, " "); + uiDefButI(block, NUM, REDRAWBUTSOBJECT, "Fast Marching:",210,100,100,20, &sphmd->sim_parms->fastmarchingevery, 0.0, 1000.0, 1.0, 0, " "); + } + else if(sphmd->sim_parms && (sphmd->sim_parms->flags & SPH_SIMSETTINGS_FLAG_FLUID)) + { + uiDefButI(block, NUM, REDRAWBUTSOBJECT, "Resolution:",10,120,100,20, &sphmd->sim_parms->resolution, 1.0, 1000.0, 1.0f, 0, " "); + } + } + + + uiBlockEndAlign(block); +} + void object_panels() { Object *ob; @@ -5709,6 +5844,7 @@ void physics_panels() object_panel_cloth(ob); object_panel_cloth_II(ob); object_panel_cloth_III(ob); + object_panel_sph(ob); object_panel_fluidsim(ob); } } diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index 3ef14574bc8..0b042fc542f 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -1883,11 +1883,13 @@ static void draw_em_measure_stats(Object *ob, EditMesh *em) { EditEdge *eed; EditFace *efa; + EditVert *eve; float v1[3], v2[3], v3[3], v4[3]; float fvec[3]; char val[32]; /* Stores the measurement display text here */ char conv_float[5]; /* Use a float conversion matching the grid size */ float area, col[3]; /* area of the face, color of the text to draw */ + int i = 0; /* make the precission of the pronted value proportionate to the gridsize */ if ((G.vd->grid) < 0.01) @@ -1941,7 +1943,7 @@ static void draw_em_measure_stats(Object *ob, EditMesh *em) if(col[1]> 0.5) {col[0]*=0.7; col[2]*= 0.7;} else col[1]= col[1]*0.7 + 0.3; glColor3fv(col); - + /* for(efa= em->faces.first; efa; efa= efa->next) { if((efa->f & SELECT) || (G.moving && faceselectedOR(efa, SELECT)) ) { VECCOPY(v1, efa->v1->co); @@ -1966,6 +1968,24 @@ static void draw_em_measure_stats(Object *ob, EditMesh *em) glRasterPos3fv(efa->cent); BMF_DrawString( G.fonts, val); } + }*/ + + /* draw IDs of mesh vertexes */ + for(eve = em->verts.first; eve; eve = eve->next) { + char val[32]; + float fvec[3]; + VecLerpf(fvec, ob->loc, eve->co, 1.1); + glRasterPos3f(fvec[0], fvec[1], fvec[2]); + + sprintf(val, "%d", eve->keyindex); + BMF_DrawString(G.fonts, val); + } + for(efa= em->faces.first; efa; efa= efa->next) { + char val[32]; + sprintf(val, "%d", i); + glRasterPos3fv(efa->cent); + BMF_DrawString( G.fonts, val); + i++; } } diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 8640e69102b..757e9a39a83 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -307,7 +307,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, case UseBullet: { CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(); - ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw()); + // ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw()); ccdPhysEnv->setDeactivationLinearTreshold(0.8f); // default, can be overridden by Python ccdPhysEnv->setDeactivationAngularTreshold(1.0f); // default, can be overridden by Python diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 9f14cf6cbef..c89e0b43456 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -71,7 +71,7 @@ protected: public: - CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0); + CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btBroadphaseInterface* broadphase=0); virtual ~CcdPhysicsEnvironment(); |