New export through plugin scheme for yafray. It is working on linux and mac os x
[blender.git] / source / blender / yafray / intern / yafray_Render.cpp
1 //----------------------------------------------------------------------------------------------------
2 // YafRay XML export
3 //
4 // For anyone else looking at this, this was designed for a tabspacing of 2 (YafRay/Jandro standard :)
5 //----------------------------------------------------------------------------------------------------
6
7 #include "yafray_Render.h"
8
9 #include <math.h>
10
11 using namespace std;
12
13 void yafrayRender_t::clearAll()
14 {
15         all_objects.clear();
16         used_materials.clear();
17         used_textures.clear();
18         dupliMtx_list.clear();
19         dup_srcob.clear();
20         objectData.clear();
21 }
22
23 bool yafrayRender_t::exportScene()
24 {
25
26   // get camera first, no checking should be necessary, all done by Blender
27         maincam_obj = G.scene->camera;
28
29         // use fixed lens for objects functioning as temporary camera (ctrl-0)
30         mainCamLens = 35.0;
31         if (maincam_obj->type==OB_CAMERA) mainCamLens=((Camera*)maincam_obj->data)->lens;
32
33         maxraydepth = 5;        // will be set to maximum depth used in blender materials
34
35         // recreate the scene as object data, as well as sorting the material & textures, ignoring duplicates
36         if (!getAllMatTexObs())
37         {
38                 // error found, clear for next call
39                 clearAll();
40                 return false;
41         }
42
43         if(!initExport())
44         {
45                 clearAll();
46                 return false;
47         }
48         cout<<"Writing textures"<<endl;
49         // start actual data export
50         writeTextures();
51         writeMaterialsAndModulators();
52         writeAllObjects();
53         writeLamps();
54         hasworld = writeWorld();
55         writeCamera();
56         writeRender();
57         
58         // clear for next call, before render to free some memory
59         clearAll();
60
61         if(!finishExport())
62         {
63                 G.afbreek = 1;  //stop render and anim if doing so
64                 return false;
65         }
66         else return true;
67 }
68
69
70 // find object by name in global scene (+'OB'!)
71 Object* yafrayRender_t::findObject(const char* name)
72 {
73         Base* bs = (Base*)G.scene->base.first;
74         while (bs) {
75           Object* obj = bs->object;
76                 if (!strcmp(name, obj->id.name)) return obj;
77                 bs = bs->next;
78         }
79         return NULL;
80 }
81
82 // gets all unique face materials & textures,
83 // and sorts the facelist rejecting anything that is not a quad or tri,
84 // as well as associating them again with the original Object.
85 bool yafrayRender_t::getAllMatTexObs()
86 {
87
88         VlakRen* vlr;
89
90         for (int i=0;i<R.totvlak;i++) {
91
92                 if ((i & 255)==0) vlr=R.blovl[i>>8]; else vlr++;
93
94                 // ---- The materials & textures
95                 // in this case, probably every face has a material assigned, which can be the default material,
96                 // so checking that this is !0 is probably not necessary, but just in case...
97                 Material* matr = vlr->mat;
98                 if (matr) {
99                         // The default assigned material seems to be nameless, no MA id, an empty string.
100                         // Since this name is needed in yafray, make it 'blender_default'
101                         if (strlen(matr->id.name)==0)
102                                 used_materials["blender_default"] = matr;
103                         else
104                                 used_materials[matr->id.name] = matr; // <-- full name to avoid name collision in yafray
105                                 //used_materials[matr->id.name+2] = matr;       // skip 'MA' id
106                         // textures, all active channels
107                         for (int m=0;m<8;m++) {
108                                 if (matr->septex & (1<<m)) continue;    // only active channels
109                                 MTex* mx = matr->mtex[m];
110                                 // if no mtex, ignore
111                                 if (mx==NULL) continue;
112                                 // if no tex, ignore
113                                 Tex* tx = mx->tex;
114                                 if (tx==NULL) continue;
115                                 short txtp = tx->type;
116                                 // if texture type not available in yafray, ignore
117                                 if ((txtp!=TEX_STUCCI) &&
118                                                 (txtp!=TEX_CLOUDS) &&
119                                                 (txtp!=TEX_WOOD) &&
120                                                 (txtp!=TEX_MARBLE) &&
121                                                 (txtp!=TEX_IMAGE)) continue;
122                                 // in the case of an image texture, check that there is an actual image, otherwise ignore
123                                 if ((txtp & TEX_IMAGE) && (!tx->ima)) continue;
124                                 used_textures[tx->id.name] = make_pair(matr, mx); // <-- full name to avoid name collision in yafray
125                                 //used_textures[tx->id.name+2] = make_pair(matr, mx);
126                         }
127                 }
128
129                 // make list of faces per object, ignore <3 vert faces, duplicate vertex sorting done later
130                 // make sure null object pointers are ignored
131                 if (vlr->ob) {
132                         int nv = 0;     // number of vertices
133                         if (vlr->v4) nv=4; else if (vlr->v3) nv=3;
134                         if (nv) all_objects[vlr->ob].push_back(vlr);
135                 }
136                 //else cout << "WARNING: VlakRen struct with null obj.ptr!\n";
137
138         }
139
140         // in case dupliMtx_list not empty, make sure that there is at least one source object
141         // in all_objects with the name given in dupliMtx_list
142         if (!dupliMtx_list.empty()) {
143
144                 for (map<Object*, vector<VlakRen*> >::const_iterator obn=all_objects.begin();
145                         obn!=all_objects.end();++obn)
146                 {
147                         Object* obj = obn->first;
148                         string obname = obj->id.name;
149                         if (dupliMtx_list.find(obname)!=dupliMtx_list.end()) dup_srcob[obname] = obj;
150                 }
151
152                 // if the name reference list is empty, return now, something was seriously wrong
153                 if (dup_srcob.empty()) {
154                   // error() doesn't work to well, when switching from Blender to console at least, so use stdout instead
155                         cout << "ERROR: Duplilist non_empty, but no srcobs\n";
156                         return false;
157                 }
158         }
159
160         return true;
161 }
162
163
164
165 void yafrayRender_t::addDupliMtx(Object* obj)
166 {
167         for (int i=0;i<4;i++)
168                 for (int j=0;j<4;j++)
169                         dupliMtx_list[string(obj->id.name)].push_back(obj->obmat[i][j]);
170 }
171
172
173 bool yafrayRender_t::objectKnownData(Object* obj)
174 {
175         // if object data already known, no need to include in renderlist, otherwise save object datapointer
176         if (objectData.find(obj->data)!=objectData.end()) {
177                 Object* orgob = objectData[obj->data];
178                 // first save original object matrix in dupliMtx_list, if not added yet
179                 if (dupliMtx_list.find(orgob->id.name)==dupliMtx_list.end()) {
180                         cout << "Added original matrix\n";
181                         addDupliMtx(orgob);
182                 }
183                 // then save matrix of linked object in dupliMtx_list, using name of ORIGINAL object
184                 for (int i=0;i<4;i++)
185                         for (int j=0;j<4;j++)
186                                 dupliMtx_list[string(orgob->id.name)].push_back(obj->obmat[i][j]);
187                 return true;
188         }
189         // object not known yet
190         objectData[obj->data] = obj;
191         return false;
192 }