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