db9fb7ccc720c5869b023c6e89de6cec4d3b44c3
[blender.git] / source / blender / yafray / intern / export_Plugin.cpp
1 #include "export_Plugin.h"
2
3 #include <math.h>
4
5 #include <cstring>
6
7 using namespace std;
8
9
10 #ifdef WIN32 
11 #define WIN32_SKIP_HKEY_PROTECTION
12 #include "BLI_winstuff.h"
13
14 #ifndef FILE_MAXDIR
15 #define FILE_MAXDIR  160
16 #endif
17
18 #ifndef FILE_MAXFILE
19 #define FILE_MAXFILE 80
20 #endif
21
22
23 static string find_path()
24 {
25         HKEY    hkey;
26         DWORD dwType, dwSize;
27
28         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\YafRay Team\\YafRay",0,KEY_READ,&hkey)==ERROR_SUCCESS)
29         {
30                 dwType = REG_EXPAND_SZ;
31                 dwSize = MAX_PATH;
32                 DWORD dwStat;
33
34                 char *pInstallDir=new char[MAX_PATH];
35
36                 dwStat=RegQueryValueEx(hkey, TEXT("InstallDir"), 
37                         NULL, NULL,(LPBYTE)pInstallDir, &dwSize);
38                 
39                 if (dwStat == NO_ERROR)
40                 {
41                         string res=pInstallDir;
42                         delete [] pInstallDir;
43                         return res;
44                 }
45                 else
46                         cout << "Couldn't READ \'InstallDir\' value. Is yafray correctly installed?\n";
47                 delete [] pInstallDir;
48
49                 RegCloseKey(hkey);
50         }       
51         else
52                 cout << "Couldn't FIND registry key for yafray, is it installed?\n";
53
54         return string("");
55
56 }
57
58 static int createDir(char* name)
59 {
60         if (BLI_exists(name))
61                 return 2;       //exists
62         if (CreateDirectory((LPCTSTR)(name), NULL)) {
63                 cout << "Directory: " << name << " created\n";
64                 return 1;       // created
65         }
66         else    {
67                 cout << "Could not create directory: " << name << endl;
68                 return 0;       // fail
69         }
70 }
71
72 extern "C" { extern char bprogname[]; }
73
74 // add drive character if not in path string, using blender executable location as reference
75 static void addDrive(string &path)
76 {
77         size_t sp = path.find_first_of(":");
78         if (sp==-1) {
79                 string blpath = bprogname;
80                 sp = blpath.find_first_of(":");
81                 if (sp!=-1) path = blpath.substr(0, sp+1) + path;
82         }
83 }
84
85 #else
86
87 #include <sys/stat.h>
88 #include <sys/types.h>
89 #include <sys/wait.h>
90 #include <signal.h>
91 #include <stdlib.h>
92 #include <unistd.h>
93 #endif
94
95 static string YafrayPath()
96 {
97 #ifdef WIN32
98         string path=find_path();
99         return path;
100 #else
101         static const char *alternative[]=
102         {
103                 "/usr/local/lib/",
104 #ifdef __x86_64__
105                 "/usr/lib64/",
106 #endif
107                 "/usr/lib/",
108                 NULL
109         };
110
111         for(int i=0;alternative[i]!=NULL;++i)
112         {
113                 string fp = string(alternative[i]) + "libyafrayplugin.so";
114                 struct stat st;
115                 if (stat(fp.c_str(), &st)<0) continue;
116                 if (st.st_mode & S_IROTH) return fp;
117         }
118         return "";
119 #endif
120 }
121
122 static string YafrayPluginPath()
123 {
124 #ifdef WIN32
125         return find_path()+"\\plugins";
126 #else
127         static const char *alternative[]=
128         {
129                 "/usr/local/lib/yafray",
130 #ifdef __x86_64__
131                 "/usr/lib64/yafray",
132 #endif
133                 "/usr/lib/yafray",
134                 NULL
135         };
136
137         for(int i=0;alternative[i]!=NULL;++i)
138         {
139                 struct stat st;
140                 if (stat(alternative[i], &st)<0) continue;
141                 if (S_ISDIR(st.st_mode) && (st.st_mode & S_IXOTH)) return alternative[i];
142         }
143         return "";
144 #endif
145 }
146
147
148
149 yafrayPluginRender_t::~yafrayPluginRender_t()
150 {
151         if (yafrayGate!=NULL) delete yafrayGate;
152         if (handle!=NULL) PIL_dynlib_close(handle);
153 #ifdef WIN32
154         if (corehandle!=NULL) PIL_dynlib_close(corehandle);
155 #endif
156 }
157
158 bool yafrayPluginRender_t::initExport()
159 {
160         // bug #1897: when forcing render without yafray present, handle can be valid,
161         // but find_symbol might have failed, trying second time will crash.
162         // So make sure plugin loaded correctly and only get handle once.
163         if ((!plugin_loaded) || (handle==NULL))
164         {
165                 string location = YafrayPath();
166 #ifdef WIN32
167                 /* Win 32 loader cannot find needed libs in yafray dir, so we have to load them
168                  * by hand. This could be fixed using setdlldirectory function, but it is not
169                  * available in all win32 versions
170                  */
171                 corehandle = PIL_dynlib_open((char *)(location + "\\yafraycore.dll").c_str());
172                 if (corehandle==NULL)
173                 {
174                         char *err = PIL_dynlib_get_error_as_string(corehandle);
175                         if (err) cerr << "Error loading yafray plugin: " << err << endl;
176                         else cerr << "Error loading yafray plugin: Unknown." << endl;
177                         return false;
178                 }
179                 location += "\\yafrayplugin.dll";
180 #endif
181
182                 if (handle==NULL) {
183                         handle = PIL_dynlib_open((char *)location.c_str());
184                         if (handle==NULL)
185                         {
186                                 cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl;
187                                 return false;
188                         }
189                 }
190                 yafray::yafrayConstructor *constructor;
191                 constructor = (yafray::yafrayConstructor *)PIL_dynlib_find_symbol(handle, YAFRAY_SYMBOL);
192                 if (constructor==NULL)
193                 {
194                         cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl;
195                         return false;
196                 }
197                 yafrayGate = constructor(re->r.threads, YafrayPluginPath());
198                 
199                 cout << "YafRay plugin loaded" << endl;
200                 plugin_loaded = true;
201         }
202         
203         return true;
204 }
205
206 bool yafrayPluginRender_t::writeRender()
207 {
208         yafray::paramMap_t params;
209         params["camera_name"]=yafray::parameter_t("MAINCAM");
210         params["raydepth"]=yafray::parameter_t((float)re->r.YF_raydepth);
211         params["gamma"]=yafray::parameter_t(re->r.YF_gamma);
212         params["exposure"]=yafray::parameter_t(re->r.YF_exposure);
213         if (re->r.YF_AA)
214         {
215                 params["AA_passes"] = yafray::parameter_t((int)re->r.YF_AApasses);
216                 params["AA_minsamples"] = yafray::parameter_t(re->r.YF_AAsamples);
217                 params["AA_pixelwidth"] = yafray::parameter_t(re->r.YF_AApixelsize);
218                 params["AA_threshold"] = yafray::parameter_t(re->r.YF_AAthreshold);
219         }
220         else
221         {
222                 // removed the default AA settings for midquality GI, better leave it to user
223                 if ((re->r.mode & R_OSA) && (re->r.osa)) 
224                 {
225                         params["AA_passes"] = yafray::parameter_t((re->r.osa & 3)==0 ? (re->r.osa >> 2) : 1);
226                         params["AA_minsamples"] = yafray::parameter_t((re->r.osa & 3)==0 ? 4 : re->r.osa);
227                 }
228                 else 
229                 {
230                         params["AA_passes"] = yafray::parameter_t(0);
231                         params["AA_minsamples"] = yafray::parameter_t(1);
232                 }
233                 params["AA_pixelwidth"] = yafray::parameter_t(1.5);
234                 params["AA_threshold"] = yafray::parameter_t(0.05f);
235         }
236         if (re->r.mode & R_BORDER)
237         {
238                 params["border_xmin"] = yafray::parameter_t(2.f*re->r.border.xmin - 1.f);
239                 params["border_xmax"] = yafray::parameter_t(2.f*re->r.border.xmax - 1.f);
240                 params["border_ymin"] = yafray::parameter_t(2.f*re->r.border.ymin - 1.f);
241                 params["border_ymax"] = yafray::parameter_t(2.f*re->r.border.ymax - 1.f);
242         }
243         if (hasworld) {
244                 World *world = G.scene->world;
245                 if (world->mode & WO_MIST) {
246                         // basic fog
247                         float fd = world->mistdist;
248                         if (fd>0) fd=1.f/fd; else fd=1;
249                         params["fog_density"] = yafray::parameter_t(fd);
250                         params["fog_color"] = yafray::parameter_t(yafray::color_t(world->horr, world->horg, world->horb));
251                 }
252                 params["background_name"] = yafray::parameter_t("world_background");
253         }
254         params["bias"] = yafray::parameter_t(re->r.YF_raybias);
255         params["clamp_rgb"] = yafray::parameter_t((re->r.YF_clamprgb==0) ? "on" : "off");
256         // lynx request
257         params["threads"] = yafray::parameter_t((int)re->r.threads);
258         blenderYafrayOutput_t output(re);
259         yafrayGate->render(params, output);
260         cout << "render finished" << endl;
261         yafrayGate->clear();
262         return true;
263 }
264
265 bool yafrayPluginRender_t::finishExport()
266 {
267         return true;
268 }
269
270
271 // displayImage() not for plugin, see putPixel() below
272
273 #ifdef WIN32
274 #define MAXPATHLEN MAX_PATH
275 #else
276 #include <sys/param.h>
277 #endif
278 static void adjustPath(string &path)
279 {
280         // if relative, expand to full path
281         char cpath[MAXPATHLEN];
282         strcpy(cpath, path.c_str());
283         BLI_convertstringcode(cpath, G.sce);
284         path = cpath;
285 #ifdef WIN32
286         // add drive char if not there
287         addDrive(path);
288 #endif
289 }
290
291
292 static string noise2string(short nbtype)
293 {
294         switch (nbtype) {
295                 case TEX_BLENDER:
296                         return "blender";
297                 case TEX_STDPERLIN:
298                         return "stdperlin";
299                 case TEX_VORONOI_F1:
300                         return "voronoi_f1";
301                 case TEX_VORONOI_F2:
302                         return "voronoi_f2";
303                 case TEX_VORONOI_F3:
304                         return "voronoi_f3";
305                 case TEX_VORONOI_F4:
306                         return "voronoi_f4";
307                 case TEX_VORONOI_F2F1:
308                         return "voronoi_f2f1";
309                 case TEX_VORONOI_CRACKLE:
310                         return "voronoi_crackle";
311                 case TEX_CELLNOISE:
312                         return "cellnoise";
313                 default:
314                 case TEX_NEWPERLIN:
315                         return "newperlin";
316         }
317 }
318
319 void yafrayPluginRender_t::writeTextures()
320 {
321         // used to keep track of images already written
322         // (to avoid duplicates if also in imagetex for material TexFace texture)
323         set<Image*> dupimg;
324
325         yafray::paramMap_t params;
326         list<yafray::paramMap_t> lparams;
327         for (map<string, MTex*>::const_iterator blendtex=used_textures.begin();
328                                                 blendtex!=used_textures.end();++blendtex) 
329         {
330                 lparams.clear();
331                 params.clear();
332                 
333                 MTex* mtex = blendtex->second;
334                 Tex* tex = mtex->tex;
335                 // name is image name instead of texture name when type is image (see TEX_IMAGE case below)
336                 // (done because of possible combinations of 'TexFace' images and regular image textures, to avoid duplicates)
337                 if (tex->type!=TEX_IMAGE) params["name"] = yafray::parameter_t(blendtex->first);
338
339                 float nsz = tex->noisesize;
340                 if (nsz!=0.f) nsz=1.f/nsz;
341
342                 // noisebasis type
343                 string ntype = noise2string(tex->noisebasis);
344                 string ts, hardnoise=(tex->noisetype==TEX_NOISESOFT) ? "off" : "on";
345
346                 switch (tex->type) {
347                         case TEX_STUCCI:
348                                 // stucci is clouds as bump, only difference is an extra parameter to handle wall in/out
349                                 // turbulence value is not used, so for large values will not match well
350                         case TEX_CLOUDS: {
351                                 params["type"] = yafray::parameter_t("clouds");
352                                 params["size"] = yafray::parameter_t(nsz);
353                                 params["hard"] = yafray::parameter_t(hardnoise);
354                                 if (tex->type==TEX_STUCCI) {
355                                         if (tex->stype==1)
356                                                 ts = "positive";
357                                         else if (tex->stype==2)
358                                                 ts = "negative";
359                                         else ts = "none";
360                                         params["bias"] = yafray::parameter_t(ts);
361                                         params["depth"] = yafray::parameter_t(0);       // for stucci always 0
362                                 }
363                                 else params["depth"] = yafray::parameter_t(tex->noisedepth);
364                                 params["color_type"] = yafray::parameter_t(tex->stype);
365                                 params["noise_type"] = yafray::parameter_t(ntype);
366                                 break;
367                         }
368                         case TEX_WOOD:
369                         {
370                                 params["type"] = yafray::parameter_t("wood");
371                                 // blender does not use depth value for wood, always 0
372                                 params["depth"] = yafray::parameter_t(0);
373                                 float turb = (tex->stype<2) ? 0.0 : tex->turbul;
374                                 params["turbulence"] = yafray::parameter_t(turb);
375                                 params["size"] = yafray::parameter_t(nsz);
376                                 params["hard"] = yafray::parameter_t(hardnoise);
377                                 ts = (tex->stype & 1) ? "rings" : "bands";      //stype 1&3 ringtype
378                                 params["wood_type"] = yafray::parameter_t(ts);
379                                 params["noise_type"] = yafray::parameter_t(ntype);
380                                 // shape parameter, for some reason noisebasis2 is used...
381                                 ts = "sin";
382                                 if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
383                                 params["shape"] = yafray::parameter_t(ts);
384                                 break;
385                         }
386                         case TEX_MARBLE: 
387                         {
388                                 params["type"] = yafray::parameter_t("marble");
389                                 params["depth"] = yafray::parameter_t(tex->noisedepth);
390                                 params["turbulence"] = yafray::parameter_t(tex->turbul);
391                                 params["size"] = yafray::parameter_t(nsz);
392                                 params["hard"] = yafray::parameter_t(hardnoise);
393                                 params["sharpness"] = yafray::parameter_t((float)(1<<tex->stype));
394                                 params["noise_type"] = yafray::parameter_t(ntype);
395                                 ts = "sin";
396                                 if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
397                                 params["shape"] = yafray::parameter_t(ts);
398                                 break;
399                         }
400                         case TEX_VORONOI:
401                         {
402                                 params["type"] = yafray::parameter_t("voronoi");
403                                 ts = "int";
404                                 if (tex->vn_coltype==1)
405                                         ts = "col1";
406                                 else if (tex->vn_coltype==2)
407                                         ts = "col2";
408                                 else if (tex->vn_coltype==3)
409                                         ts = "col3";
410                                 params["color_type"] = yafray::parameter_t(ts);
411                                 params["weight1"] = yafray::parameter_t(tex->vn_w1);
412                                 params["weight2"] = yafray::parameter_t(tex->vn_w2);
413                                 params["weight3"] = yafray::parameter_t(tex->vn_w3);
414                                 params["weight4"] = yafray::parameter_t(tex->vn_w4);
415                                 params["mk_exponent"] = yafray::parameter_t(tex->vn_mexp);
416                                 params["intensity"] = yafray::parameter_t(tex->ns_outscale);
417                                 params["size"] = yafray::parameter_t(nsz);
418                                 ts = "actual";
419                                 if (tex->vn_distm==TEX_DISTANCE_SQUARED)
420                                         ts = "squared";
421                                 else if (tex->vn_distm==TEX_MANHATTAN)
422                                         ts = "manhattan";
423                                 else if (tex->vn_distm==TEX_CHEBYCHEV)
424                                         ts = "chebychev";
425                                 else if (tex->vn_distm==TEX_MINKOVSKY_HALF)
426                                         ts = "minkovsky_half";
427                                 else if (tex->vn_distm==TEX_MINKOVSKY_FOUR)
428                                         ts = "minkovsky_four";
429                                 else if (tex->vn_distm==TEX_MINKOVSKY)
430                                         ts = "minkovsky";
431                                 params["distance_metric"] = yafray::parameter_t(ts);
432                                 break;
433                         }
434                         case TEX_MUSGRAVE:
435                         {
436                                 params["type"] = yafray::parameter_t("musgrave");
437                                 switch (tex->stype) {
438                                         case TEX_MFRACTAL:
439                                                 ts = "multifractal";
440                                                 break;
441                                         case TEX_RIDGEDMF:
442                                                 ts = "ridgedmf";
443                                                 break;
444                                         case TEX_HYBRIDMF:
445                                                 ts = "hybridmf";
446                                                 break;
447                                         case TEX_HTERRAIN:
448                                                 ts = "heteroterrain";
449                                                 break;
450                                         default:
451                                         case TEX_FBM:
452                                                 ts = "fBm";
453                                 }
454                                 params["musgrave_type"] = yafray::parameter_t(ts);
455                                 params["noise_type"] = yafray::parameter_t(ntype);
456                                 params["H"] = yafray::parameter_t(tex->mg_H);
457                                 params["lacunarity"] = yafray::parameter_t(tex->mg_lacunarity);
458                                 params["octaves"] = yafray::parameter_t(tex->mg_octaves);
459                                 if ((tex->stype==TEX_HTERRAIN) || (tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF)) {
460                                         params["offset"] = yafray::parameter_t(tex->mg_offset);
461                                         if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF))
462                                                 params["gain"] = yafray::parameter_t(tex->mg_gain);
463                                 }
464                                 params["size"] = yafray::parameter_t(nsz);
465                                 params["intensity"] = yafray::parameter_t(tex->ns_outscale);
466                                 break;
467                         }
468                         case TEX_DISTNOISE:
469                         {
470                                 params["type"] = yafray::parameter_t("distorted_noise");
471                                 params["distort"] = yafray::parameter_t(tex->dist_amount);
472                                 params["size"] = yafray::parameter_t(nsz);
473                                 params["noise_type1"] = yafray::parameter_t(ntype);
474                                 params["noise_type2"] = yafray::parameter_t(noise2string(tex->noisebasis2));
475                                 break;
476                         }
477                         case TEX_BLEND:
478                         {
479                                 params["type"] = yafray::parameter_t("gradient");
480                                 switch (tex->stype) {
481                                         case 1:  ts="quadratic"; break;
482                                         case 2:  ts="cubic";     break;
483                                         case 3:  ts="diagonal";  break;
484                                         case 4:  ts="sphere";    break;
485                                         case 5:  ts="halo";      break;
486                                         default:
487                                         case 0:  ts="linear";    break;
488                                 }
489                                 params["gradient_type"] = yafray::parameter_t(ts);
490                                 if (tex->flag & TEX_FLIPBLEND) ts="on"; else ts="off";
491                                 params["flip_xy"] = yafray::parameter_t(ts);
492                                 break;
493                         }
494                         case TEX_NOISE:
495                         {
496                                 params["type"] = yafray::parameter_t("random_noise");
497                                 params["depth"] = yafray::parameter_t(tex->noisedepth);
498                                 break;
499                         }
500                         case TEX_IMAGE: 
501                         {
502                                 Image* ima = tex->ima;
503                                 if (ima) {
504                                         // remember image to avoid duplicates later if also in imagetex
505                                         // (formerly done by removing from imagetex, but need image/material link)
506                                         dupimg.insert(ima);
507                                         params["type"] = yafray::parameter_t("image");
508                                         params["name"] = yafray::parameter_t(ima->id.name);
509                                         string texpath = ima->name;
510                                         adjustPath(texpath);
511                                         params["filename"] = yafray::parameter_t(texpath);
512                                         params["interpolate"] = yafray::parameter_t((tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none");
513                                 }
514                                 break;
515                         }
516                         default:
517                                 cout << "Unsupported texture type\n";
518                 }
519                 yafrayGate->addShader(params, lparams);
520
521                 // colorbands
522                 if (tex->flag & TEX_COLORBAND) 
523                 {
524                         ColorBand* cb = tex->coba;
525                         if (cb) 
526                         {
527                                 lparams.clear();
528                                 params.clear();
529                                 params["type"] = yafray::parameter_t("colorband");
530                                 params["name"] = yafray::parameter_t(blendtex->first + "_coba");
531                                 params["input"] = yafray::parameter_t(blendtex->first);
532                                 for (int i=0;i<cb->tot;i++) 
533                                 {
534                                         yafray::paramMap_t mparams;
535                                         mparams["value"] = yafray::parameter_t(cb->data[i].pos);
536                                         mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r,
537                                                                                                                                                                                                                                                                 cb->data[i].g,
538                                                                                                                                                                                                                                                                 cb->data[i].b,
539                                                                                                                                                                                                                                                                 cb->data[i].a));
540                                         lparams.push_back(mparams);
541                                 }
542                                 yafrayGate->addShader(params, lparams);
543                         }
544                 }
545
546         }
547
548         // If used, textures for the material 'TexFace' case
549         if (!imagetex.empty()) {
550                 for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
551                                         imgtex!=imagetex.end();++imgtex)
552                 {
553                         // skip if already written above
554                         if (dupimg.find(imgtex->first)==dupimg.end()) {
555                                 lparams.clear();
556                                 params.clear();
557                                 params["name"] = yafray::parameter_t(imgtex->first->id.name);
558                                 params["type"] = yafray::parameter_t("image");
559                                 string texpath(imgtex->first->name);
560                                 adjustPath(texpath);
561                                 params["filename"] = yafray::parameter_t(texpath);
562                                 yafrayGate->addShader(params, lparams);
563                         }
564                 }
565         }
566
567 }
568
569
570 void yafrayPluginRender_t::writeShader(const string &shader_name, Material* matr, const string &facetexname)
571 {
572         yafray::paramMap_t params;
573         list<yafray::paramMap_t> lparams;
574
575         // if material has ramps, export colorbands first
576         if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
577         {
578                 // both colorbands without input shader
579                 ColorBand* cb = matr->ramp_col;
580                 if ((matr->mode & MA_RAMP_COL) && (cb!=NULL))
581                 {
582                         params["type"] = yafray::parameter_t("colorband");
583                         params["name"] = yafray::parameter_t(shader_name+"_difframp");
584                         for (int i=0;i<cb->tot;i++) {
585                                 yafray::paramMap_t mparams;
586                                 mparams["value"] = yafray::parameter_t(cb->data[i].pos);
587                                 mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a));
588                                 lparams.push_back(mparams);
589                         }
590                         yafrayGate->addShader(params, lparams);
591                 }
592                 cb = matr->ramp_spec;
593                 if ((matr->mode & MA_RAMP_SPEC) && (cb!=NULL))
594                 {
595                         lparams.clear();
596                         params.clear();
597                         params["type"] = yafray::parameter_t("colorband");
598                         params["name"] = yafray::parameter_t(shader_name+"_specramp");
599                         for (int i=0;i<cb->tot;i++) {
600                                 yafray::paramMap_t mparams;
601                                 mparams["value"] = yafray::parameter_t(cb->data[i].pos);
602                                 mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a));
603                                 lparams.push_back(mparams);
604                         }
605                         yafrayGate->addShader(params, lparams);
606                 }
607                 lparams.clear();
608                 params.clear();
609         }
610
611         params["type"] = yafray::parameter_t("blendershader");
612         params["name"] = yafray::parameter_t(shader_name);
613         params["color"] = yafray::parameter_t(yafray::color_t(matr->r, matr->g, matr->b));
614         float sr=matr->specr, sg=matr->specg, sb=matr->specb;
615         if (matr->spec_shader==MA_SPEC_WARDISO) {
616                 // ........
617                 sr /= M_PI;
618                 sg /= M_PI;
619                 sb /= M_PI;
620         }
621         params["specular_color"] = yafray::parameter_t(yafray::color_t(sr, sg, sb));
622         params["mirror_color"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb));
623         params["diffuse_reflect"] = yafray::parameter_t(matr->ref);
624         params["specular_amount"] = yafray::parameter_t(matr->spec);
625         params["alpha"] = yafray::parameter_t(matr->alpha);
626         
627         // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
628         float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
629         params["emit"]=yafray::parameter_t(matr->emit*bg_mult);
630
631         // reflection/refraction
632         if ( (matr->mode & MA_RAYMIRROR) || (matr->mode & MA_RAYTRANSP) )
633                 params["IOR"] = yafray::parameter_t(matr->ang);
634
635         if (matr->mode & MA_RAYMIRROR)
636         {
637                 // Sofar yafray's min_refle parameter (which misleadingly actually controls fresnel reflection offset)
638                 // has been mapped to Blender's ray_mirror parameter.
639                 // This causes it be be misinterpreted and misused as a reflection amount control however.
640                 // Besides that, it also causes extra complications for the yafray Blendershader.
641                 // So added an actual amount of reflection parameter instead, and another
642                 // extra parameter 'frsOfs' to actually control fresnel offset (re-uses Blender fresnel_mir_i param).
643                 params["reflect"] = yafray::parameter_t("on");
644                 params["reflect_amount"] = yafray::parameter_t(matr->ray_mirror);
645                 float fo = 1.f-(matr->fresnel_mir_i-1.f)*0.25f; // blender param range [1,5], also here reversed (1 in Blender -> no fresnel)
646                 params["fresnel_offset"] = yafray::parameter_t(fo);
647
648                 // for backward compatibility, also add old 'reflected' parameter, copy of mirror_color
649                 params["reflected"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb));
650                 // same for 'min_refle' param. Instead of the ray_mirror parameter that was used before, since now
651                 // the parameter's function is taken over by the fresnel offset parameter, use that instead.
652                 params["min_refle"] = yafray::parameter_t(fo);
653
654         }
655
656         if (matr->mode & MA_RAYTRANSP) 
657         {
658                 params["refract"] = yafray::parameter_t("on");
659                 params["transmit_filter"] = yafray::parameter_t(matr->filter);
660                 // tir on by default
661                 params["tir"] = yafray::parameter_t("on");
662
663                 // transmit absorption color
664                 // to make things easier(?) for user it now specifies the actual color at 1 unit / YF_dscale of distance
665                 const float maxlog = -log(1e-38);
666                 float ar = (matr->YF_ar>0) ? -log(matr->YF_ar) : maxlog;
667                 float ag = (matr->YF_ag>0) ? -log(matr->YF_ag) : maxlog;
668                 float ab = (matr->YF_ab>0) ? -log(matr->YF_ab) : maxlog;
669                 float sc = matr->YF_dscale;
670                 if (sc!=0.f) sc=1.f/sc;
671                 params["absorption"] = yafray::parameter_t(yafray::color_t(ar*sc, ag*sc, ab*sc));
672                 // dispersion
673                 params["dispersion_power"] = yafray::parameter_t(matr->YF_dpwr);
674                 params["dispersion_samples"] = yafray::parameter_t(matr->YF_dsmp);
675                 params["dispersion_jitter"] = yafray::parameter_t(matr->YF_djit ? "on" : "off");
676
677                 // for backward compatibility, also add old 'transmitted' parameter, copy of 'color' * (1-alpha)
678                 float na = 1.f-matr->alpha;
679                 params["transmitted"] = yafray::parameter_t(yafray::color_t(matr->r*na, matr->g*na, matr->b*na));
680         }
681
682         string Mmode = "";
683         if (matr->mode & MA_TRACEBLE) Mmode += "traceable";
684         if (matr->mode & MA_SHADOW) Mmode += " shadow";
685         if (matr->mode & MA_SHLESS) Mmode += " shadeless";
686         if (matr->mode & MA_VERTEXCOL) Mmode += " vcol_light";
687         if (matr->mode & MA_VERTEXCOLP) Mmode += " vcol_paint";
688         if (matr->mode & MA_ZTRA) Mmode += " ztransp";
689         if (matr->mode & MA_ONLYSHADOW) Mmode += " onlyshadow";
690         if (Mmode!="") params["matmodes"] = yafray::parameter_t(Mmode);
691
692         // diffuse & specular brdf, lambert/cooktorr defaults
693         // diffuse
694         if (matr->diff_shader==MA_DIFF_ORENNAYAR) {
695                 params["diffuse_brdf"] = yafray::parameter_t("oren_nayar");
696                 params["roughness"] = yafray::parameter_t(matr->roughness);
697         }
698         else if (matr->diff_shader==MA_DIFF_TOON) {
699                 params["diffuse_brdf"] = yafray::parameter_t("toon");
700                 params["toondiffuse_size"] = yafray::parameter_t(matr->param[0]);
701                 params["toondiffuse_smooth"] = yafray::parameter_t(matr->param[1]);
702         }
703         else if (matr->diff_shader==MA_DIFF_MINNAERT) {
704                 params["diffuse_brdf"] = yafray::parameter_t("minnaert");
705                 params["darkening"] = yafray::parameter_t(matr->darkness);
706         }
707         else params["diffuse_brdf"] = yafray::parameter_t("lambert");
708         // specular
709         if (matr->spec_shader==MA_SPEC_PHONG) {
710                 params["specular_brdf"] = yafray::parameter_t("phong");
711                 params["hard"] = yafray::parameter_t(matr->har);
712         }
713         else if (matr->spec_shader==MA_SPEC_BLINN) {
714                 params["specular_brdf"] = yafray::parameter_t("blinn");
715                 params["blinn_ior"] = yafray::parameter_t(matr->refrac);
716                 params["hard"] = yafray::parameter_t(matr->har);
717         }
718         else if (matr->spec_shader==MA_SPEC_TOON) {
719                 params["specular_brdf"] = yafray::parameter_t("toon");
720                 params["toonspecular_size"] = yafray::parameter_t(matr->param[2]);
721                 params["toonspecular_smooth"] = yafray::parameter_t(matr->param[3]);
722         }
723         else if (matr->spec_shader==MA_SPEC_WARDISO) {
724                 params["specular_brdf"] = yafray::parameter_t("ward");
725                 params["u_roughness"] = yafray::parameter_t(matr->rms);
726                 params["v_roughness"] = yafray::parameter_t(matr->rms);
727         }
728         else {
729                 params["specular_brdf"] = yafray::parameter_t("blender_cooktorr");
730                 params["hard"] = yafray::parameter_t(matr->har);
731         }
732
733         // ramps, if used
734         if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
735         {
736                 const string rm_blend[9] = {"mix", "add", "mul", "sub", "screen", "divide", "difference", "darken", "lighten"};
737                 const string rm_mode[4] = {"shader", "energy", "normal", "result"};
738                 // diffuse
739                 if ((matr->mode & MA_RAMP_COL) && (matr->ramp_col!=NULL))
740                 {
741                         params["diffuse_ramp"] = yafray::parameter_t(shader_name+"_difframp");
742                         params["diffuse_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_col]);
743                         params["diffuse_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_col]);
744                         params["diffuse_ramp_factor"] = yafray::parameter_t(matr->rampfac_col);
745                 }
746                 // specular
747                 if ((matr->mode & MA_RAMP_SPEC) && (matr->ramp_spec!=NULL)) {
748                         params["specular_ramp"] = yafray::parameter_t(shader_name+"_specramp");
749                         params["specular_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_spec]);
750                         params["specular_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_spec]);
751                         params["specular_ramp_factor"] = yafray::parameter_t(matr->rampfac_spec);
752                 }
753         }
754
755         // modulators
756         // first modulator is the texture of the face, if used (TexFace mode)
757         if (facetexname.length()!=0) {
758                         yafray::paramMap_t mparams;
759                         mparams["input"] = yafray::parameter_t(facetexname);
760                         mparams["color"] = yafray::parameter_t(1);
761                         lparams.push_back(mparams);
762         }
763         
764         for (int m2=0;m2<MAX_MTEX;m2++)
765         {
766                 if (matr->septex & (1<<m2)) continue;// all active channels
767                 // ignore null mtex
768                 MTex* mtex = matr->mtex[m2];
769                 if (mtex==NULL) continue;
770                 // ignore null tex
771                 Tex* tex = mtex->tex;
772                 if (tex==NULL) continue;
773
774                 map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
775                 if (mtexL!=used_textures.end()) 
776                 {
777                         yafray::paramMap_t mparams;
778                         // when no facetex used, shader_name is created from original material name
779                         char temp[32];
780                         sprintf(temp,"_map%d", m2);
781                         if (facetexname.length()!=0)
782                                 mparams["input"] = yafray::parameter_t(string(matr->id.name) + string(temp));
783                         else
784                                 mparams["input"] = yafray::parameter_t(shader_name + temp);
785
786                         // blendtype, would have been nice if the order would have been the same as for ramps...
787                         const string blendtype[MTEX_NUM_BLENDTYPES] = {"mix", "mul", "add", "sub", "divide", "darken", "difference", "lighten", "screen", "hue", "sat", "val", "color"};
788                         mparams["mode"] = yafray::parameter_t(blendtype[(int)mtex->blendtype]);
789
790                         // texture color (for use with MUL and/or no_rgb etc..)
791                         mparams["texcol"]=yafray::parameter_t(yafray::color_t(mtex->r,mtex->g,mtex->b));
792                         // texture contrast, brightness & color adjustment
793                         mparams["filtercolor"]=yafray::parameter_t(yafray::color_t(tex->rfac,tex->gfac,tex->bfac));
794                         mparams["contrast"]=yafray::parameter_t(tex->contrast);
795                         mparams["brightness"]=yafray::parameter_t(tex->bright);
796                         // all texture flags now are switches, having the value 1 or -1 (negative option)
797                         // the negative option only used for the intensity modulation options.
798
799                         // material (diffuse) color, amount controlled by colfac (see below)
800                         if (mtex->mapto & MAP_COL)
801                                 mparams["color"]=yafray::parameter_t(1.0);
802                         // bumpmapping
803                         if ((mtex->mapto & MAP_NORM) || (mtex->maptoneg & MAP_NORM)) 
804                         {
805                                 // for yafray, bump factor is negated (unless tex is stucci, not affected by 'Neg')
806                                 // scaled down quite a bit
807                                 float nf = mtex->norfac;
808                                 if (tex->type!=TEX_STUCCI) nf *= -1.f;
809                                 if (mtex->maptoneg & MAP_NORM) nf *= -1.f;
810                                 mparams["normal"] = yafray::parameter_t(nf/60.f);
811                         }
812
813                         // all blender texture modulation as switches, either 1 or -1 (negative state of button)
814                         // Csp, specular color modulation
815                         if (mtex->mapto & MAP_COLSPEC)
816                                 mparams["colspec"] = yafray::parameter_t(1.0);
817                         // CMir, mirror color  modulation
818                         if (mtex->mapto & MAP_COLMIR)
819                                 mparams["colmir"] = yafray::parameter_t(1.0);
820
821                         // Ref, diffuse reflection amount  modulation
822                         if ((mtex->mapto & MAP_REF) || (mtex->maptoneg & MAP_REF)) 
823                         {
824                                 int t = 1;
825                                 if (mtex->maptoneg & MAP_REF) t = -1;
826                                 mparams["difref"] = yafray::parameter_t(t);
827                         }
828
829                         // Spec, specular amount mod
830                         if ((mtex->mapto & MAP_SPEC) || (mtex->maptoneg & MAP_SPEC)) 
831                         {
832                                 int t = 1;
833                                 if (mtex->maptoneg & MAP_SPEC) t = -1;
834                                 mparams["specular"] = yafray::parameter_t(t);
835                         }
836
837                         // hardness modulation
838                         if ((mtex->mapto & MAP_HAR) || (mtex->maptoneg & MAP_HAR)) 
839                         {
840                                 int t = 1;
841                                 if (mtex->maptoneg & MAP_HAR) t = -1;
842                                 mparams["hard"] = yafray::parameter_t(t);
843                         }
844
845                         // alpha modulation
846                         if ((mtex->mapto & MAP_ALPHA) || (mtex->maptoneg & MAP_ALPHA)) 
847                         {
848                                 int t = 1;
849                                 if (mtex->maptoneg & MAP_ALPHA) t = -1;
850                                 mparams["alpha"] = yafray::parameter_t(t);
851                         }
852
853                         // emit modulation
854                         if ((mtex->mapto & MAP_EMIT) || (mtex->maptoneg & MAP_EMIT)) {
855                                 int t = 1;
856                                 if (mtex->maptoneg & MAP_EMIT) t = -1;
857                                 mparams["emit"] = yafray::parameter_t(t);
858                         }
859
860                         // raymir modulation
861                         if ((mtex->mapto & MAP_RAYMIRR) || (mtex->maptoneg & MAP_RAYMIRR)) {
862                                 int t = 1;
863                                 if (mtex->maptoneg & MAP_RAYMIRR) t = -1;
864                                 mparams["raymir"] = yafray::parameter_t(t);
865                         }
866
867                         // texture flag, combination of strings
868                         string ts;
869                         if (mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE)) {
870                                 ts = "";
871                                 if (mtex->texflag & MTEX_RGBTOINT) ts += "no_rgb ";
872                                 if (mtex->texflag & MTEX_STENCIL) ts += "stencil ";
873                                 if (mtex->texflag & MTEX_NEGATIVE) ts += "negative";
874                                 mparams["texflag"]=yafray::parameter_t(ts);
875                         }
876
877                         // colfac, controls amount of color modulation
878                         mparams["colfac"]=yafray::parameter_t(mtex->colfac);
879                         // def_var
880                         mparams["def_var"]=yafray::parameter_t(mtex->def_var);
881                         //varfac
882                         mparams["varfac"]=yafray::parameter_t(mtex->varfac);
883
884                         if ((tex->imaflag & (TEX_CALCALPHA | TEX_USEALPHA)) || (tex->flag & TEX_NEGALPHA)) 
885                         {
886                                 ts = "";
887                                 if (tex->imaflag & TEX_CALCALPHA) ts += "calc_alpha ";
888                                 if (tex->imaflag & TEX_USEALPHA) ts += "use_alpha ";
889                                 if (tex->flag & TEX_NEGALPHA) ts += "neg_alpha";
890                                 mparams["alpha_flag"] = yafray::parameter_t(ts);
891                         }
892
893                         // image as normalmap flag
894                         if (tex->imaflag & TEX_NORMALMAP) mparams["normalmap"] = yafray::parameter_t("on");
895
896                         lparams.push_back(mparams);
897                 }
898         }
899         yafrayGate->addShader(params, lparams);
900
901 }
902
903 // write all materials & modulators
904 void yafrayPluginRender_t::writeMaterialsAndModulators()
905 {
906         // shaders/mappers for regular texture (or non-texture) mode
907         // In case material has texface mode, and all faces have an image texture,
908         // this shader will not be used, but still be written
909         yafray::paramMap_t params;
910         list<yafray::paramMap_t> lparams;
911         for (map<string, Material*>::const_iterator blendmat=used_materials.begin();
912                 blendmat!=used_materials.end();++blendmat) 
913         {
914                 Material* matr = blendmat->second;
915                 // mapper(s)
916                 for (int m=0;m<MAX_MTEX;m++) 
917                 {
918                         if (matr->septex & (1<<m)) continue;// all active channels
919                         // ignore null mtex
920                         MTex* mtex = matr->mtex[m];
921                         if (mtex==NULL) continue;
922                         // ignore null tex
923                         Tex* tex = mtex->tex;
924                         if (tex==NULL) continue;
925
926                         map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
927                         if (mtexL!=used_textures.end()) 
928                         {
929                                 params.clear(); //!!!
930                                 lparams.clear();
931                                 char temp[32];
932                                 sprintf(temp, "_map%d", m);
933                                 params["type"] = yafray::parameter_t("blendermapper");
934                                 params["name"] = yafray::parameter_t(blendmat->first + string(temp));
935                                 if ((mtex->texco & TEXCO_OBJECT) || (mtex->texco & TEXCO_REFL) || (mtex->texco & TEXCO_NORM))
936                                 {
937                                         // For object, reflection & normal mapping, add the object matrix to the modulator,
938                                         // as in LF script, use camera matrix if no object specified.
939                                         // In this case this means the inverse of that matrix
940                                         float texmat[4][4], itexmat[4][4];
941                                         if ((mtex->texco & TEXCO_OBJECT) && (mtex->object))
942                                                 MTC_Mat4CpyMat4(texmat, mtex->object->obmat);
943                                         else    // also for refl. map
944                                                 MTC_Mat4CpyMat4(texmat, maincam_obj->obmat);
945                                         MTC_Mat4Invert(itexmat, texmat);
946 #define flp yafray::parameter_t
947                                         params["m00"]=flp(itexmat[0][0]);  params["m01"]=flp(itexmat[1][0]);
948                                         params["m02"]=flp(itexmat[2][0]);  params["m03"]=flp(itexmat[3][0]);
949                                         params["m10"]=flp(itexmat[0][1]);  params["m11"]=flp(itexmat[1][1]);
950                                         params["m12"]=flp(itexmat[2][1]);  params["m13"]=flp(itexmat[3][1]);
951                                         params["m20"]=flp(itexmat[0][2]);  params["m21"]=flp(itexmat[1][2]);
952                                         params["m22"]=flp(itexmat[2][2]);  params["m23"]=flp(itexmat[3][2]);
953                                         params["m30"]=flp(itexmat[0][3]);  params["m31"]=flp(itexmat[1][3]);
954                                         params["m32"]=flp(itexmat[2][3]);  params["m33"]=flp(itexmat[3][3]);
955 #undef flp
956                                 }
957                                 // use image name instead of texname when texture is image
958                                 if ((tex->type==TEX_IMAGE) && tex->ima)
959                                         params["input"] = yafray::parameter_t(tex->ima->id.name);
960                                 else if ((tex->flag & TEX_COLORBAND) & (tex->coba!=NULL))
961                                         params["input"] = yafray::parameter_t(mtexL->first + "_coba");
962                                 else
963                                         params["input"] = yafray::parameter_t(mtexL->first);
964
965                                 // texture size
966                                 params["sizex"] = yafray::parameter_t(mtex->size[0]);
967                                 params["sizey"] = yafray::parameter_t(mtex->size[1]);
968                                 params["sizez"] = yafray::parameter_t(mtex->size[2]);
969
970                                 // texture offset
971                                 params["ofsx"] = yafray::parameter_t(mtex->ofs[0]);
972                                 params["ofsy"] = yafray::parameter_t(mtex->ofs[1]);
973                                 params["ofsz"] = yafray::parameter_t(mtex->ofs[2]);
974
975                                 // texture coordinates, have to disable 'sticky' in Blender
976                                 if (mtex->texco & TEXCO_UV)
977                                         params["texco"] = yafray::parameter_t("uv");
978                                 else if ((mtex->texco & TEXCO_GLOB) || (mtex->texco & TEXCO_OBJECT))
979                                         // object mode is also set as global, but the object matrix 
980                                         // was specified above with <modulator..>
981                                         params["texco"] = yafray::parameter_t("global");
982                                 else if ((mtex->texco & TEXCO_ORCO) || (mtex->texco & TEXCO_STRAND))
983                                         // orco flag now used for 'strand'-mapping as well, see mesh code
984                                         params["texco"] = yafray::parameter_t("orco");
985                                 else if (mtex->texco & TEXCO_WINDOW)
986                                         params["texco"] = yafray::parameter_t("window");
987                                 else if (mtex->texco & TEXCO_NORM)
988                                         params["texco"] = yafray::parameter_t("normal");
989                                 else if (mtex->texco & TEXCO_REFL)
990                                         params["texco"] = yafray::parameter_t("reflect");
991
992                                 // texture projection axes, both image & procedural
993                                 string proj = "nxyz";           // 'n' for 'none'
994                                 params["proj_x"] = yafray::parameter_t(string(1,proj[mtex->projx]));
995                                 params["proj_y"] = yafray::parameter_t(string(1,proj[mtex->projy]));
996                                 params["proj_z"] = yafray::parameter_t(string(1,proj[mtex->projz]));
997
998                                 // texture mapping parameters only relevant to image type
999                                 if (tex->type==TEX_IMAGE) 
1000                                 {
1001                                         if (mtex->mapping==MTEX_FLAT)
1002                                                 params["mapping"] = yafray::parameter_t("flat");
1003                                         else if (mtex->mapping==MTEX_CUBE)
1004                                                 params["mapping"] = yafray::parameter_t("cube");
1005                                         else if (mtex->mapping==MTEX_TUBE)
1006                                                 params["mapping"] = yafray::parameter_t("tube");
1007                                         else if (mtex->mapping==MTEX_SPHERE)
1008                                                 params["mapping"] = yafray::parameter_t("sphere");
1009
1010                                         // repeat
1011                                         params["xrepeat"] = yafray::parameter_t(tex->xrepeat);
1012                                         params["yrepeat"] = yafray::parameter_t(tex->yrepeat);
1013
1014                                         // clipping
1015                                         if (tex->extend==TEX_EXTEND)
1016                                                 params["clipping"] = yafray::parameter_t("extend");
1017                                         else if (tex->extend==TEX_CLIP)
1018                                                 params["clipping"] = yafray::parameter_t("clip");
1019                                         else if (tex->extend==TEX_CLIPCUBE)
1020                                                 params["clipping"] = yafray::parameter_t("clipcube");
1021                                         else if (tex->extend==TEX_CHECKER) {
1022                                                 params["clipping"] = yafray::parameter_t("checker");
1023                                                 string ts = "";
1024                                                 if (tex->flag & TEX_CHECKER_ODD) ts += "odd";
1025                                                 if (tex->flag & TEX_CHECKER_EVEN) ts += " even";
1026                                                 params["checker_mode"] = yafray::parameter_t(ts);
1027                                                 params["checker_dist"] = yafray::parameter_t(tex->checkerdist);
1028                                         }
1029                                         else
1030                                                 params["clipping"] = yafray::parameter_t("repeat");
1031
1032                                         // crop min/max
1033                                         params["cropmin_x"] = yafray::parameter_t(tex->cropxmin);
1034                                         params["cropmin_y"] = yafray::parameter_t(tex->cropymin);
1035                                         params["cropmax_x"] = yafray::parameter_t(tex->cropxmax);
1036                                         params["cropmax_y"] = yafray::parameter_t(tex->cropymax);
1037
1038                                         // rot90 flag
1039                                         if (tex->imaflag & TEX_IMAROT) 
1040                                                 params["rot90"] = yafray::parameter_t("on");
1041                                         else
1042                                                 params["rot90"] = yafray::parameter_t("off");
1043                                 }
1044                                 yafrayGate->addShader(params, lparams);
1045                         }
1046                 }
1047
1048                 // shader + modulators
1049                 writeShader(blendmat->first, matr);
1050
1051         }
1052
1053                 // write the mappers & shaders for the TexFace case
1054         if (!imagetex.empty()) {
1055                 // Yafray doesn't have per-face-textures, only per-face-shaders,
1056                 // so create as many mappers/shaders as the images used by the object
1057                 params.clear();
1058                 lparams.clear();
1059                 int snum = 0;
1060                 for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
1061                                 imgtex!=imagetex.end();++imgtex)
1062                 {
1063
1064                         for (set<Material*>::const_iterator imgmat=imgtex->second.begin();
1065                                         imgmat!=imgtex->second.end();++imgmat)
1066                         {
1067                                 Material* matr = *imgmat;
1068                                 // mapper
1069                                 params["type"] = yafray::parameter_t("blendermapper");
1070                                 char temp[32];
1071                                 sprintf(temp, "_ftmap%d", snum);
1072                                 params["name"] = yafray::parameter_t(string(matr->id.name) + string(temp));
1073                                 params["input"] = yafray::parameter_t(imgtex->first->id.name);
1074                                 // all yafray default settings, except for texco, so no need to set others
1075                                 params["texco"] = yafray::parameter_t("uv");
1076                                 yafrayGate->addShader(params, lparams);
1077
1078                                 // shader, remember name, used later when writing per-face-shaders
1079                                 sprintf(temp, "_ftsha%d", snum);
1080                                 string shader_name = string(matr->id.name) + string(temp);
1081                                 imgtex_shader[string(matr->id.name) + string(imgtex->first->id.name)] = shader_name;
1082
1083                                 sprintf(temp, "_ftmap%d", snum++);
1084                                 string facetexname = string(matr->id.name) + string(temp);
1085                                 writeShader(shader_name, matr, facetexname);
1086                         }
1087
1088                 }
1089         }
1090
1091 }
1092
1093 void yafrayPluginRender_t::genUVcoords(vector<yafray::GFLOAT> &uvcoords, ObjectRen *obr, VlakRen *vlr, MTFace* uvc, bool comple)
1094 {
1095         if (uvc) 
1096         {
1097                 // tri uv split indices
1098                 int ui1=0, ui2=1, ui3=2;
1099                 if (vlr->flag & R_DIVIDE_24) {
1100                         ui3++;
1101                         if (vlr->flag & R_FACE_SPLIT) { ui1++;  ui2++; }
1102                 }
1103                 else if (vlr->flag & R_FACE_SPLIT) { ui2++;  ui3++; }
1104                 if (comple) {
1105                         ui1 = (ui1+2) & 3;
1106                         ui2 = (ui2+2) & 3;
1107                         ui3 = (ui3+2) & 3;
1108                 }
1109                 uvcoords.push_back(uvc->uv[ui1][0]);  uvcoords.push_back(1-uvc->uv[ui1][1]);
1110                 uvcoords.push_back(uvc->uv[ui2][0]);  uvcoords.push_back(1-uvc->uv[ui2][1]);
1111                 uvcoords.push_back(uvc->uv[ui3][0]);  uvcoords.push_back(1-uvc->uv[ui3][1]);
1112         }
1113         else
1114         {
1115                 uvcoords.push_back(0);  uvcoords.push_back(0);
1116                 uvcoords.push_back(0);  uvcoords.push_back(0);
1117                 uvcoords.push_back(0);  uvcoords.push_back(0);
1118         }
1119 }
1120
1121 void yafrayPluginRender_t::genVcol(vector<yafray::CFLOAT> &vcol, ObjectRen *obr, VlakRen *vlr, bool comple)
1122 {
1123         MCol *mcol= RE_vlakren_get_mcol(obr, vlr, obr->actmcol, NULL, 0);
1124
1125         if (mcol)
1126         {
1127                 // tri vcol split indices
1128                 int ui1=0, ui2=1, ui3=2;
1129                 if (vlr->flag & R_DIVIDE_24) {
1130                         ui3++;
1131                         if (vlr->flag & R_FACE_SPLIT) { ui1++;  ui2++; }
1132                 }
1133                 else if (vlr->flag & R_FACE_SPLIT) { ui2++;  ui3++; }
1134                 if (comple) {
1135                         ui1 = (ui1+2) & 3;
1136                         ui2 = (ui2+2) & 3;
1137                         ui3 = (ui3+2) & 3;
1138                 }
1139                 unsigned char* pt = reinterpret_cast<unsigned char*>(&mcol[ui1]);
1140                 vcol.push_back((float)pt[3]/255.f);  vcol.push_back((float)pt[2]/255.f);  vcol.push_back((float)pt[1]/255.f);
1141                 pt = reinterpret_cast<unsigned char*>(&mcol[ui2]);
1142                 vcol.push_back((float)pt[3]/255.f);  vcol.push_back((float)pt[2]/255.f);  vcol.push_back((float)pt[1]/255.f);
1143                 pt = reinterpret_cast<unsigned char*>(&mcol[ui3]);
1144                 vcol.push_back((float)pt[3]/255.f);  vcol.push_back((float)pt[2]/255.f);  vcol.push_back((float)pt[1]/255.f);
1145         }
1146         else
1147         {
1148                 vcol.push_back(0);  vcol.push_back(0);  vcol.push_back(0);
1149                 vcol.push_back(0);  vcol.push_back(0);  vcol.push_back(0);
1150                 vcol.push_back(0);  vcol.push_back(0);  vcol.push_back(0);
1151         }
1152 }
1153
1154 void yafrayPluginRender_t::genFace(vector<int> &faces,vector<string> &shaders,vector<int> &faceshader,
1155                                                                                                                 vector<yafray::GFLOAT> &uvcoords,vector<yafray::CFLOAT> &vcol,
1156                                                                                                                 map<VertRen*, int> &vert_idx,ObjectRen *obr,VlakRen *vlr,
1157                                                                                                                 int has_orco,bool has_uv)
1158 {
1159         Material* fmat = vlr->mat;
1160         bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0);
1161         string fmatname(fmat->id.name);
1162         // use name in imgtex_shader list if 'TexFace' enabled for this face material
1163         if (fmat->mode & MA_FACETEXTURE) {
1164                 MTFace* tface = RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
1165                 if (tface) {
1166                         Image* fimg = (Image*)tface->tpage;
1167                         if (fimg) fmatname = imgtex_shader[fmatname + string(fimg->id.name)];
1168                 }
1169         }
1170         else if (fmatname.length()==0) fmatname = "blender_default";
1171         bool newmat=true;
1172         for(unsigned int i=0;i<shaders.size();++i)
1173                 if(shaders[i]==fmatname)
1174                 {
1175                         newmat=false;
1176                         faceshader.push_back(i);
1177                         break;
1178                 }
1179         if(newmat)
1180         {
1181                 shaders.push_back(fmatname);
1182                 faceshader.push_back(shaders.size()-1);
1183         }
1184
1185         MTFace* uvc = RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); // possible uvcoords (v upside down)
1186         int idx1, idx2, idx3;
1187
1188         idx1 = vert_idx.find(vlr->v1)->second;
1189         idx2 = vert_idx.find(vlr->v2)->second;
1190         idx3 = vert_idx.find(vlr->v3)->second;
1191
1192         // make sure the indices point to the vertices when orco coords exported
1193         if (has_orco) { idx1*=2;  idx2*=2;  idx3*=2; }
1194
1195         faces.push_back(idx1);  faces.push_back(idx2);  faces.push_back(idx3);
1196
1197         if(has_uv) genUVcoords(uvcoords, obr, vlr, uvc);
1198         if (EXPORT_VCOL) genVcol(vcol, obr, vlr);
1199 }
1200
1201 void yafrayPluginRender_t::genCompleFace(vector<int> &faces,/*vector<string> &shaders,*/vector<int> &faceshader,
1202                                                                                                                 vector<yafray::GFLOAT> &uvcoords,vector<yafray::CFLOAT> &vcol,
1203                                                                                                                 map<VertRen*, int> &vert_idx,ObjectRen *obr,VlakRen *vlr,
1204                                                                                                                 int has_orco,bool has_uv)
1205 {
1206         Material* fmat = vlr->mat;
1207         bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0);
1208
1209         faceshader.push_back(faceshader.back());
1210         MTFace* uvc = RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); // possible uvcoords (v upside down)
1211         int idx1, idx2, idx3;
1212         idx1 = vert_idx.find(vlr->v3)->second;
1213         idx2 = vert_idx.find(vlr->v4)->second;
1214         idx3 = vert_idx.find(vlr->v1)->second;
1215
1216         // make sure the indices point to the vertices when orco coords exported
1217         if (has_orco) { idx1*=2;  idx2*=2;  idx3*=2; }
1218
1219         faces.push_back(idx1);  faces.push_back(idx2);  faces.push_back(idx3);
1220
1221         if (has_uv) genUVcoords(uvcoords, obr, vlr, uvc, true);
1222         if (EXPORT_VCOL) genVcol(vcol, obr, vlr, true);
1223 }
1224
1225 void yafrayPluginRender_t::genVertices(vector<yafray::point3d_t> &verts, int &vidx,
1226                                                                                                                                                          map<VertRen*, int> &vert_idx, ObjectRen *obr, VlakRen* vlr, int has_orco, Object* obj)
1227 {
1228         VertRen* ver;
1229         float tvec[3];  // for back2world transform
1230
1231         // for deformed objects, object->imat is no longer valid,
1232         // so have to create inverse render matrix ourselves here
1233         float mat[4][4], imat[4][4];
1234         MTC_Mat4MulMat4(mat, obj->obmat, re->viewmat);
1235         MTC_Mat4Invert(imat, mat);
1236
1237         if (vert_idx.find(vlr->v1)==vert_idx.end()) 
1238         {
1239                 vert_idx[vlr->v1] = vidx++;
1240                 ver = vlr->v1;
1241                 MTC_cp3Float(ver->co, tvec);
1242                 MTC_Mat4MulVecfl(imat, tvec);
1243                 verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
1244                 // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
1245                 if (has_orco==1)
1246                         verts.push_back(yafray::point3d_t(ver->accum));
1247                 else if (has_orco==2)
1248                         verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
1249         }
1250         if (vert_idx.find(vlr->v2)==vert_idx.end()) 
1251         {
1252                 vert_idx[vlr->v2] = vidx++;
1253                 ver = vlr->v2;
1254                 MTC_cp3Float(ver->co, tvec);
1255                 MTC_Mat4MulVecfl(imat, tvec);
1256                 verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
1257                 // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
1258                 if (has_orco==1)
1259                         verts.push_back(yafray::point3d_t(ver->accum));
1260                 else if (has_orco==2)
1261                         verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
1262         }
1263         if (vert_idx.find(vlr->v3)==vert_idx.end()) 
1264         {
1265                 vert_idx[vlr->v3] = vidx++;
1266                 ver = vlr->v3;
1267                 MTC_cp3Float(ver->co, tvec);
1268                 MTC_Mat4MulVecfl(imat, tvec);
1269                 verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
1270                 // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
1271                 if (has_orco==1)
1272                         verts.push_back(yafray::point3d_t(ver->accum));
1273                 else if (has_orco==2)
1274                         verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
1275         }
1276         if ((vlr->v4) && (vert_idx.find(vlr->v4)==vert_idx.end())) 
1277         {
1278                 vert_idx[vlr->v4] = vidx++;
1279                 ver = vlr->v4;
1280                 MTC_cp3Float(ver->co, tvec);
1281                 MTC_Mat4MulVecfl(imat, tvec);
1282                 verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
1283                 // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
1284                 if (has_orco==1)
1285                         verts.push_back(yafray::point3d_t(ver->accum));
1286                 else if (has_orco==2)
1287                         verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
1288         }
1289 }
1290
1291 void yafrayPluginRender_t::writeObject(Object* obj, ObjectRen *obr, const vector<VlakRen*> &VLR_list, const float obmat[4][4])
1292 {
1293         float mtr[4*4];
1294         mtr[0*4+0]=obmat[0][0];  mtr[0*4+1]=obmat[1][0];  mtr[0*4+2]=obmat[2][0];  mtr[0*4+3]=obmat[3][0];
1295         mtr[1*4+0]=obmat[0][1];  mtr[1*4+1]=obmat[1][1];  mtr[1*4+2]=obmat[2][1];  mtr[1*4+3]=obmat[3][1];
1296         mtr[2*4+0]=obmat[0][2];  mtr[2*4+1]=obmat[1][2];  mtr[2*4+2]=obmat[2][2];  mtr[2*4+3]=obmat[3][2];
1297         mtr[3*4+0]=obmat[0][3];  mtr[3*4+1]=obmat[1][3];  mtr[3*4+2]=obmat[2][3];  mtr[3*4+3]=obmat[3][3];
1298         yafrayGate->transformPush(mtr);
1299         
1300         VlakRen* face0 = VLR_list[0];
1301         Material* face0mat = face0->mat;
1302         
1303         bool castShadows = face0mat->mode & MA_TRACEBLE;
1304         float caus_IOR=1.0;
1305         yafray::color_t caus_tcolor(0.0, 0.0, 0.0), caus_rcolor(0.0, 0.0, 0.0);
1306         bool caus = (((face0->mat->mode & MA_RAYTRANSP) | (face0->mat->mode & MA_RAYMIRROR))!=0);
1307         if (caus) {
1308                 caus_IOR = face0mat->ang;
1309                 float tr = 1.0-face0mat->alpha;
1310                 caus_tcolor.set(face0mat->r*tr, face0mat->g*tr, face0mat->b*tr);
1311                 tr = face0mat->ray_mirror;
1312                 caus_rcolor.set(face0mat->mirr*tr, face0mat->mirg*tr, face0mat->mirb*tr);
1313         }
1314
1315         // Export orco coords test.
1316         // Previously was done by checking orco pointer, however this can be non-null but still not initialized.
1317         // Test the rendermaterial texco flag instead.
1318         // update2: bug #3193 it seems it has changed again with the introduction of static 'hair' particles,
1319         // now it uses the vert pointer again as an extra test to make sure there are orco coords available
1320         int has_orco = 0;
1321         if (face0mat->texco & TEXCO_STRAND)
1322                 has_orco = 1;
1323         else
1324                 has_orco = (((face0mat->texco & TEXCO_ORCO)!=0) && (face0->v1->orco!=NULL)) ? 2 : 0;
1325
1326         bool no_auto = true;    //in case non-mesh, or mesh has no autosmooth
1327         float sm_angle = 0.1f;
1328         if (obj->type==OB_MESH) 
1329         {
1330                 Mesh* mesh = (Mesh*)obj->data;
1331                 if (mesh->flag & ME_AUTOSMOOTH) {
1332                         sm_angle = mesh->smoothresh;
1333                         no_auto = false;
1334                 }
1335         }
1336         // this for non-mesh as well
1337         if (no_auto) {
1338                 // no per face smooth flag in yafray, if AutoSmooth not used, 
1339                 // use smooth flag of the first face instead
1340                 if (face0->flag & ME_SMOOTH) sm_angle=180;
1341         }
1342         vector<yafray::point3d_t> verts;
1343         vector<yafray::CFLOAT> vcol;
1344         // now all vertices
1345         map<VertRen*, int> vert_idx;    // for removing duplicate verts and creating an index list
1346         int vidx = 0;   // vertex index counter
1347         bool has_uv=false;
1348         for (vector<VlakRen*>::const_iterator fci=VLR_list.begin();
1349                                 fci!=VLR_list.end();++fci)
1350         {
1351                 VlakRen* vlr = *fci;
1352                 genVertices(verts, vidx, vert_idx, obr, vlr, has_orco, obj);
1353                 if(RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0)) has_uv=true;
1354         }
1355         // all faces using the index list created above
1356         vector<int> faces;
1357         vector<string> shaders;
1358         vector<int> faceshader;
1359         vector<yafray::GFLOAT> uvcoords;
1360         for (vector<VlakRen*>::const_iterator fci2=VLR_list.begin();
1361                                 fci2!=VLR_list.end();++fci2)
1362         {
1363                 VlakRen* vlr = *fci2;
1364                 genFace(faces, shaders, faceshader, uvcoords, vcol, vert_idx, obr, vlr, has_orco, has_uv);
1365                 if (vlr->v4) 
1366                         genCompleFace(faces, faceshader, uvcoords, vcol, vert_idx, obr, vlr, has_orco, has_uv);
1367         }
1368
1369         // using the ObjectRen database, contruct a new name if object has a parent.
1370         // This is done to prevent name clashes (group/library link related)
1371         string obname(obj->id.name);
1372         // previous implementation, keep around, in case this is still useful
1373         //if (obj->id.flag & (LIB_EXTERN|LIB_INDIRECT))obname = "lib_" + obname;
1374         ObjectRen *obren;
1375         for (obren = static_cast<ObjectRen*>(re->objecttable.first);
1376              obren; obren=static_cast<ObjectRen*>(obren->next))
1377         {
1378                 Object *db_ob = obren->ob, *db_par = obren->par;
1379                 if (db_ob==obj)
1380                         if ((db_ob!=NULL) && (db_par!=NULL)) {
1381                                 obname += "_" + string(db_par->id.name);
1382                                 break;
1383                         }
1384         }
1385
1386         yafrayGate->addObject_trimesh(obname, verts, faces, uvcoords, vcol,
1387                         shaders, faceshader, sm_angle, castShadows, true, true, caus, has_orco,
1388                         caus_rcolor, caus_tcolor, caus_IOR);
1389         yafrayGate->transformPop();
1390 }
1391
1392
1393 // write all objects
1394 void yafrayPluginRender_t::writeAllObjects()
1395 {
1396         // first all objects except dupliverts (and main instance object for dups)
1397         for (map<Object*, yafrayObjectRen >::const_iterator obi=all_objects.begin();
1398                         obi!=all_objects.end(); ++obi)
1399         {
1400           // skip main duplivert object if in dupliMtx_list, written later
1401                 Object* obj = obi->first;
1402                 if (dupliMtx_list.find(string(obj->id.name))!=dupliMtx_list.end()) continue;
1403                 writeObject(obj, obi->second.obr, obi->second.faces, obj->obmat);
1404         }
1405
1406         // Now all duplivert objects (if any) as instances of main object
1407         // The original object has been included in the VlakRen renderlist above (see convertBlenderScene.c)
1408         // but is written here which all other duplis are instances of.
1409         float obmat[4][4], cmat[4][4], imat[4][4], nmat[4][4];
1410         for (map<string, vector<float> >::const_iterator dupMtx=dupliMtx_list.begin();
1411                 dupMtx!=dupliMtx_list.end();++dupMtx) {
1412
1413                 // original inverse matrix, not actual matrix of object, but first duplivert.
1414                 for (int i=0;i<4;i++)
1415                         for (int j=0;j<4;j++)
1416                                 obmat[i][j] = dupMtx->second[(i<<2)+j];
1417                 MTC_Mat4Invert(imat, obmat);
1418
1419                 // first object written as normal (but with transform of first duplivert)
1420                 Object* obj = dup_srcob[dupMtx->first];
1421                 writeObject(obj, all_objects[obj].obr, all_objects[obj].faces, obmat);
1422
1423                 // all others instances of first
1424                 for (unsigned int curmtx=16;curmtx<dupMtx->second.size();curmtx+=16) 
1425                 {       // number of 4x4 matrices
1426                         // new mtx
1427                         for (int i=0;i<4;i++)
1428                                 for (int j=0;j<4;j++)
1429                                         nmat[i][j] = dupMtx->second[curmtx+(i<<2)+j];
1430
1431                         MTC_Mat4MulMat4(cmat, imat, nmat);      // transform with respect to original = inverse_original * new
1432
1433                         float mtr[4*4];
1434                         mtr[0*4+0]=cmat[0][0];  mtr[0*4+1]=cmat[1][0];  mtr[0*4+2]=cmat[2][0];  mtr[0*4+3]=cmat[3][0];
1435                         mtr[1*4+0]=cmat[0][1];  mtr[1*4+1]=cmat[1][1];  mtr[1*4+2]=cmat[2][1];  mtr[1*4+3]=cmat[3][1];
1436                         mtr[2*4+0]=cmat[0][2];  mtr[2*4+1]=cmat[1][2];  mtr[2*4+2]=cmat[2][2];  mtr[2*4+3]=cmat[3][2];
1437                         mtr[3*4+0]=cmat[0][3];  mtr[3*4+1]=cmat[1][3];  mtr[3*4+2]=cmat[2][3];  mtr[3*4+3]=cmat[3][3];
1438                         yafrayGate->transformPush(mtr);
1439
1440                         // new name from original
1441                         string name=(obj->id.name);
1442                         char temp[16];
1443                         sprintf(temp,"_dup%d",(curmtx>>4));
1444                         name+=temp;
1445                         yafrayGate->addObject_reference(name,obj->id.name);
1446                         yafrayGate->transformPop();
1447                 }
1448
1449         }
1450 }
1451
1452 void yafrayPluginRender_t::writeAreaLamp(LampRen* lamp, int num, float iview[4][4])
1453 {
1454         yafray::paramMap_t params;
1455         
1456         if (lamp->area_shape!=LA_AREA_SQUARE) return;
1457         float *a=lamp->area[0], *b=lamp->area[1], *c=lamp->area[2], *d=lamp->area[3];
1458         float power=lamp->energy;
1459         
1460         string md = "off";
1461         // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
1462         if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on";  power*=re->r.GIpower; }
1463         params["type"]=yafray::parameter_t("arealight");
1464         char temp[16];
1465         sprintf(temp,"LAMP%d",num+1);
1466         params["name"]=yafray::parameter_t(temp);
1467         params["dummy"]=yafray::parameter_t(md);
1468         params["power"]=yafray::parameter_t(power);
1469         // samples not used for GI with photons, can still be exported, is ignored
1470         int psm=0, sm = lamp->ray_totsamp;
1471         if (sm>=25) psm = sm/5;
1472         params["samples"]=yafray::parameter_t(sm);
1473         params["psamples"]=yafray::parameter_t(psm);
1474         
1475         // transform area lamp coords back to world
1476         float lpco[4][3];
1477         MTC_cp3Float(a, lpco[0]);
1478         MTC_Mat4MulVecfl(iview, lpco[0]);
1479         MTC_cp3Float(b, lpco[1]);
1480         MTC_Mat4MulVecfl(iview, lpco[1]);
1481         MTC_cp3Float(c, lpco[2]);
1482         MTC_Mat4MulVecfl(iview, lpco[2]);
1483         MTC_cp3Float(d, lpco[3]);
1484         MTC_Mat4MulVecfl(iview, lpco[3]);       
1485         params["a"] = yafray::parameter_t(yafray::point3d_t(lpco[0][0], lpco[0][1], lpco[0][2]));
1486         params["b"] = yafray::parameter_t(yafray::point3d_t(lpco[1][0], lpco[1][1], lpco[1][2]));
1487         params["c"] = yafray::parameter_t(yafray::point3d_t(lpco[2][0], lpco[2][1], lpco[2][2]));
1488         params["d"] = yafray::parameter_t(yafray::point3d_t(lpco[3][0], lpco[3][1], lpco[3][2]));
1489         
1490         params["color"]=yafray::parameter_t(yafray::color_t(lamp->r,lamp->g,lamp->b));
1491         yafrayGate->addLight(params);
1492 }
1493
1494 void yafrayPluginRender_t::writeLamps()
1495 {
1496         GroupObject *go;
1497         int i=0;
1498         
1499         // inver viewmatrix needed for back2world transform
1500         float iview[4][4];
1501         // re->viewinv != inv.re->viewmat because of possible ortho mode (see convertBlenderScene.c)
1502         // have to invert it here
1503         MTC_Mat4Invert(iview, re->viewmat);
1504
1505         // all lamps
1506         for(go=(GroupObject *)re->lights.first; go; go= go->next, i++)
1507         {
1508                 LampRen* lamp = (LampRen *)go->lampren;
1509                 
1510                 yafray::paramMap_t params;
1511                 string type="";
1512                 
1513                 if (lamp->type==LA_AREA) { writeAreaLamp(lamp, i, iview);  continue; }
1514                 
1515                 // TODO: add decay setting in yafray
1516                 bool is_softL=false, is_sphereL=false;
1517                 if (lamp->type==LA_LOCAL) {
1518                         if (lamp->mode & LA_YF_SOFT) {
1519                                 // shadowmapped omnidirectional light
1520                                 params["type"] = yafray::parameter_t("softlight");
1521                                 is_softL = true;
1522                         }
1523                         else if ((lamp->mode & LA_SHAD_RAY) && (lamp->YF_ltradius>0.0)) {
1524                                 // area sphere, only when ray shadows enabled and radius>0.0
1525                                 params["type"] = yafray::parameter_t("spherelight");
1526                                 is_sphereL = true;
1527                         }
1528                         else params["type"] = yafray::parameter_t("pointlight");
1529                         params["glow_intensity"] = yafray::parameter_t(lamp->YF_glowint);
1530                         params["glow_offset"] = yafray::parameter_t(lamp->YF_glowofs);
1531                         params["glow_type"] = yafray::parameter_t(lamp->YF_glowtype);
1532                 }
1533                 else if (lamp->type==LA_SPOT)
1534                         params["type"] = yafray::parameter_t("spotlight");
1535                 else if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI)) // hemi exported as sun
1536                         params["type"] = yafray::parameter_t("sunlight");
1537                 else if (lamp->type==LA_YF_PHOTON)
1538                         params["type"] = yafray::parameter_t("photonlight");
1539                 else {
1540                         // possibly unknown type, ignore
1541                         cout << "Unknown Blender lamp type: " << lamp->type << endl;
1542                         continue;
1543                 }
1544                 
1545                 //no name available here, create one
1546                 char temp[16];
1547                 sprintf(temp,"LAMP%d",i+1);
1548                 params["name"] = yafray::parameter_t(temp);
1549
1550                 // color already premultiplied by energy, so only need distance here
1551                 float pwr = 1;  // default for sun/hemi, distance irrelevant
1552                 if ((lamp->type!=LA_SUN) && (lamp->type!=LA_HEMI)) {
1553                         if (lamp->mode & LA_SPHERE) {
1554                                 // best approx. as used in LFexport script (LF d.f.m. 4pi?)
1555                                 pwr = lamp->dist*(lamp->dist+1)*(0.25/M_PI);
1556                                 //decay = 2;
1557                         }
1558                         else {
1559                                 pwr = lamp->dist;
1560                                 //decay = 1;
1561                         }
1562                 }
1563
1564                 if (is_sphereL) {
1565                         // 'dummy' mode for spherelight when used with gpm
1566                         string md = "off";
1567                         // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
1568                         if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on";  pwr*=re->r.GIpower; }
1569                         params["power"] = yafray::parameter_t(pwr);
1570                         params["dummy"] = yafray::parameter_t(md);
1571                 }
1572                 else params["power"] = yafray::parameter_t(pwr);
1573                 
1574                 // cast_shadows flag not used with softlight, spherelight or photonlight
1575                 if ((!is_softL) && (!is_sphereL) && (lamp->type!=LA_YF_PHOTON)) {
1576                         string lpmode="off";
1577                         // Blender hemilights exported as sunlights which might have shadow flag set
1578                         // should have cast_shadows set to off (reported by varuag)
1579                         if (lamp->type!=LA_HEMI) {
1580                                 if (re->r.mode & R_SHADOW) {
1581                                         // old bug was here since the yafray lamp settings panel was added,
1582                                         // blender spotlight shadbuf flag should be ignored, since it is not in the panel anymore
1583                                         if (lamp->mode & LA_SHAD_RAY) lpmode="on";
1584                                 }
1585                         }
1586                         params["cast_shadows"] = yafray::parameter_t(lpmode);
1587                 }
1588                 
1589                 // spot specific stuff
1590                 bool has_halo = ((lamp->type==LA_SPOT) && (lamp->mode & LA_HALO) && (lamp->haint>0.0));
1591                 if (lamp->type==LA_SPOT) {
1592                         // conversion already changed spotsize to cosine of half angle
1593                         float ld = 1-lamp->spotsi;      //convert back to blender slider setting
1594                         if (ld!=0) ld = 1.f/ld;
1595                         params["size"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI);
1596                         params["blend"] = yafray::parameter_t(lamp->spotbl*ld);
1597                         params["beam_falloff"] = yafray::parameter_t(2.0);
1598                         // halo params
1599                         if (has_halo) {
1600                                 params["halo"] = yafray::parameter_t("on");
1601                                 params["res"] = yafray::parameter_t(lamp->YF_bufsize);
1602                                 int hsmp = ((12-lamp->shadhalostep)*16)/12;
1603                                 hsmp = (hsmp+1)*16;     // makes range (16, 272) for halostep(12, 0), good enough?
1604                                 // halo 'samples' now 'stepsize'
1605                                 // convert from old integer samples value to some reasonable stepsize
1606                                 params["stepsize"] = yafray::parameter_t(1.0/sqrt((float)hsmp));
1607                                 params["shadow_samples"] = yafray::parameter_t(lamp->samp*lamp->samp);
1608                                 params["halo_blur"] = yafray::parameter_t(0.0);
1609                                 params["shadow_blur"] = yafray::parameter_t(lamp->soft*0.01f);
1610                                 params["fog_density"] = yafray::parameter_t(lamp->haint*0.2f);
1611                         }
1612                 }
1613                 else if (is_softL) {
1614                         // softlight
1615                         params["res"] = yafray::parameter_t(lamp->YF_bufsize);
1616                         params["radius"] = yafray::parameter_t(lamp->soft);
1617                         params["bias"] = yafray::parameter_t(lamp->bias);
1618                 }
1619                 else if (is_sphereL) {
1620                         // spherelight
1621                         int psm=0, sm = lamp->ray_samp*lamp->ray_samp;
1622                         if (sm>=25) psm = sm/5;
1623                         params["radius"] = yafray::parameter_t(lamp->YF_ltradius);
1624                         params["samples"] = yafray::parameter_t(sm);
1625                         params["psamples"] = yafray::parameter_t(psm);
1626                         params["qmc_method"] = yafray::parameter_t(1);
1627                 }
1628                 else if (lamp->type==LA_YF_PHOTON) {
1629                         string qmc="off";
1630                         if (lamp->YF_useqmc) qmc="on";
1631                         params["photons"] = yafray::parameter_t(lamp->YF_numphotons);
1632                         params["search"] = yafray::parameter_t(lamp->YF_numsearch);
1633                         params["depth"] = yafray::parameter_t(lamp->YF_phdepth);
1634                         params["use_QMC"] = yafray::parameter_t(qmc);
1635                         params["angle"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI);
1636                         float cl = lamp->YF_causticblur/sqrt((float)lamp->YF_numsearch);
1637                         params["fixedradius"] = yafray::parameter_t(lamp->YF_causticblur);
1638                         params["cluster"] = yafray::parameter_t(cl);
1639                 }
1640
1641                 // transform lamp co & vec back to world
1642                 float lpco[3], lpvec[3];
1643                 MTC_cp3Float(lamp->co, lpco);
1644                 MTC_Mat4MulVecfl(iview, lpco);
1645                 MTC_cp3Float(lamp->vec, lpvec);
1646                 MTC_Mat4Mul3Vecfl(iview, lpvec);
1647
1648                 // position, (==-blendir for sun/hemi)
1649                 if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI))
1650                         params["from"] = yafray::parameter_t(yafray::point3d_t(-lpvec[0], -lpvec[1], -lpvec[2]));
1651                 else
1652                         params["from"] = yafray::parameter_t(yafray::point3d_t(lpco[0], lpco[1], lpco[2]));
1653                 // 'to' for spot/photonlight, already calculated by Blender
1654                 if ((lamp->type==LA_SPOT) || (lamp->type==LA_YF_PHOTON)) {
1655                         params["to"] = yafray::parameter_t(yafray::point3d_t(lpco[0] + lpvec[0],
1656                                                                                                                                                                                                                                          lpco[1] + lpvec[1],
1657                                                                                                                                                                                                                                          lpco[2] + lpvec[2]));
1658                         if (has_halo) params["fog"] = yafray::parameter_t(yafray::color_t(1.0, 1.0, 1.0));
1659                 }
1660                 
1661                 // color
1662                 // rgb in LampRen is premultiplied by energy, power is compensated for that above
1663                 params["color"] = yafray::parameter_t(yafray::color_t(lamp->r, lamp->g, lamp->b));
1664                 yafrayGate->addLight(params);
1665         }
1666 }
1667
1668 // write main camera
1669 void yafrayPluginRender_t::writeCamera()
1670 {
1671         yafray::paramMap_t params;
1672         params["name"]=yafray::parameter_t("MAINCAM");
1673         if (re->r.mode & R_ORTHO)
1674                 params["type"] = yafray::parameter_t("ortho");
1675         else
1676                 params["type"] = yafray::parameter_t("perspective");
1677         
1678         params["resx"] = yafray::parameter_t(re->winx);
1679         params["resy"] = yafray::parameter_t(re->winy);
1680
1681         float f_aspect = 1;
1682         if ((re->winx * re->r.xasp) <= (re->winy * re->r.yasp))
1683                 f_aspect = float(re->winx * re->r.xasp) / float(re->winy * re->r.yasp);
1684         params["focal"] = yafray::parameter_t(mainCamLens/(f_aspect*32.f));
1685         // bug #4532, when field rendering is enabled, ycor is doubled
1686         if (re->r.mode & R_FIELDS)
1687                 params["aspect_ratio"] = yafray::parameter_t(re->ycor * 0.5f);
1688         else
1689                 params["aspect_ratio"] = yafray::parameter_t(re->ycor);
1690
1691         // dof params, only valid for real camera
1692         float fdist = 1;        // only changes for ortho
1693         if (maincam_obj->type==OB_CAMERA) {
1694                 Camera* cam = (Camera*)maincam_obj->data;
1695                 if (re->r.mode & R_ORTHO) fdist = cam->ortho_scale*(mainCamLens/32.f);
1696                 params["dof_distance"] = yafray::parameter_t(cam->YF_dofdist);
1697                 params["aperture"] = yafray::parameter_t(cam->YF_aperture);
1698                 if (cam->flag & CAM_YF_NO_QMC)
1699                         params["use_qmc"] = yafray::parameter_t("off");
1700                 else
1701                         params["use_qmc"] = yafray::parameter_t("on");
1702                 // bokeh params
1703                 string st = "disk1";
1704                 if (cam->YF_bkhtype==1)
1705                         st = "disk2";
1706                 else if (cam->YF_bkhtype==2)
1707                         st = "triangle";
1708                 else if (cam->YF_bkhtype==3)
1709                         st = "square";
1710                 else if (cam->YF_bkhtype==4)
1711                         st = "pentagon";
1712                 else if (cam->YF_bkhtype==5)
1713                         st = "hexagon";
1714                 else if (cam->YF_bkhtype==6)
1715                         st = "ring";
1716                 params["bokeh_type"] = yafray::parameter_t(st);
1717                 st = "uniform";
1718                 if (cam->YF_bkhbias==1)
1719                         st = "center";
1720                 else if (cam->YF_bkhbias==2)
1721                         st = "edge";
1722                 params["bokeh_bias"] = yafray::parameter_t(st);
1723                 params["bokeh_rotation"] = yafray::parameter_t(cam->YF_bkhrot);
1724         }
1725
1726         params["from"]=yafray::parameter_t(
1727                         yafray::point3d_t(maincam_obj->obmat[3][0], maincam_obj->obmat[3][1], maincam_obj->obmat[3][2]));
1728         params["to"]=yafray::parameter_t(
1729                         yafray::point3d_t(maincam_obj->obmat[3][0] - fdist * re->viewmat[0][2],
1730                                                                                                 maincam_obj->obmat[3][1] - fdist * re->viewmat[1][2],
1731                                                                                                 maincam_obj->obmat[3][2] - fdist * re->viewmat[2][2]));
1732         params["up"]=yafray::parameter_t(
1733                         yafray::point3d_t(maincam_obj->obmat[3][0] + re->viewmat[0][1],
1734                                                                                                 maincam_obj->obmat[3][1] + re->viewmat[1][1],
1735                                                                                                 maincam_obj->obmat[3][2] + re->viewmat[2][1]));
1736
1737         yafrayGate->addCamera(params);
1738 }
1739
1740 void yafrayPluginRender_t::writeHemilight()
1741 {
1742         yafray::paramMap_t params;
1743         World *world = G.scene->world;
1744         bool fromAO = false;
1745         if (re->r.GIquality==6){
1746                 // use Blender AO params is possible
1747                 if (world==NULL) return;
1748                 if ((world->mode & WO_AMB_OCC)==0) {
1749                         // no AO, use default GIquality
1750                         cout << "[Warning]: Can't use AO parameters\nNo ambient occlusion enabled, using default values instead" << endl;
1751                 }
1752                 else fromAO = true;
1753         }
1754         if (re->r.GIcache) {
1755                 params["type"] = yafray::parameter_t("pathlight");
1756                 params["name"] = yafray::parameter_t("path_LT");
1757                 params["power"] = yafray::parameter_t(re->r.GIpower);
1758                 params["mode"] = yafray::parameter_t("occlusion");
1759                 params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off");
1760                 if (fromAO) {
1761                         // for AO, with cache, using range of 32*1 to 32*16 seems good enough
1762                         params["samples"] = yafray::parameter_t(32*world->aosamp);
1763                         params["maxdistance"] = yafray::parameter_t(world->aodist);
1764                 }
1765                 else {
1766                         switch (re->r.GIquality)
1767                         {
1768                                 case 1 : params["samples"] = yafray::parameter_t(128);  break;
1769                                 case 2 : params["samples"] = yafray::parameter_t(256);  break;
1770                                 case 3 : params["samples"] = yafray::parameter_t(512);  break;
1771                                 case 4 : params["samples"] = yafray::parameter_t(1024); break;
1772                                 case 5 : params["samples"] = yafray::parameter_t(2048); break;
1773                                 default: params["samples"] = yafray::parameter_t(256);
1774                         }
1775                 }
1776                 params["cache"] = yafray::parameter_t("on");
1777                 params["use_QMC"] = yafray::parameter_t("on");
1778                 params["threshold"] = yafray::parameter_t(re->r.GIrefinement);
1779                 params["cache_size"] = yafray::parameter_t((2.0/float(re->winx))*re->r.GIpixelspersample);
1780                 params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality);
1781                 params["grid"] = yafray::parameter_t(82);
1782                 params["search"] = yafray::parameter_t(35);
1783         }
1784         else {
1785                 params["type"] = yafray::parameter_t("hemilight");
1786                 params["name"] = yafray::parameter_t("hemi_LT");
1787                 params["power"] = yafray::parameter_t(re->r.GIpower);
1788                 if (fromAO) {
1789                         // use minimum of 4 samples for lowest sample setting, single sample way too noisy
1790                         params["samples"] = yafray::parameter_t(3 + world->aosamp*world->aosamp);
1791                         params["maxdistance"] = yafray::parameter_t(world->aodist);
1792                         params["use_QMC"] = yafray::parameter_t((world->aomode & WO_AORNDSMP) ? "off" : "on");
1793                 }
1794                 else {
1795                         switch (re->r.GIquality)
1796                         {
1797                                 case 1 :
1798                                 case 2 : params["samples"]=yafray::parameter_t(16);  break;
1799                                 case 3 : params["samples"]=yafray::parameter_t(36);  break;
1800                                 case 4 : params["samples"]=yafray::parameter_t(64);  break;
1801                                 case 5 : params["samples"]=yafray::parameter_t(128);  break;
1802                                 default: params["samples"]=yafray::parameter_t(25);
1803                         }
1804                 }
1805         }
1806         yafrayGate->addLight(params);
1807 }
1808
1809 void yafrayPluginRender_t::writePathlight()
1810 {
1811         if (re->r.GIphotons)
1812         {
1813                 yafray::paramMap_t params;
1814                 params["type"] = yafray::parameter_t("globalphotonlight");
1815                 params["name"] = yafray::parameter_t("gpm");
1816                 params["photons"] = yafray::parameter_t(re->r.GIphotoncount);
1817                 params["radius"] = yafray::parameter_t(re->r.GIphotonradius);
1818                 params["depth"] = yafray::parameter_t(((re->r.GIdepth>2) ? (re->r.GIdepth-1) : 1));
1819                 params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth);
1820                 params["search"] = yafray::parameter_t(re->r.GImixphotons);
1821                 yafrayGate->addLight(params);
1822         }
1823         yafray::paramMap_t params;
1824         params["type"] = yafray::parameter_t("pathlight");
1825         params["name"] = yafray::parameter_t("path_LT");
1826         params["power"] = yafray::parameter_t(re->r.GIindirpower);
1827         params["depth"] = yafray::parameter_t(((re->r.GIphotons) ? 1 : re->r.GIdepth));
1828         params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth);
1829         if (re->r.GIdirect && re->r.GIphotons) params["direct"] = yafray::parameter_t("on");
1830         if (re->r.GIcache && !(re->r.GIdirect && re->r.GIphotons))
1831         {
1832                 switch (re->r.GIquality)
1833                 {
1834                         case 1 : params["samples"] = yafray::parameter_t(128);  break;
1835                         case 2 : params["samples"] = yafray::parameter_t(256);  break;
1836                         case 3 : params["samples"] = yafray::parameter_t(512);  break;
1837                         case 4 : params["samples"] = yafray::parameter_t(1024); break;
1838                         case 5 : params["samples"] = yafray::parameter_t(2048); break;
1839                         default: params["samples"] = yafray::parameter_t(256);
1840                 }
1841                 params["cache"] = yafray::parameter_t("on");
1842                 params["use_QMC"] = yafray::parameter_t("on");
1843                 params["threshold"] = yafray::parameter_t(re->r.GIrefinement);
1844                 params["cache_size"] = yafray::parameter_t((2.0/float(re->recty))*re->r.GIpixelspersample);
1845                 params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality);
1846                 params["grid"] = yafray::parameter_t(82);
1847                 params["search"] = yafray::parameter_t(35);
1848                 params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off");
1849         }
1850         else
1851         {
1852                 switch (re->r.GIquality)
1853                 {
1854                         case 1 : params["samples"] = yafray::parameter_t(16);  break;
1855                         case 2 : params["samples"] = yafray::parameter_t(36);  break;
1856                         case 3 : params["samples"] = yafray::parameter_t(64);  break;
1857                         case 4 : params["samples"] = yafray::parameter_t(128); break;
1858                         case 5 : params["samples"] = yafray::parameter_t(256); break;
1859                         default: params["samples"] = yafray::parameter_t(25);
1860                 }
1861         }
1862         yafrayGate->addLight(params);
1863 }
1864
1865 bool yafrayPluginRender_t::writeWorld()
1866 {
1867         World *world = G.scene->world;
1868         if (re->r.GIquality!=0) {
1869                 if (re->r.GImethod==1) {
1870                         if (world==NULL) cout << "WARNING: need world background for skydome!\n";
1871                         writeHemilight();
1872                 }
1873                 else if (re->r.GImethod==2) writePathlight();
1874         }
1875         if (world==NULL) return false;
1876         
1877         yafray::paramMap_t params;
1878         for (int i=0;i<MAX_MTEX;i++) {
1879                 MTex* wtex = world->mtex[i];
1880                 if (!wtex) continue;
1881                 Image* wimg = wtex->tex->ima;
1882                 // now always exports if image used as world texture (and 'Hori' mapping enabled)
1883                 if ((wtex->tex->type==TEX_IMAGE) && (wimg!=NULL) && (wtex->mapto & WOMAP_HORIZ)) {
1884                         string wt_path = wimg->name;
1885                         adjustPath(wt_path);
1886                         params["type"] = yafray::parameter_t("image");
1887                         params["name"] = yafray::parameter_t("world_background");
1888                         // exposure_adjust not restricted to integer range anymore
1889                         params["exposure_adjust"] = yafray::parameter_t(wtex->tex->bright-1.f);
1890                         if (wtex->texco & TEXCO_ANGMAP)
1891                                 params["mapping"] = yafray::parameter_t("probe");
1892                         else if (wtex->texco & TEXCO_H_SPHEREMAP)       // in yafray full sphere
1893                                 params["mapping"] = yafray::parameter_t("sphere");
1894                         else    // assume 'tube' for anything else
1895                                 params["mapping"] = yafray::parameter_t("tube");
1896                         params["filename"] = yafray::parameter_t(wt_path);
1897                         params["interpolate"] = yafray::parameter_t((wtex->tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none");
1898                         if (wtex->tex->filtersize>1.f) params["prefilter"] = yafray::parameter_t("on");
1899                         yafrayGate->addBackground(params);
1900                         return true;
1901                 }
1902         }
1903
1904         params.clear();
1905         params["type"] = yafray::parameter_t("constant");
1906         params["name"] = yafray::parameter_t("world_background");
1907         // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
1908         // (have to change method to init yafray vars in Blender)
1909         float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
1910         params["color"]=yafray::parameter_t(yafray::color_t(world->horr * bg_mult,
1911                                                                                                                                                                                                                         world->horg * bg_mult,
1912                                                                                                                                                                                                                         world->horb * bg_mult));
1913         yafrayGate->addBackground(params);
1914         return true;
1915 }
1916
1917 bool blenderYafrayOutput_t::putPixel(int x, int y, const yafray::color_t &c,
1918                 yafray::CFLOAT alpha, yafray::PFLOAT depth)
1919 {
1920         // XXX how to get the image from Blender and write to it. This call doesn't allow to change buffer rects
1921         RenderResult rres;
1922         RE_GetResultImage(re, &rres);
1923         // rres.rectx, rres.recty is width/height
1924         // rres.rectf is float buffer, scanlines starting in bottom
1925         // rres.rectz is zbuffer, available when associated pass is set
1926
1927         const unsigned int maxy = rres.recty-1;
1928
1929         if (re->r.mode & R_BORDER) {
1930                 // border render, blender renderwin is size of border region,
1931                 // but yafray returns coords relative to full resolution
1932                 x -= int(re->r.border.xmin * re->winx);
1933                 y -= int((1.f-re->r.border.ymax) * re->winy);
1934                 if ((x >= 0) && (x < re->rectx) && (y >= 0) && (y < re->recty))
1935                 {
1936                         const unsigned int px = rres.rectx*(maxy - y);
1937                         // rgba
1938                         float* fpt = rres.rectf + ((px + x) << 2);
1939                         *fpt++ = c.R;
1940                         *fpt++ = c.G;
1941                         *fpt++ = c.B;
1942                         *fpt = alpha;
1943                         // depth values
1944                         if (rres.rectz) rres.rectz[px + x] = depth;
1945                         // to simplify things a bit, just do complete redraw here...
1946                         out++;
1947                         if ((out==4096) || ((x+y*re->rectx) == ((re->rectx-1)+(re->recty-1)*re->rectx))) {
1948                                 re->result->renlay = render_get_active_layer(re, re->result);
1949                                 re->display_draw(re->result, NULL);
1950                                 out = 0;
1951                         }
1952                 }
1953                 if (re->test_break()) return false;
1954                 return true;
1955         }
1956
1957         const unsigned int px = (maxy - y)*rres.rectx;
1958
1959         // rgba
1960         float* fpt = rres.rectf + ((px + x) << 2);
1961         *fpt++ = c.R;
1962         *fpt++ = c.G;
1963         *fpt++ = c.B;
1964         *fpt = alpha;
1965
1966         // depth values
1967         if (rres.rectz) rres.rectz[px + x] = depth;
1968         
1969         // attempt to optimize drawing, by only drawing the tile currently rendered by yafray,
1970         // and not the entire display every time (blender has to to do float->char conversion),
1971         // but since the tile is not actually known, it has to be calculated from the coords.
1972         // not sure if it really makes all that much difference at all... unless rendering really large pictures
1973         // (renderwin.c also had to be adapted for this)
1974         // tile start & end coords
1975         const int txs = x & 0xffffffc0, tys = y & 0xffffffc0;
1976         int txe = txs + 63, tye = tys + 63;
1977         // tile border clip
1978         if (txe >= rres.rectx) txe = rres.rectx-1;
1979         if (tye >= rres.recty) tye = maxy;
1980         // draw tile if last pixel reached
1981         if ((y*rres.rectx + x) == (tye*rres.rectx + txe)) {
1982                 re->result->renlay = render_get_active_layer(re, re->result);
1983                 // note: ymin/ymax swapped here, img. upside down!
1984                 rcti rt = {txs, txe+1, maxy-tye, ((tys==0) ? maxy : (rres.recty-tys))}; // !!! tys can be zero
1985                 re->display_draw(re->result, &rt);
1986         }
1987
1988         if (re->test_break()) return false;
1989         return true;
1990 }