Merge branch 'master' into blender2.8
[blender.git] / intern / elbeem / intern / ntl_blenderdumper.cpp
1 /** \file elbeem/intern/ntl_blenderdumper.cpp
2  *  \ingroup elbeem
3  */
4 /******************************************************************************
5  *
6  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
7  * Copyright 2003-2006 Nils Thuerey
8  *
9  * Replaces std. raytracer, and only dumps time dep. objects to disc
10  *
11  *****************************************************************************/
12
13 #include <fstream>
14 #include <sys/types.h>
15
16 #include "utilities.h"
17 #include "ntl_matrices.h"
18 #include "ntl_blenderdumper.h"
19 #include "ntl_world.h"
20 #include "solver_interface.h"
21 #include "globals.h"
22
23 #include <zlib.h>
24
25
26
27 /******************************************************************************
28  * Constructor
29  *****************************************************************************/
30 ntlBlenderDumper::ntlBlenderDumper() : ntlWorld()
31 {
32         // same as normal constructor here
33 }
34 ntlBlenderDumper::ntlBlenderDumper(string filename, bool commandlineMode) :
35         ntlWorld(filename,commandlineMode)
36 {
37         // init world
38 }
39
40
41
42 /******************************************************************************
43  * Destructor
44  *****************************************************************************/
45 ntlBlenderDumper::~ntlBlenderDumper()
46 {
47         debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10);
48 }
49
50 /******************************************************************************
51  * Only dump time dep. objects to file
52  *****************************************************************************/
53 int ntlBlenderDumper::renderScene( void )
54 {
55         char nrStr[5];                                                          /* nr conversion */
56   ntlRenderGlobals *glob = mpGlob;
57   ntlScene *scene = mpGlob->getSimScene();
58         bool debugOut = false;
59         bool debugRender = false;
60 #if ELBEEM_PLUGIN==1
61         debugOut = false;
62 #endif // ELBEEM_PLUGIN==1
63
64         vector<string> gmName;   // gm names
65         vector<string> gmMat;    // materials for gm
66         int numGMs = 0;                                  // no. of .obj models created
67
68         if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1);
69   long startTime = getTime();
70         snprintf(nrStr, 5, "%04d", glob->getAniCount() );
71
72   // local scene vars
73   vector<ntlTriangle> Triangles;
74   vector<ntlVec3Gfx>  Vertices;
75   vector<ntlVec3Gfx>  VertNormals;
76
77         // check geo objects
78         int idCnt = 0;          // give IDs to objects
79         for (vector<ntlGeometryClass*>::iterator iter = scene->getGeoClasses()->begin();
80                         iter != scene->getGeoClasses()->end(); iter++) {
81                 if(!(*iter)->getVisible()) continue;
82                 int tid = (*iter)->getTypeId();
83
84                 if(tid & GEOCLASSTID_OBJECT) {
85                         // normal geom. objects -> ignore
86                 }
87                 if(tid & GEOCLASSTID_SHADER) {
88                         ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast<ntlGeometryShader*>(*iter);
89                         string outname = geoshad->getOutFilename();
90                         if(outname.length()<1) outname = mpGlob->getOutFilename();
91                         geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname);
92
93                         for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin();
94                                         siter != geoshad->getObjectsEnd();
95                                         siter++) {
96                                 if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8);
97
98                                 (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime);
99                                 bool doDump = false;
100                                 bool isPreview = false;
101                                 // only dump final&preview surface meshes
102                                 if( (*siter)->getName().find( "final" ) != string::npos) {
103                                         doDump = true;
104                                 } else if( (*siter)->getName().find( "preview" ) != string::npos) {
105                                         doDump = true;
106                                         isPreview = true;
107                                 }
108                                 if(!doDump) continue;
109
110                                 // dont quit, some objects need notifyOfDump call
111                                 if((glob_mpactive) && (glob_mpindex>0)) {
112                                         continue; //return 0;
113                                 }
114                                 
115                                 // only dump geo shader objects
116                                 Triangles.clear();
117                                 Vertices.clear();
118                                 VertNormals.clear();
119                                 (*siter)->initialize( mpGlob );
120                                 (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt);
121                                 idCnt ++;
122                                 
123                                 // WARNING - this is dirty, but simobjs are the only geoshaders right now
124                                 SimulationObject *sim = (SimulationObject *)geoshad;
125                                 LbmSolverInterface *lbm = sim->getSolver();
126
127
128                                 // always dump mesh, even empty ones...
129
130                                 // dump to binary file
131                                 std::ostringstream boutfilename("");
132                                 //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj";
133                                 boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr;
134                                 if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName() 
135                                                 <<", triangles:"<<Triangles.size()<<", vertices:"<<Vertices.size()<<
136                                                 " to "<<boutfilename.str() , 7);
137                                 gzFile gzf;
138
139                                 // output velocities if desired
140                                 if((!isPreview) && (lbm->getDumpVelocities())) {
141                                         std::ostringstream bvelfilename;
142                                         bvelfilename << boutfilename.str();
143                                         bvelfilename << ".bvel.gz";
144                                         gzf = gzopen(bvelfilename.str().c_str(), "wb9");
145                                         if(gzf) {
146                                                 int numVerts;
147                                                 if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
148                                                 numVerts = Vertices.size();
149                                                 gzwrite(gzf, &numVerts, sizeof(numVerts));
150                                                 for(size_t i=0; i<Vertices.size(); i++) {
151                                                         // returns smoothed velocity, scaled by frame time
152                                                         ntlVec3Gfx v = lbm->getVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] );
153                                                         // translation not necessary, test rotation & scaling?
154                                                         for(int j=0; j<3; j++) {
155                                                                 float vertp = v[j];
156                                                                 //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "<<i<<" = "<<v);
157                                                                 gzwrite(gzf, &vertp, sizeof(vertp)); }
158                                                 }
159                                                 gzclose( gzf );
160                                         }
161                                 }
162
163                                 // compress all bobj's 
164                                 boutfilename << ".bobj.gz";
165                                 gzf = gzopen(boutfilename.str().c_str(), "wb1"); // wb9 is slow for large meshes!
166                                 if (!gzf) {
167                                         errMsg("ntlBlenderDumper::renderScene","Unable to open output '" + boutfilename.str() + "' ");
168                                         return 1; }
169
170                                 // dont transform velocity output, this is handled in blender
171                                 // current transform matrix
172                                 ntlMatrix4x4<gfxReal> *trafo;
173                                 trafo = lbm->getDomainTrafo();
174                                 if(trafo) {
175                                         // transform into source space
176                                         for(size_t i=0; i<Vertices.size(); i++) {
177                                                 Vertices[i] = (*trafo) * Vertices[i];
178                                         }
179                                 }
180                                 // rotate vertnormals
181                                 ntlMatrix4x4<gfxReal> rottrafo;
182                                 rottrafo.initId();
183                                 if(lbm->getDomainTrafo()) {
184                                         // dont modifiy original!
185                                         rottrafo = *lbm->getDomainTrafo();
186                                         ntlVec3Gfx rTrans,rScale,rRot,rShear;
187                                         rottrafo.decompose(rTrans,rScale,rRot,rShear);
188                                         rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]);
189                                         // only rotate here...
190                                         for(size_t i=0; i<Vertices.size(); i++) {
191                                                 VertNormals[i] = rottrafo * VertNormals[i];
192                                                 normalize(VertNormals[i]); // remove scaling etc.
193                                         }
194                                 }
195
196                                 
197                                 // write to file
198                                 int numVerts;
199                                 if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; }
200                                 numVerts = Vertices.size();
201                                 gzwrite(gzf, &numVerts, sizeof(numVerts));
202                                 for(size_t i=0; i<Vertices.size(); i++) {
203                                         for(int j=0; j<3; j++) {
204                                                 float vertp = Vertices[i][j];
205                                                 gzwrite(gzf, &vertp, sizeof(vertp)); }
206                                 }
207
208                                 // should be the same as Vertices.size
209                                 if(VertNormals.size() != (size_t)numVerts) {
210                                         errMsg("ntlBlenderDumper::renderScene","Normals have to have same size as vertices!");
211                                         VertNormals.resize( Vertices.size() );
212                                 }
213                                 gzwrite(gzf, &numVerts, sizeof(numVerts));
214                                 for(size_t i=0; i<VertNormals.size(); i++) {
215                                         for(int j=0; j<3; j++) {
216                                                 float normp = VertNormals[i][j];
217                                                 gzwrite(gzf, &normp, sizeof(normp)); }
218                                 }
219
220                                 int numTris = Triangles.size();
221                                 gzwrite(gzf, &numTris, sizeof(numTris));
222                                 for(size_t i=0; i<Triangles.size(); i++) {
223                                         for(int j=0; j<3; j++) {
224                                                 int triIndex = Triangles[i].getPoints()[j];
225                                                 gzwrite(gzf, &triIndex, sizeof(triIndex)); }
226                                 }
227                                 gzclose( gzf );
228                                 debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY," Wrote: '"<<boutfilename.str()<<"' ", 2);
229                                 numGMs++;
230                         }
231                 }
232
233         }
234
235         // output ecr config file
236         if(numGMs>0) {
237                 if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<<numGMs, 10);
238         } else {
239                 if((glob_mpactive) && (glob_mpindex>0)) {
240                         // ok, nothing to do anyway...
241                 } else {
242                         errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR);
243                         return 1;
244                 }
245         }
246
247         // debug timing
248         long stopTime = getTime();
249         debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<<nrStr<<" dump time: "<< getTimeString(stopTime-startTime) <<" ", 10);
250
251         // still render for preview...
252         if(debugRender) {
253                 debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Performing preliminary render", 1);
254                 ntlWorld::renderScene(); }
255         else {
256                 // next frame 
257                 glob->setAniCount( glob->getAniCount() +1 );
258         }
259
260         return 0;
261 }
262
263
264