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