#include "export_Plugin.h" #include #include using namespace std; #ifdef WIN32 #define WIN32_SKIP_HKEY_PROTECTION #include "BLI_winstuff.h" #ifndef FILE_MAXDIR #define FILE_MAXDIR 160 #endif #ifndef FILE_MAXFILE #define FILE_MAXFILE 80 #endif static string find_path() { HKEY hkey; DWORD dwType, dwSize; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\YafRay Team\\YafRay",0,KEY_READ,&hkey)==ERROR_SUCCESS) { dwType = REG_EXPAND_SZ; dwSize = MAX_PATH; DWORD dwStat; char *pInstallDir=new char[MAX_PATH]; dwStat=RegQueryValueEx(hkey, TEXT("InstallDir"), NULL, NULL,(LPBYTE)pInstallDir, &dwSize); if (dwStat == NO_ERROR) { string res=pInstallDir; delete [] pInstallDir; return res; } else cout << "Couldn't READ \'InstallDir\' value. Is yafray correctly installed?\n"; delete [] pInstallDir; RegCloseKey(hkey); } else cout << "Couldn't FIND registry key for yafray, is it installed?\n"; return string(""); } static int createDir(char* name) { if (BLI_exists(name)) return 2; //exists if (CreateDirectory((LPCTSTR)(name), NULL)) { cout << "Directory: " << name << " created\n"; return 1; // created } else { cout << "Could not create directory: " << name << endl; return 0; // fail } } extern "C" { extern char bprogname[]; } // add drive character if not in path string, using blender executable location as reference static void addDrive(string &path) { size_t sp = path.find_first_of(":"); if (sp==-1) { string blpath = bprogname; sp = blpath.find_first_of(":"); if (sp!=-1) path = blpath.substr(0, sp+1) + path; } } #else #include #include #include #include #include #include #endif static string YafrayPath() { #ifdef WIN32 string path=find_path(); return path; #else static const char *alternative[]= { "/usr/local/lib/", #ifdef __x86_64__ "/usr/lib64/", #endif "/usr/lib/", NULL }; for(int i=0;alternative[i]!=NULL;++i) { string fp = string(alternative[i]) + "libyafrayplugin.so"; struct stat st; if (stat(fp.c_str(), &st)<0) continue; if (st.st_mode & S_IROTH) return fp; } return ""; #endif } static string YafrayPluginPath() { #ifdef WIN32 return find_path()+"\\plugins"; #else static const char *alternative[]= { "/usr/local/lib/yafray", #ifdef __x86_64__ "/usr/lib64/yafray", #endif "/usr/lib/yafray", NULL }; for(int i=0;alternative[i]!=NULL;++i) { struct stat st; if (stat(alternative[i], &st)<0) continue; if (S_ISDIR(st.st_mode) && (st.st_mode & S_IXOTH)) return alternative[i]; } return ""; #endif } yafrayPluginRender_t::~yafrayPluginRender_t() { if (yafrayGate!=NULL) delete yafrayGate; if (handle!=NULL) PIL_dynlib_close(handle); #ifdef WIN32 if (corehandle!=NULL) PIL_dynlib_close(corehandle); #endif } bool yafrayPluginRender_t::initExport() { // bug #1897: when forcing render without yafray present, handle can be valid, // but find_symbol might have failed, trying second time will crash. // So make sure plugin loaded correctly and only get handle once. if ((!plugin_loaded) || (handle==NULL)) { string location = YafrayPath(); #ifdef WIN32 /* Win 32 loader cannot find needed libs in yafray dir, so we have to load them * by hand. This could be fixed using setdlldirectory function, but it is not * available in all win32 versions */ corehandle = PIL_dynlib_open((char *)(location + "\\yafraycore.dll").c_str()); if (corehandle==NULL) { char *err = PIL_dynlib_get_error_as_string(corehandle); if (err) cerr << "Error loading yafray plugin: " << err << endl; else cerr << "Error loading yafray plugin: Unknown." << endl; return false; } location += "\\yafrayplugin.dll"; #endif if (handle==NULL) { handle = PIL_dynlib_open((char *)location.c_str()); if (handle==NULL) { cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl; return false; } } yafray::yafrayConstructor *constructor; constructor = (yafray::yafrayConstructor *)PIL_dynlib_find_symbol(handle, YAFRAY_SYMBOL); if (constructor==NULL) { cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl; return false; } yafrayGate = constructor(re->r.threads, YafrayPluginPath()); cout << "YafRay plugin loaded" << endl; plugin_loaded = true; } return true; } bool yafrayPluginRender_t::writeRender() { yafray::paramMap_t params; params["camera_name"]=yafray::parameter_t("MAINCAM"); params["raydepth"]=yafray::parameter_t((float)re->r.YF_raydepth); params["gamma"]=yafray::parameter_t(re->r.YF_gamma); params["exposure"]=yafray::parameter_t(re->r.YF_exposure); if (re->r.YF_AA) { params["AA_passes"] = yafray::parameter_t((int)re->r.YF_AApasses); params["AA_minsamples"] = yafray::parameter_t(re->r.YF_AAsamples); params["AA_pixelwidth"] = yafray::parameter_t(re->r.YF_AApixelsize); params["AA_threshold"] = yafray::parameter_t(re->r.YF_AAthreshold); } else { // removed the default AA settings for midquality GI, better leave it to user if ((re->r.mode & R_OSA) && (re->r.osa)) { params["AA_passes"] = yafray::parameter_t((re->r.osa & 3)==0 ? (re->r.osa >> 2) : 1); params["AA_minsamples"] = yafray::parameter_t((re->r.osa & 3)==0 ? 4 : re->r.osa); } else { params["AA_passes"] = yafray::parameter_t(0); params["AA_minsamples"] = yafray::parameter_t(1); } params["AA_pixelwidth"] = yafray::parameter_t(1.5); params["AA_threshold"] = yafray::parameter_t(0.05f); } if (re->r.mode & R_BORDER) { params["border_xmin"] = yafray::parameter_t(2.f*re->r.border.xmin - 1.f); params["border_xmax"] = yafray::parameter_t(2.f*re->r.border.xmax - 1.f); params["border_ymin"] = yafray::parameter_t(2.f*re->r.border.ymin - 1.f); params["border_ymax"] = yafray::parameter_t(2.f*re->r.border.ymax - 1.f); } if (hasworld) { World *world = G.scene->world; if (world->mode & WO_MIST) { // basic fog float fd = world->mistdist; if (fd>0) fd=1.f/fd; else fd=1; params["fog_density"] = yafray::parameter_t(fd); params["fog_color"] = yafray::parameter_t(yafray::color_t(world->horr, world->horg, world->horb)); } params["background_name"] = yafray::parameter_t("world_background"); } params["bias"] = yafray::parameter_t(re->r.YF_raybias); params["clamp_rgb"] = yafray::parameter_t((re->r.YF_clamprgb==0) ? "on" : "off"); // lynx request params["threads"] = yafray::parameter_t((int)re->r.threads); blenderYafrayOutput_t output(re); yafrayGate->render(params, output); cout << "render finished" << endl; yafrayGate->clear(); return true; } bool yafrayPluginRender_t::finishExport() { return true; } // displayImage() not for plugin, see putPixel() below #ifdef WIN32 #define MAXPATHLEN MAX_PATH #else #include #endif static void adjustPath(string &path) { // if relative, expand to full path char cpath[MAXPATHLEN]; strcpy(cpath, path.c_str()); BLI_convertstringcode(cpath, G.sce); path = cpath; #ifdef WIN32 // add drive char if not there addDrive(path); #endif } static string noise2string(short nbtype) { switch (nbtype) { case TEX_BLENDER: return "blender"; case TEX_STDPERLIN: return "stdperlin"; case TEX_VORONOI_F1: return "voronoi_f1"; case TEX_VORONOI_F2: return "voronoi_f2"; case TEX_VORONOI_F3: return "voronoi_f3"; case TEX_VORONOI_F4: return "voronoi_f4"; case TEX_VORONOI_F2F1: return "voronoi_f2f1"; case TEX_VORONOI_CRACKLE: return "voronoi_crackle"; case TEX_CELLNOISE: return "cellnoise"; default: case TEX_NEWPERLIN: return "newperlin"; } } void yafrayPluginRender_t::writeTextures() { // used to keep track of images already written // (to avoid duplicates if also in imagetex for material TexFace texture) set dupimg; yafray::paramMap_t params; list lparams; for (map::const_iterator blendtex=used_textures.begin(); blendtex!=used_textures.end();++blendtex) { lparams.clear(); params.clear(); MTex* mtex = blendtex->second; Tex* tex = mtex->tex; // name is image name instead of texture name when type is image (see TEX_IMAGE case below) // (done because of possible combinations of 'TexFace' images and regular image textures, to avoid duplicates) if (tex->type!=TEX_IMAGE) params["name"] = yafray::parameter_t(blendtex->first); float nsz = tex->noisesize; if (nsz!=0.f) nsz=1.f/nsz; // noisebasis type string ntype = noise2string(tex->noisebasis); string ts, hardnoise=(tex->noisetype==TEX_NOISESOFT) ? "off" : "on"; switch (tex->type) { case TEX_STUCCI: // stucci is clouds as bump, only difference is an extra parameter to handle wall in/out // turbulence value is not used, so for large values will not match well case TEX_CLOUDS: { params["type"] = yafray::parameter_t("clouds"); params["size"] = yafray::parameter_t(nsz); params["hard"] = yafray::parameter_t(hardnoise); if (tex->type==TEX_STUCCI) { if (tex->stype==1) ts = "positive"; else if (tex->stype==2) ts = "negative"; else ts = "none"; params["bias"] = yafray::parameter_t(ts); params["depth"] = yafray::parameter_t(0); // for stucci always 0 } else params["depth"] = yafray::parameter_t(tex->noisedepth); params["color_type"] = yafray::parameter_t(tex->stype); params["noise_type"] = yafray::parameter_t(ntype); break; } case TEX_WOOD: { params["type"] = yafray::parameter_t("wood"); // blender does not use depth value for wood, always 0 params["depth"] = yafray::parameter_t(0); float turb = (tex->stype<2) ? 0.0 : tex->turbul; params["turbulence"] = yafray::parameter_t(turb); params["size"] = yafray::parameter_t(nsz); params["hard"] = yafray::parameter_t(hardnoise); ts = (tex->stype & 1) ? "rings" : "bands"; //stype 1&3 ringtype params["wood_type"] = yafray::parameter_t(ts); params["noise_type"] = yafray::parameter_t(ntype); // shape parameter, for some reason noisebasis2 is used... ts = "sin"; if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri"; params["shape"] = yafray::parameter_t(ts); break; } case TEX_MARBLE: { params["type"] = yafray::parameter_t("marble"); params["depth"] = yafray::parameter_t(tex->noisedepth); params["turbulence"] = yafray::parameter_t(tex->turbul); params["size"] = yafray::parameter_t(nsz); params["hard"] = yafray::parameter_t(hardnoise); params["sharpness"] = yafray::parameter_t((float)(1<stype)); params["noise_type"] = yafray::parameter_t(ntype); ts = "sin"; if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri"; params["shape"] = yafray::parameter_t(ts); break; } case TEX_VORONOI: { params["type"] = yafray::parameter_t("voronoi"); ts = "int"; if (tex->vn_coltype==1) ts = "col1"; else if (tex->vn_coltype==2) ts = "col2"; else if (tex->vn_coltype==3) ts = "col3"; params["color_type"] = yafray::parameter_t(ts); params["weight1"] = yafray::parameter_t(tex->vn_w1); params["weight2"] = yafray::parameter_t(tex->vn_w2); params["weight3"] = yafray::parameter_t(tex->vn_w3); params["weight4"] = yafray::parameter_t(tex->vn_w4); params["mk_exponent"] = yafray::parameter_t(tex->vn_mexp); params["intensity"] = yafray::parameter_t(tex->ns_outscale); params["size"] = yafray::parameter_t(nsz); ts = "actual"; if (tex->vn_distm==TEX_DISTANCE_SQUARED) ts = "squared"; else if (tex->vn_distm==TEX_MANHATTAN) ts = "manhattan"; else if (tex->vn_distm==TEX_CHEBYCHEV) ts = "chebychev"; else if (tex->vn_distm==TEX_MINKOVSKY_HALF) ts = "minkovsky_half"; else if (tex->vn_distm==TEX_MINKOVSKY_FOUR) ts = "minkovsky_four"; else if (tex->vn_distm==TEX_MINKOVSKY) ts = "minkovsky"; params["distance_metric"] = yafray::parameter_t(ts); break; } case TEX_MUSGRAVE: { params["type"] = yafray::parameter_t("musgrave"); switch (tex->stype) { case TEX_MFRACTAL: ts = "multifractal"; break; case TEX_RIDGEDMF: ts = "ridgedmf"; break; case TEX_HYBRIDMF: ts = "hybridmf"; break; case TEX_HTERRAIN: ts = "heteroterrain"; break; default: case TEX_FBM: ts = "fBm"; } params["musgrave_type"] = yafray::parameter_t(ts); params["noise_type"] = yafray::parameter_t(ntype); params["H"] = yafray::parameter_t(tex->mg_H); params["lacunarity"] = yafray::parameter_t(tex->mg_lacunarity); params["octaves"] = yafray::parameter_t(tex->mg_octaves); if ((tex->stype==TEX_HTERRAIN) || (tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF)) { params["offset"] = yafray::parameter_t(tex->mg_offset); if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF)) params["gain"] = yafray::parameter_t(tex->mg_gain); } params["size"] = yafray::parameter_t(nsz); params["intensity"] = yafray::parameter_t(tex->ns_outscale); break; } case TEX_DISTNOISE: { params["type"] = yafray::parameter_t("distorted_noise"); params["distort"] = yafray::parameter_t(tex->dist_amount); params["size"] = yafray::parameter_t(nsz); params["noise_type1"] = yafray::parameter_t(ntype); params["noise_type2"] = yafray::parameter_t(noise2string(tex->noisebasis2)); break; } case TEX_BLEND: { params["type"] = yafray::parameter_t("gradient"); switch (tex->stype) { case 1: ts="quadratic"; break; case 2: ts="cubic"; break; case 3: ts="diagonal"; break; case 4: ts="sphere"; break; case 5: ts="halo"; break; default: case 0: ts="linear"; break; } params["gradient_type"] = yafray::parameter_t(ts); if (tex->flag & TEX_FLIPBLEND) ts="on"; else ts="off"; params["flip_xy"] = yafray::parameter_t(ts); break; } case TEX_NOISE: { params["type"] = yafray::parameter_t("random_noise"); params["depth"] = yafray::parameter_t(tex->noisedepth); break; } case TEX_IMAGE: { Image* ima = tex->ima; if (ima) { // remember image to avoid duplicates later if also in imagetex // (formerly done by removing from imagetex, but need image/material link) dupimg.insert(ima); params["type"] = yafray::parameter_t("image"); params["name"] = yafray::parameter_t(ima->id.name); string texpath = ima->name; adjustPath(texpath); params["filename"] = yafray::parameter_t(texpath); params["interpolate"] = yafray::parameter_t((tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none"); } break; } default: cout << "Unsupported texture type\n"; } yafrayGate->addShader(params, lparams); // colorbands if (tex->flag & TEX_COLORBAND) { ColorBand* cb = tex->coba; if (cb) { lparams.clear(); params.clear(); params["type"] = yafray::parameter_t("colorband"); params["name"] = yafray::parameter_t(blendtex->first + "_coba"); params["input"] = yafray::parameter_t(blendtex->first); for (int i=0;itot;i++) { yafray::paramMap_t mparams; mparams["value"] = yafray::parameter_t(cb->data[i].pos); mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a)); lparams.push_back(mparams); } yafrayGate->addShader(params, lparams); } } } // If used, textures for the material 'TexFace' case if (!imagetex.empty()) { for (map >::const_iterator imgtex=imagetex.begin(); imgtex!=imagetex.end();++imgtex) { // skip if already written above if (dupimg.find(imgtex->first)==dupimg.end()) { lparams.clear(); params.clear(); params["name"] = yafray::parameter_t(imgtex->first->id.name); params["type"] = yafray::parameter_t("image"); string texpath(imgtex->first->name); adjustPath(texpath); params["filename"] = yafray::parameter_t(texpath); yafrayGate->addShader(params, lparams); } } } } void yafrayPluginRender_t::writeShader(const string &shader_name, Material* matr, const string &facetexname) { yafray::paramMap_t params; list lparams; // if material has ramps, export colorbands first if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC)) { // both colorbands without input shader ColorBand* cb = matr->ramp_col; if ((matr->mode & MA_RAMP_COL) && (cb!=NULL)) { params["type"] = yafray::parameter_t("colorband"); params["name"] = yafray::parameter_t(shader_name+"_difframp"); for (int i=0;itot;i++) { yafray::paramMap_t mparams; mparams["value"] = yafray::parameter_t(cb->data[i].pos); mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a)); lparams.push_back(mparams); } yafrayGate->addShader(params, lparams); } cb = matr->ramp_spec; if ((matr->mode & MA_RAMP_SPEC) && (cb!=NULL)) { lparams.clear(); params.clear(); params["type"] = yafray::parameter_t("colorband"); params["name"] = yafray::parameter_t(shader_name+"_specramp"); for (int i=0;itot;i++) { yafray::paramMap_t mparams; mparams["value"] = yafray::parameter_t(cb->data[i].pos); mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a)); lparams.push_back(mparams); } yafrayGate->addShader(params, lparams); } lparams.clear(); params.clear(); } params["type"] = yafray::parameter_t("blendershader"); params["name"] = yafray::parameter_t(shader_name); params["color"] = yafray::parameter_t(yafray::color_t(matr->r, matr->g, matr->b)); float sr=matr->specr, sg=matr->specg, sb=matr->specb; if (matr->spec_shader==MA_SPEC_WARDISO) { // ........ sr /= M_PI; sg /= M_PI; sb /= M_PI; } params["specular_color"] = yafray::parameter_t(yafray::color_t(sr, sg, sb)); params["mirror_color"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb)); params["diffuse_reflect"] = yafray::parameter_t(matr->ref); params["specular_amount"] = yafray::parameter_t(matr->spec); params["alpha"] = yafray::parameter_t(matr->alpha); // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower; params["emit"]=yafray::parameter_t(matr->emit*bg_mult); // reflection/refraction if ( (matr->mode & MA_RAYMIRROR) || (matr->mode & MA_RAYTRANSP) ) params["IOR"] = yafray::parameter_t(matr->ang); if (matr->mode & MA_RAYMIRROR) { // Sofar yafray's min_refle parameter (which misleadingly actually controls fresnel reflection offset) // has been mapped to Blender's ray_mirror parameter. // This causes it be be misinterpreted and misused as a reflection amount control however. // Besides that, it also causes extra complications for the yafray Blendershader. // So added an actual amount of reflection parameter instead, and another // extra parameter 'frsOfs' to actually control fresnel offset (re-uses Blender fresnel_mir_i param). params["reflect"] = yafray::parameter_t("on"); params["reflect_amount"] = yafray::parameter_t(matr->ray_mirror); 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) params["fresnel_offset"] = yafray::parameter_t(fo); // for backward compatibility, also add old 'reflected' parameter, copy of mirror_color params["reflected"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb)); // same for 'min_refle' param. Instead of the ray_mirror parameter that was used before, since now // the parameter's function is taken over by the fresnel offset parameter, use that instead. params["min_refle"] = yafray::parameter_t(fo); } if (matr->mode & MA_RAYTRANSP) { params["refract"] = yafray::parameter_t("on"); params["transmit_filter"] = yafray::parameter_t(matr->filter); // tir on by default params["tir"] = yafray::parameter_t("on"); // transmit absorption color // to make things easier(?) for user it now specifies the actual color at 1 unit / YF_dscale of distance const float maxlog = -log(1e-38); float ar = (matr->YF_ar>0) ? -log(matr->YF_ar) : maxlog; float ag = (matr->YF_ag>0) ? -log(matr->YF_ag) : maxlog; float ab = (matr->YF_ab>0) ? -log(matr->YF_ab) : maxlog; float sc = matr->YF_dscale; if (sc!=0.f) sc=1.f/sc; params["absorption"] = yafray::parameter_t(yafray::color_t(ar*sc, ag*sc, ab*sc)); // dispersion params["dispersion_power"] = yafray::parameter_t(matr->YF_dpwr); params["dispersion_samples"] = yafray::parameter_t(matr->YF_dsmp); params["dispersion_jitter"] = yafray::parameter_t(matr->YF_djit ? "on" : "off"); // for backward compatibility, also add old 'transmitted' parameter, copy of 'color' * (1-alpha) float na = 1.f-matr->alpha; params["transmitted"] = yafray::parameter_t(yafray::color_t(matr->r*na, matr->g*na, matr->b*na)); } string Mmode = ""; if (matr->mode & MA_TRACEBLE) Mmode += "traceable"; if (matr->mode & MA_SHADOW) Mmode += " shadow"; if (matr->mode & MA_SHLESS) Mmode += " shadeless"; if (matr->mode & MA_VERTEXCOL) Mmode += " vcol_light"; if (matr->mode & MA_VERTEXCOLP) Mmode += " vcol_paint"; if (matr->mode & MA_ZTRA) Mmode += " ztransp"; if (matr->mode & MA_ONLYSHADOW) Mmode += " onlyshadow"; if (Mmode!="") params["matmodes"] = yafray::parameter_t(Mmode); // diffuse & specular brdf, lambert/cooktorr defaults // diffuse if (matr->diff_shader==MA_DIFF_ORENNAYAR) { params["diffuse_brdf"] = yafray::parameter_t("oren_nayar"); params["roughness"] = yafray::parameter_t(matr->roughness); } else if (matr->diff_shader==MA_DIFF_TOON) { params["diffuse_brdf"] = yafray::parameter_t("toon"); params["toondiffuse_size"] = yafray::parameter_t(matr->param[0]); params["toondiffuse_smooth"] = yafray::parameter_t(matr->param[1]); } else if (matr->diff_shader==MA_DIFF_MINNAERT) { params["diffuse_brdf"] = yafray::parameter_t("minnaert"); params["darkening"] = yafray::parameter_t(matr->darkness); } else params["diffuse_brdf"] = yafray::parameter_t("lambert"); // specular if (matr->spec_shader==MA_SPEC_PHONG) { params["specular_brdf"] = yafray::parameter_t("phong"); params["hard"] = yafray::parameter_t(matr->har); } else if (matr->spec_shader==MA_SPEC_BLINN) { params["specular_brdf"] = yafray::parameter_t("blinn"); params["blinn_ior"] = yafray::parameter_t(matr->refrac); params["hard"] = yafray::parameter_t(matr->har); } else if (matr->spec_shader==MA_SPEC_TOON) { params["specular_brdf"] = yafray::parameter_t("toon"); params["toonspecular_size"] = yafray::parameter_t(matr->param[2]); params["toonspecular_smooth"] = yafray::parameter_t(matr->param[3]); } else if (matr->spec_shader==MA_SPEC_WARDISO) { params["specular_brdf"] = yafray::parameter_t("ward"); params["u_roughness"] = yafray::parameter_t(matr->rms); params["v_roughness"] = yafray::parameter_t(matr->rms); } else { params["specular_brdf"] = yafray::parameter_t("blender_cooktorr"); params["hard"] = yafray::parameter_t(matr->har); } // ramps, if used if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC)) { const string rm_blend[9] = {"mix", "add", "mul", "sub", "screen", "divide", "difference", "darken", "lighten"}; const string rm_mode[4] = {"shader", "energy", "normal", "result"}; // diffuse if ((matr->mode & MA_RAMP_COL) && (matr->ramp_col!=NULL)) { params["diffuse_ramp"] = yafray::parameter_t(shader_name+"_difframp"); params["diffuse_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_col]); params["diffuse_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_col]); params["diffuse_ramp_factor"] = yafray::parameter_t(matr->rampfac_col); } // specular if ((matr->mode & MA_RAMP_SPEC) && (matr->ramp_spec!=NULL)) { params["specular_ramp"] = yafray::parameter_t(shader_name+"_specramp"); params["specular_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_spec]); params["specular_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_spec]); params["specular_ramp_factor"] = yafray::parameter_t(matr->rampfac_spec); } } // modulators // first modulator is the texture of the face, if used (TexFace mode) if (facetexname.length()!=0) { yafray::paramMap_t mparams; mparams["input"] = yafray::parameter_t(facetexname); mparams["color"] = yafray::parameter_t(1); lparams.push_back(mparams); } for (int m2=0;m2septex & (1<mtex[m2]; if (mtex==NULL) continue; // ignore null tex Tex* tex = mtex->tex; if (tex==NULL) continue; map::const_iterator mtexL = used_textures.find(string(tex->id.name)); if (mtexL!=used_textures.end()) { yafray::paramMap_t mparams; // when no facetex used, shader_name is created from original material name char temp[32]; sprintf(temp,"_map%d", m2); if (facetexname.length()!=0) mparams["input"] = yafray::parameter_t(string(matr->id.name) + string(temp)); else mparams["input"] = yafray::parameter_t(shader_name + temp); // blendtype, would have been nice if the order would have been the same as for ramps... const string blendtype[MTEX_NUM_BLENDTYPES] = {"mix", "mul", "add", "sub", "divide", "darken", "difference", "lighten", "screen", "hue", "sat", "val", "color"}; mparams["mode"] = yafray::parameter_t(blendtype[(int)mtex->blendtype]); // texture color (for use with MUL and/or no_rgb etc..) mparams["texcol"]=yafray::parameter_t(yafray::color_t(mtex->r,mtex->g,mtex->b)); // texture contrast, brightness & color adjustment mparams["filtercolor"]=yafray::parameter_t(yafray::color_t(tex->rfac,tex->gfac,tex->bfac)); mparams["contrast"]=yafray::parameter_t(tex->contrast); mparams["brightness"]=yafray::parameter_t(tex->bright); // all texture flags now are switches, having the value 1 or -1 (negative option) // the negative option only used for the intensity modulation options. // material (diffuse) color, amount controlled by colfac (see below) if (mtex->mapto & MAP_COL) mparams["color"]=yafray::parameter_t(1.0); // bumpmapping if ((mtex->mapto & MAP_NORM) || (mtex->maptoneg & MAP_NORM)) { // for yafray, bump factor is negated (unless tex is stucci, not affected by 'Neg') // scaled down quite a bit float nf = mtex->norfac; if (tex->type!=TEX_STUCCI) nf *= -1.f; if (mtex->maptoneg & MAP_NORM) nf *= -1.f; mparams["normal"] = yafray::parameter_t(nf/60.f); } // all blender texture modulation as switches, either 1 or -1 (negative state of button) // Csp, specular color modulation if (mtex->mapto & MAP_COLSPEC) mparams["colspec"] = yafray::parameter_t(1.0); // CMir, mirror color modulation if (mtex->mapto & MAP_COLMIR) mparams["colmir"] = yafray::parameter_t(1.0); // Ref, diffuse reflection amount modulation if ((mtex->mapto & MAP_REF) || (mtex->maptoneg & MAP_REF)) { int t = 1; if (mtex->maptoneg & MAP_REF) t = -1; mparams["difref"] = yafray::parameter_t(t); } // Spec, specular amount mod if ((mtex->mapto & MAP_SPEC) || (mtex->maptoneg & MAP_SPEC)) { int t = 1; if (mtex->maptoneg & MAP_SPEC) t = -1; mparams["specular"] = yafray::parameter_t(t); } // hardness modulation if ((mtex->mapto & MAP_HAR) || (mtex->maptoneg & MAP_HAR)) { int t = 1; if (mtex->maptoneg & MAP_HAR) t = -1; mparams["hard"] = yafray::parameter_t(t); } // alpha modulation if ((mtex->mapto & MAP_ALPHA) || (mtex->maptoneg & MAP_ALPHA)) { int t = 1; if (mtex->maptoneg & MAP_ALPHA) t = -1; mparams["alpha"] = yafray::parameter_t(t); } // emit modulation if ((mtex->mapto & MAP_EMIT) || (mtex->maptoneg & MAP_EMIT)) { int t = 1; if (mtex->maptoneg & MAP_EMIT) t = -1; mparams["emit"] = yafray::parameter_t(t); } // raymir modulation if ((mtex->mapto & MAP_RAYMIRR) || (mtex->maptoneg & MAP_RAYMIRR)) { int t = 1; if (mtex->maptoneg & MAP_RAYMIRR) t = -1; mparams["raymir"] = yafray::parameter_t(t); } // texture flag, combination of strings string ts; if (mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE)) { ts = ""; if (mtex->texflag & MTEX_RGBTOINT) ts += "no_rgb "; if (mtex->texflag & MTEX_STENCIL) ts += "stencil "; if (mtex->texflag & MTEX_NEGATIVE) ts += "negative"; mparams["texflag"]=yafray::parameter_t(ts); } // colfac, controls amount of color modulation mparams["colfac"]=yafray::parameter_t(mtex->colfac); // def_var mparams["def_var"]=yafray::parameter_t(mtex->def_var); //varfac mparams["varfac"]=yafray::parameter_t(mtex->varfac); if ((tex->imaflag & (TEX_CALCALPHA | TEX_USEALPHA)) || (tex->flag & TEX_NEGALPHA)) { ts = ""; if (tex->imaflag & TEX_CALCALPHA) ts += "calc_alpha "; if (tex->imaflag & TEX_USEALPHA) ts += "use_alpha "; if (tex->flag & TEX_NEGALPHA) ts += "neg_alpha"; mparams["alpha_flag"] = yafray::parameter_t(ts); } // image as normalmap flag if (tex->imaflag & TEX_NORMALMAP) mparams["normalmap"] = yafray::parameter_t("on"); lparams.push_back(mparams); } } yafrayGate->addShader(params, lparams); } // write all materials & modulators void yafrayPluginRender_t::writeMaterialsAndModulators() { // shaders/mappers for regular texture (or non-texture) mode // In case material has texface mode, and all faces have an image texture, // this shader will not be used, but still be written yafray::paramMap_t params; list lparams; for (map::const_iterator blendmat=used_materials.begin(); blendmat!=used_materials.end();++blendmat) { Material* matr = blendmat->second; // mapper(s) for (int m=0;mseptex & (1<mtex[m]; if (mtex==NULL) continue; // ignore null tex Tex* tex = mtex->tex; if (tex==NULL) continue; map::const_iterator mtexL = used_textures.find(string(tex->id.name)); if (mtexL!=used_textures.end()) { params.clear(); //!!! lparams.clear(); char temp[32]; sprintf(temp, "_map%d", m); params["type"] = yafray::parameter_t("blendermapper"); params["name"] = yafray::parameter_t(blendmat->first + string(temp)); if ((mtex->texco & TEXCO_OBJECT) || (mtex->texco & TEXCO_REFL) || (mtex->texco & TEXCO_NORM)) { // For object, reflection & normal mapping, add the object matrix to the modulator, // as in LF script, use camera matrix if no object specified. // In this case this means the inverse of that matrix float texmat[4][4], itexmat[4][4]; if ((mtex->texco & TEXCO_OBJECT) && (mtex->object)) MTC_Mat4CpyMat4(texmat, mtex->object->obmat); else // also for refl. map MTC_Mat4CpyMat4(texmat, maincam_obj->obmat); MTC_Mat4Invert(itexmat, texmat); #define flp yafray::parameter_t params["m00"]=flp(itexmat[0][0]); params["m01"]=flp(itexmat[1][0]); params["m02"]=flp(itexmat[2][0]); params["m03"]=flp(itexmat[3][0]); params["m10"]=flp(itexmat[0][1]); params["m11"]=flp(itexmat[1][1]); params["m12"]=flp(itexmat[2][1]); params["m13"]=flp(itexmat[3][1]); params["m20"]=flp(itexmat[0][2]); params["m21"]=flp(itexmat[1][2]); params["m22"]=flp(itexmat[2][2]); params["m23"]=flp(itexmat[3][2]); params["m30"]=flp(itexmat[0][3]); params["m31"]=flp(itexmat[1][3]); params["m32"]=flp(itexmat[2][3]); params["m33"]=flp(itexmat[3][3]); #undef flp } // use image name instead of texname when texture is image if ((tex->type==TEX_IMAGE) && tex->ima) params["input"] = yafray::parameter_t(tex->ima->id.name); else if ((tex->flag & TEX_COLORBAND) & (tex->coba!=NULL)) params["input"] = yafray::parameter_t(mtexL->first + "_coba"); else params["input"] = yafray::parameter_t(mtexL->first); // texture size params["sizex"] = yafray::parameter_t(mtex->size[0]); params["sizey"] = yafray::parameter_t(mtex->size[1]); params["sizez"] = yafray::parameter_t(mtex->size[2]); // texture offset params["ofsx"] = yafray::parameter_t(mtex->ofs[0]); params["ofsy"] = yafray::parameter_t(mtex->ofs[1]); params["ofsz"] = yafray::parameter_t(mtex->ofs[2]); // texture coordinates, have to disable 'sticky' in Blender if (mtex->texco & TEXCO_UV) params["texco"] = yafray::parameter_t("uv"); else if ((mtex->texco & TEXCO_GLOB) || (mtex->texco & TEXCO_OBJECT)) // object mode is also set as global, but the object matrix // was specified above with params["texco"] = yafray::parameter_t("global"); else if ((mtex->texco & TEXCO_ORCO) || (mtex->texco & TEXCO_STRAND)) // orco flag now used for 'strand'-mapping as well, see mesh code params["texco"] = yafray::parameter_t("orco"); else if (mtex->texco & TEXCO_WINDOW) params["texco"] = yafray::parameter_t("window"); else if (mtex->texco & TEXCO_NORM) params["texco"] = yafray::parameter_t("normal"); else if (mtex->texco & TEXCO_REFL) params["texco"] = yafray::parameter_t("reflect"); // texture projection axes, both image & procedural string proj = "nxyz"; // 'n' for 'none' params["proj_x"] = yafray::parameter_t(string(1,proj[mtex->projx])); params["proj_y"] = yafray::parameter_t(string(1,proj[mtex->projy])); params["proj_z"] = yafray::parameter_t(string(1,proj[mtex->projz])); // texture mapping parameters only relevant to image type if (tex->type==TEX_IMAGE) { if (mtex->mapping==MTEX_FLAT) params["mapping"] = yafray::parameter_t("flat"); else if (mtex->mapping==MTEX_CUBE) params["mapping"] = yafray::parameter_t("cube"); else if (mtex->mapping==MTEX_TUBE) params["mapping"] = yafray::parameter_t("tube"); else if (mtex->mapping==MTEX_SPHERE) params["mapping"] = yafray::parameter_t("sphere"); // repeat params["xrepeat"] = yafray::parameter_t(tex->xrepeat); params["yrepeat"] = yafray::parameter_t(tex->yrepeat); // clipping if (tex->extend==TEX_EXTEND) params["clipping"] = yafray::parameter_t("extend"); else if (tex->extend==TEX_CLIP) params["clipping"] = yafray::parameter_t("clip"); else if (tex->extend==TEX_CLIPCUBE) params["clipping"] = yafray::parameter_t("clipcube"); else if (tex->extend==TEX_CHECKER) { params["clipping"] = yafray::parameter_t("checker"); string ts = ""; if (tex->flag & TEX_CHECKER_ODD) ts += "odd"; if (tex->flag & TEX_CHECKER_EVEN) ts += " even"; params["checker_mode"] = yafray::parameter_t(ts); params["checker_dist"] = yafray::parameter_t(tex->checkerdist); } else params["clipping"] = yafray::parameter_t("repeat"); // crop min/max params["cropmin_x"] = yafray::parameter_t(tex->cropxmin); params["cropmin_y"] = yafray::parameter_t(tex->cropymin); params["cropmax_x"] = yafray::parameter_t(tex->cropxmax); params["cropmax_y"] = yafray::parameter_t(tex->cropymax); // rot90 flag if (tex->imaflag & TEX_IMAROT) params["rot90"] = yafray::parameter_t("on"); else params["rot90"] = yafray::parameter_t("off"); } yafrayGate->addShader(params, lparams); } } // shader + modulators writeShader(blendmat->first, matr); } // write the mappers & shaders for the TexFace case if (!imagetex.empty()) { // Yafray doesn't have per-face-textures, only per-face-shaders, // so create as many mappers/shaders as the images used by the object params.clear(); lparams.clear(); int snum = 0; for (map >::const_iterator imgtex=imagetex.begin(); imgtex!=imagetex.end();++imgtex) { for (set::const_iterator imgmat=imgtex->second.begin(); imgmat!=imgtex->second.end();++imgmat) { Material* matr = *imgmat; // mapper params["type"] = yafray::parameter_t("blendermapper"); char temp[32]; sprintf(temp, "_ftmap%d", snum); params["name"] = yafray::parameter_t(string(matr->id.name) + string(temp)); params["input"] = yafray::parameter_t(imgtex->first->id.name); // all yafray default settings, except for texco, so no need to set others params["texco"] = yafray::parameter_t("uv"); yafrayGate->addShader(params, lparams); // shader, remember name, used later when writing per-face-shaders sprintf(temp, "_ftsha%d", snum); string shader_name = string(matr->id.name) + string(temp); imgtex_shader[string(matr->id.name) + string(imgtex->first->id.name)] = shader_name; sprintf(temp, "_ftmap%d", snum++); string facetexname = string(matr->id.name) + string(temp); writeShader(shader_name, matr, facetexname); } } } } void yafrayPluginRender_t::genUVcoords(vector &uvcoords, ObjectRen *obr, VlakRen *vlr, MTFace* uvc, bool comple) { if (uvc) { // tri uv split indices int ui1=0, ui2=1, ui3=2; if (vlr->flag & R_DIVIDE_24) { ui3++; if (vlr->flag & R_FACE_SPLIT) { ui1++; ui2++; } } else if (vlr->flag & R_FACE_SPLIT) { ui2++; ui3++; } if (comple) { ui1 = (ui1+2) & 3; ui2 = (ui2+2) & 3; ui3 = (ui3+2) & 3; } uvcoords.push_back(uvc->uv[ui1][0]); uvcoords.push_back(1-uvc->uv[ui1][1]); uvcoords.push_back(uvc->uv[ui2][0]); uvcoords.push_back(1-uvc->uv[ui2][1]); uvcoords.push_back(uvc->uv[ui3][0]); uvcoords.push_back(1-uvc->uv[ui3][1]); } else { uvcoords.push_back(0); uvcoords.push_back(0); uvcoords.push_back(0); uvcoords.push_back(0); uvcoords.push_back(0); uvcoords.push_back(0); } } void yafrayPluginRender_t::genVcol(vector &vcol, ObjectRen *obr, VlakRen *vlr, bool comple) { MCol *mcol= RE_vlakren_get_mcol(obr, vlr, obr->actmcol, NULL, 0); if (mcol) { // tri vcol split indices int ui1=0, ui2=1, ui3=2; if (vlr->flag & R_DIVIDE_24) { ui3++; if (vlr->flag & R_FACE_SPLIT) { ui1++; ui2++; } } else if (vlr->flag & R_FACE_SPLIT) { ui2++; ui3++; } if (comple) { ui1 = (ui1+2) & 3; ui2 = (ui2+2) & 3; ui3 = (ui3+2) & 3; } unsigned char* pt = reinterpret_cast(&mcol[ui1]); vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f); pt = reinterpret_cast(&mcol[ui2]); vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f); pt = reinterpret_cast(&mcol[ui3]); vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f); } else { vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); vcol.push_back(0); } } void yafrayPluginRender_t::genFace(vector &faces,vector &shaders,vector &faceshader, vector &uvcoords,vector &vcol, map &vert_idx,ObjectRen *obr,VlakRen *vlr, int has_orco,bool has_uv) { Material* fmat = vlr->mat; bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0); string fmatname(fmat->id.name); // use name in imgtex_shader list if 'TexFace' enabled for this face material if (fmat->mode & MA_FACETEXTURE) { MTFace* tface = RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); if (tface) { Image* fimg = (Image*)tface->tpage; if (fimg) fmatname = imgtex_shader[fmatname + string(fimg->id.name)]; } } else if (fmatname.length()==0) fmatname = "blender_default"; bool newmat=true; for(unsigned int i=0;iactmtface, NULL, 0); // possible uvcoords (v upside down) int idx1, idx2, idx3; idx1 = vert_idx.find(vlr->v1)->second; idx2 = vert_idx.find(vlr->v2)->second; idx3 = vert_idx.find(vlr->v3)->second; // make sure the indices point to the vertices when orco coords exported if (has_orco) { idx1*=2; idx2*=2; idx3*=2; } faces.push_back(idx1); faces.push_back(idx2); faces.push_back(idx3); if(has_uv) genUVcoords(uvcoords, obr, vlr, uvc); if (EXPORT_VCOL) genVcol(vcol, obr, vlr); } void yafrayPluginRender_t::genCompleFace(vector &faces,/*vector &shaders,*/vector &faceshader, vector &uvcoords,vector &vcol, map &vert_idx,ObjectRen *obr,VlakRen *vlr, int has_orco,bool has_uv) { Material* fmat = vlr->mat; bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0); faceshader.push_back(faceshader.back()); MTFace* uvc = RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); // possible uvcoords (v upside down) int idx1, idx2, idx3; idx1 = vert_idx.find(vlr->v3)->second; idx2 = vert_idx.find(vlr->v4)->second; idx3 = vert_idx.find(vlr->v1)->second; // make sure the indices point to the vertices when orco coords exported if (has_orco) { idx1*=2; idx2*=2; idx3*=2; } faces.push_back(idx1); faces.push_back(idx2); faces.push_back(idx3); if (has_uv) genUVcoords(uvcoords, obr, vlr, uvc, true); if (EXPORT_VCOL) genVcol(vcol, obr, vlr, true); } void yafrayPluginRender_t::genVertices(vector &verts, int &vidx, map &vert_idx, ObjectRen *obr, VlakRen* vlr, int has_orco, Object* obj) { VertRen* ver; float tvec[3]; // for back2world transform // for deformed objects, object->imat is no longer valid, // so have to create inverse render matrix ourselves here float mat[4][4], imat[4][4]; MTC_Mat4MulMat4(mat, obj->obmat, re->viewmat); MTC_Mat4Invert(imat, mat); if (vert_idx.find(vlr->v1)==vert_idx.end()) { vert_idx[vlr->v1] = vidx++; ver = vlr->v1; MTC_cp3Float(ver->co, tvec); MTC_Mat4MulVecfl(imat, tvec); verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2])); // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping if (has_orco==1) verts.push_back(yafray::point3d_t(ver->accum)); else if (has_orco==2) verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2])); } if (vert_idx.find(vlr->v2)==vert_idx.end()) { vert_idx[vlr->v2] = vidx++; ver = vlr->v2; MTC_cp3Float(ver->co, tvec); MTC_Mat4MulVecfl(imat, tvec); verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2])); // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping if (has_orco==1) verts.push_back(yafray::point3d_t(ver->accum)); else if (has_orco==2) verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2])); } if (vert_idx.find(vlr->v3)==vert_idx.end()) { vert_idx[vlr->v3] = vidx++; ver = vlr->v3; MTC_cp3Float(ver->co, tvec); MTC_Mat4MulVecfl(imat, tvec); verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2])); // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping if (has_orco==1) verts.push_back(yafray::point3d_t(ver->accum)); else if (has_orco==2) verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2])); } if ((vlr->v4) && (vert_idx.find(vlr->v4)==vert_idx.end())) { vert_idx[vlr->v4] = vidx++; ver = vlr->v4; MTC_cp3Float(ver->co, tvec); MTC_Mat4MulVecfl(imat, tvec); verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2])); // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping if (has_orco==1) verts.push_back(yafray::point3d_t(ver->accum)); else if (has_orco==2) verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2])); } } void yafrayPluginRender_t::writeObject(Object* obj, ObjectRen *obr, const vector &VLR_list, const float obmat[4][4]) { float mtr[4*4]; 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]; 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]; 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]; 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]; yafrayGate->transformPush(mtr); VlakRen* face0 = VLR_list[0]; Material* face0mat = face0->mat; bool castShadows = face0mat->mode & MA_TRACEBLE; float caus_IOR=1.0; yafray::color_t caus_tcolor(0.0, 0.0, 0.0), caus_rcolor(0.0, 0.0, 0.0); bool caus = (((face0->mat->mode & MA_RAYTRANSP) | (face0->mat->mode & MA_RAYMIRROR))!=0); if (caus) { caus_IOR = face0mat->ang; float tr = 1.0-face0mat->alpha; caus_tcolor.set(face0mat->r*tr, face0mat->g*tr, face0mat->b*tr); tr = face0mat->ray_mirror; caus_rcolor.set(face0mat->mirr*tr, face0mat->mirg*tr, face0mat->mirb*tr); } // Export orco coords test. // Previously was done by checking orco pointer, however this can be non-null but still not initialized. // Test the rendermaterial texco flag instead. // update2: bug #3193 it seems it has changed again with the introduction of static 'hair' particles, // now it uses the vert pointer again as an extra test to make sure there are orco coords available int has_orco = 0; if (face0mat->texco & TEXCO_STRAND) has_orco = 1; else has_orco = (((face0mat->texco & TEXCO_ORCO)!=0) && (face0->v1->orco!=NULL)) ? 2 : 0; bool no_auto = true; //in case non-mesh, or mesh has no autosmooth float sm_angle = 0.1f; if (obj->type==OB_MESH) { Mesh* mesh = (Mesh*)obj->data; if (mesh->flag & ME_AUTOSMOOTH) { sm_angle = mesh->smoothresh; no_auto = false; } } // this for non-mesh as well if (no_auto) { // no per face smooth flag in yafray, if AutoSmooth not used, // use smooth flag of the first face instead if (face0->flag & ME_SMOOTH) sm_angle=180; } vector verts; vector vcol; // now all vertices map vert_idx; // for removing duplicate verts and creating an index list int vidx = 0; // vertex index counter bool has_uv=false; for (vector::const_iterator fci=VLR_list.begin(); fci!=VLR_list.end();++fci) { VlakRen* vlr = *fci; genVertices(verts, vidx, vert_idx, obr, vlr, has_orco, obj); if(RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0)) has_uv=true; } // all faces using the index list created above vector faces; vector shaders; vector faceshader; vector uvcoords; for (vector::const_iterator fci2=VLR_list.begin(); fci2!=VLR_list.end();++fci2) { VlakRen* vlr = *fci2; genFace(faces, shaders, faceshader, uvcoords, vcol, vert_idx, obr, vlr, has_orco, has_uv); if (vlr->v4) genCompleFace(faces, faceshader, uvcoords, vcol, vert_idx, obr, vlr, has_orco, has_uv); } // using the ObjectRen database, contruct a new name if object has a parent. // This is done to prevent name clashes (group/library link related) string obname(obj->id.name); // previous implementation, keep around, in case this is still useful //if (obj->id.flag & (LIB_EXTERN|LIB_INDIRECT))obname = "lib_" + obname; ObjectRen *obren; for (obren = static_cast(re->objecttable.first); obren; obren=static_cast(obren->next)) { Object *db_ob = obren->ob, *db_par = obren->par; if (db_ob==obj) if ((db_ob!=NULL) && (db_par!=NULL)) { obname += "_" + string(db_par->id.name); break; } } yafrayGate->addObject_trimesh(obname, verts, faces, uvcoords, vcol, shaders, faceshader, sm_angle, castShadows, true, true, caus, has_orco, caus_rcolor, caus_tcolor, caus_IOR); yafrayGate->transformPop(); } // write all objects void yafrayPluginRender_t::writeAllObjects() { // first all objects except dupliverts (and main instance object for dups) for (map::const_iterator obi=all_objects.begin(); obi!=all_objects.end(); ++obi) { // skip main duplivert object if in dupliMtx_list, written later Object* obj = obi->first; if (dupliMtx_list.find(string(obj->id.name))!=dupliMtx_list.end()) continue; writeObject(obj, obi->second.obr, obi->second.faces, obj->obmat); } // Now all duplivert objects (if any) as instances of main object // The original object has been included in the VlakRen renderlist above (see convertBlenderScene.c) // but is written here which all other duplis are instances of. float obmat[4][4], cmat[4][4], imat[4][4], nmat[4][4]; for (map >::const_iterator dupMtx=dupliMtx_list.begin(); dupMtx!=dupliMtx_list.end();++dupMtx) { // original inverse matrix, not actual matrix of object, but first duplivert. for (int i=0;i<4;i++) for (int j=0;j<4;j++) obmat[i][j] = dupMtx->second[(i<<2)+j]; MTC_Mat4Invert(imat, obmat); // first object written as normal (but with transform of first duplivert) Object* obj = dup_srcob[dupMtx->first]; writeObject(obj, all_objects[obj].obr, all_objects[obj].faces, obmat); // all others instances of first for (unsigned int curmtx=16;curmtxsecond.size();curmtx+=16) { // number of 4x4 matrices // new mtx for (int i=0;i<4;i++) for (int j=0;j<4;j++) nmat[i][j] = dupMtx->second[curmtx+(i<<2)+j]; MTC_Mat4MulMat4(cmat, imat, nmat); // transform with respect to original = inverse_original * new float mtr[4*4]; 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]; 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]; 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]; 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]; yafrayGate->transformPush(mtr); // new name from original string name=(obj->id.name); char temp[16]; sprintf(temp,"_dup%d",(curmtx>>4)); name+=temp; yafrayGate->addObject_reference(name,obj->id.name); yafrayGate->transformPop(); } } } void yafrayPluginRender_t::writeAreaLamp(LampRen* lamp, int num, float iview[4][4]) { yafray::paramMap_t params; if (lamp->area_shape!=LA_AREA_SQUARE) return; float *a=lamp->area[0], *b=lamp->area[1], *c=lamp->area[2], *d=lamp->area[3]; float power=lamp->energy; string md = "off"; // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; power*=re->r.GIpower; } params["type"]=yafray::parameter_t("arealight"); char temp[16]; sprintf(temp,"LAMP%d",num+1); params["name"]=yafray::parameter_t(temp); params["dummy"]=yafray::parameter_t(md); params["power"]=yafray::parameter_t(power); // samples not used for GI with photons, can still be exported, is ignored int psm=0, sm = lamp->ray_totsamp; if (sm>=25) psm = sm/5; params["samples"]=yafray::parameter_t(sm); params["psamples"]=yafray::parameter_t(psm); // transform area lamp coords back to world float lpco[4][3]; MTC_cp3Float(a, lpco[0]); MTC_Mat4MulVecfl(iview, lpco[0]); MTC_cp3Float(b, lpco[1]); MTC_Mat4MulVecfl(iview, lpco[1]); MTC_cp3Float(c, lpco[2]); MTC_Mat4MulVecfl(iview, lpco[2]); MTC_cp3Float(d, lpco[3]); MTC_Mat4MulVecfl(iview, lpco[3]); params["a"] = yafray::parameter_t(yafray::point3d_t(lpco[0][0], lpco[0][1], lpco[0][2])); params["b"] = yafray::parameter_t(yafray::point3d_t(lpco[1][0], lpco[1][1], lpco[1][2])); params["c"] = yafray::parameter_t(yafray::point3d_t(lpco[2][0], lpco[2][1], lpco[2][2])); params["d"] = yafray::parameter_t(yafray::point3d_t(lpco[3][0], lpco[3][1], lpco[3][2])); params["color"]=yafray::parameter_t(yafray::color_t(lamp->r,lamp->g,lamp->b)); yafrayGate->addLight(params); } void yafrayPluginRender_t::writeLamps() { GroupObject *go; int i=0; // inver viewmatrix needed for back2world transform float iview[4][4]; // re->viewinv != inv.re->viewmat because of possible ortho mode (see convertBlenderScene.c) // have to invert it here MTC_Mat4Invert(iview, re->viewmat); // all lamps for(go=(GroupObject *)re->lights.first; go; go= go->next, i++) { LampRen* lamp = (LampRen *)go->lampren; yafray::paramMap_t params; string type=""; if (lamp->type==LA_AREA) { writeAreaLamp(lamp, i, iview); continue; } // TODO: add decay setting in yafray bool is_softL=false, is_sphereL=false; if (lamp->type==LA_LOCAL) { if (lamp->mode & LA_YF_SOFT) { // shadowmapped omnidirectional light params["type"] = yafray::parameter_t("softlight"); is_softL = true; } else if ((lamp->mode & LA_SHAD_RAY) && (lamp->YF_ltradius>0.0)) { // area sphere, only when ray shadows enabled and radius>0.0 params["type"] = yafray::parameter_t("spherelight"); is_sphereL = true; } else params["type"] = yafray::parameter_t("pointlight"); params["glow_intensity"] = yafray::parameter_t(lamp->YF_glowint); params["glow_offset"] = yafray::parameter_t(lamp->YF_glowofs); params["glow_type"] = yafray::parameter_t(lamp->YF_glowtype); } else if (lamp->type==LA_SPOT) params["type"] = yafray::parameter_t("spotlight"); else if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI)) // hemi exported as sun params["type"] = yafray::parameter_t("sunlight"); else if (lamp->type==LA_YF_PHOTON) params["type"] = yafray::parameter_t("photonlight"); else { // possibly unknown type, ignore cout << "Unknown Blender lamp type: " << lamp->type << endl; continue; } //no name available here, create one char temp[16]; sprintf(temp,"LAMP%d",i+1); params["name"] = yafray::parameter_t(temp); // color already premultiplied by energy, so only need distance here float pwr = 1; // default for sun/hemi, distance irrelevant if ((lamp->type!=LA_SUN) && (lamp->type!=LA_HEMI)) { if (lamp->mode & LA_SPHERE) { // best approx. as used in LFexport script (LF d.f.m. 4pi?) pwr = lamp->dist*(lamp->dist+1)*(0.25/M_PI); //decay = 2; } else { pwr = lamp->dist; //decay = 1; } } if (is_sphereL) { // 'dummy' mode for spherelight when used with gpm string md = "off"; // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; pwr*=re->r.GIpower; } params["power"] = yafray::parameter_t(pwr); params["dummy"] = yafray::parameter_t(md); } else params["power"] = yafray::parameter_t(pwr); // cast_shadows flag not used with softlight, spherelight or photonlight if ((!is_softL) && (!is_sphereL) && (lamp->type!=LA_YF_PHOTON)) { string lpmode="off"; // Blender hemilights exported as sunlights which might have shadow flag set // should have cast_shadows set to off (reported by varuag) if (lamp->type!=LA_HEMI) { if (re->r.mode & R_SHADOW) { // old bug was here since the yafray lamp settings panel was added, // blender spotlight shadbuf flag should be ignored, since it is not in the panel anymore if (lamp->mode & LA_SHAD_RAY) lpmode="on"; } } params["cast_shadows"] = yafray::parameter_t(lpmode); } // spot specific stuff bool has_halo = ((lamp->type==LA_SPOT) && (lamp->mode & LA_HALO) && (lamp->haint>0.0)); if (lamp->type==LA_SPOT) { // conversion already changed spotsize to cosine of half angle float ld = 1-lamp->spotsi; //convert back to blender slider setting if (ld!=0) ld = 1.f/ld; params["size"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI); params["blend"] = yafray::parameter_t(lamp->spotbl*ld); params["beam_falloff"] = yafray::parameter_t(2.0); // halo params if (has_halo) { params["halo"] = yafray::parameter_t("on"); params["res"] = yafray::parameter_t(lamp->YF_bufsize); int hsmp = ((12-lamp->shadhalostep)*16)/12; hsmp = (hsmp+1)*16; // makes range (16, 272) for halostep(12, 0), good enough? // halo 'samples' now 'stepsize' // convert from old integer samples value to some reasonable stepsize params["stepsize"] = yafray::parameter_t(1.0/sqrt((float)hsmp)); params["shadow_samples"] = yafray::parameter_t(lamp->samp*lamp->samp); params["halo_blur"] = yafray::parameter_t(0.0); params["shadow_blur"] = yafray::parameter_t(lamp->soft*0.01f); params["fog_density"] = yafray::parameter_t(lamp->haint*0.2f); } } else if (is_softL) { // softlight params["res"] = yafray::parameter_t(lamp->YF_bufsize); params["radius"] = yafray::parameter_t(lamp->soft); params["bias"] = yafray::parameter_t(lamp->bias); } else if (is_sphereL) { // spherelight int psm=0, sm = lamp->ray_samp*lamp->ray_samp; if (sm>=25) psm = sm/5; params["radius"] = yafray::parameter_t(lamp->YF_ltradius); params["samples"] = yafray::parameter_t(sm); params["psamples"] = yafray::parameter_t(psm); params["qmc_method"] = yafray::parameter_t(1); } else if (lamp->type==LA_YF_PHOTON) { string qmc="off"; if (lamp->YF_useqmc) qmc="on"; params["photons"] = yafray::parameter_t(lamp->YF_numphotons); params["search"] = yafray::parameter_t(lamp->YF_numsearch); params["depth"] = yafray::parameter_t(lamp->YF_phdepth); params["use_QMC"] = yafray::parameter_t(qmc); params["angle"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI); float cl = lamp->YF_causticblur/sqrt((float)lamp->YF_numsearch); params["fixedradius"] = yafray::parameter_t(lamp->YF_causticblur); params["cluster"] = yafray::parameter_t(cl); } // transform lamp co & vec back to world float lpco[3], lpvec[3]; MTC_cp3Float(lamp->co, lpco); MTC_Mat4MulVecfl(iview, lpco); MTC_cp3Float(lamp->vec, lpvec); MTC_Mat4Mul3Vecfl(iview, lpvec); // position, (==-blendir for sun/hemi) if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI)) params["from"] = yafray::parameter_t(yafray::point3d_t(-lpvec[0], -lpvec[1], -lpvec[2])); else params["from"] = yafray::parameter_t(yafray::point3d_t(lpco[0], lpco[1], lpco[2])); // 'to' for spot/photonlight, already calculated by Blender if ((lamp->type==LA_SPOT) || (lamp->type==LA_YF_PHOTON)) { params["to"] = yafray::parameter_t(yafray::point3d_t(lpco[0] + lpvec[0], lpco[1] + lpvec[1], lpco[2] + lpvec[2])); if (has_halo) params["fog"] = yafray::parameter_t(yafray::color_t(1.0, 1.0, 1.0)); } // color // rgb in LampRen is premultiplied by energy, power is compensated for that above params["color"] = yafray::parameter_t(yafray::color_t(lamp->r, lamp->g, lamp->b)); yafrayGate->addLight(params); } } // write main camera void yafrayPluginRender_t::writeCamera() { yafray::paramMap_t params; params["name"]=yafray::parameter_t("MAINCAM"); if (re->r.mode & R_ORTHO) params["type"] = yafray::parameter_t("ortho"); else params["type"] = yafray::parameter_t("perspective"); params["resx"] = yafray::parameter_t(re->winx); params["resy"] = yafray::parameter_t(re->winy); float f_aspect = 1; if ((re->winx * re->r.xasp) <= (re->winy * re->r.yasp)) f_aspect = float(re->winx * re->r.xasp) / float(re->winy * re->r.yasp); params["focal"] = yafray::parameter_t(mainCamLens/(f_aspect*32.f)); // bug #4532, when field rendering is enabled, ycor is doubled if (re->r.mode & R_FIELDS) params["aspect_ratio"] = yafray::parameter_t(re->ycor * 0.5f); else params["aspect_ratio"] = yafray::parameter_t(re->ycor); // dof params, only valid for real camera float fdist = 1; // only changes for ortho if (maincam_obj->type==OB_CAMERA) { Camera* cam = (Camera*)maincam_obj->data; if (re->r.mode & R_ORTHO) fdist = cam->ortho_scale*(mainCamLens/32.f); params["dof_distance"] = yafray::parameter_t(cam->YF_dofdist); params["aperture"] = yafray::parameter_t(cam->YF_aperture); if (cam->flag & CAM_YF_NO_QMC) params["use_qmc"] = yafray::parameter_t("off"); else params["use_qmc"] = yafray::parameter_t("on"); // bokeh params string st = "disk1"; if (cam->YF_bkhtype==1) st = "disk2"; else if (cam->YF_bkhtype==2) st = "triangle"; else if (cam->YF_bkhtype==3) st = "square"; else if (cam->YF_bkhtype==4) st = "pentagon"; else if (cam->YF_bkhtype==5) st = "hexagon"; else if (cam->YF_bkhtype==6) st = "ring"; params["bokeh_type"] = yafray::parameter_t(st); st = "uniform"; if (cam->YF_bkhbias==1) st = "center"; else if (cam->YF_bkhbias==2) st = "edge"; params["bokeh_bias"] = yafray::parameter_t(st); params["bokeh_rotation"] = yafray::parameter_t(cam->YF_bkhrot); } params["from"]=yafray::parameter_t( yafray::point3d_t(maincam_obj->obmat[3][0], maincam_obj->obmat[3][1], maincam_obj->obmat[3][2])); params["to"]=yafray::parameter_t( yafray::point3d_t(maincam_obj->obmat[3][0] - fdist * re->viewmat[0][2], maincam_obj->obmat[3][1] - fdist * re->viewmat[1][2], maincam_obj->obmat[3][2] - fdist * re->viewmat[2][2])); params["up"]=yafray::parameter_t( yafray::point3d_t(maincam_obj->obmat[3][0] + re->viewmat[0][1], maincam_obj->obmat[3][1] + re->viewmat[1][1], maincam_obj->obmat[3][2] + re->viewmat[2][1])); yafrayGate->addCamera(params); } void yafrayPluginRender_t::writeHemilight() { yafray::paramMap_t params; World *world = G.scene->world; bool fromAO = false; if (re->r.GIquality==6){ // use Blender AO params is possible if (world==NULL) return; if ((world->mode & WO_AMB_OCC)==0) { // no AO, use default GIquality cout << "[Warning]: Can't use AO parameters\nNo ambient occlusion enabled, using default values instead" << endl; } else fromAO = true; } if (re->r.GIcache) { params["type"] = yafray::parameter_t("pathlight"); params["name"] = yafray::parameter_t("path_LT"); params["power"] = yafray::parameter_t(re->r.GIpower); params["mode"] = yafray::parameter_t("occlusion"); params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off"); if (fromAO) { // for AO, with cache, using range of 32*1 to 32*16 seems good enough params["samples"] = yafray::parameter_t(32*world->aosamp); params["maxdistance"] = yafray::parameter_t(world->aodist); } else { switch (re->r.GIquality) { case 1 : params["samples"] = yafray::parameter_t(128); break; case 2 : params["samples"] = yafray::parameter_t(256); break; case 3 : params["samples"] = yafray::parameter_t(512); break; case 4 : params["samples"] = yafray::parameter_t(1024); break; case 5 : params["samples"] = yafray::parameter_t(2048); break; default: params["samples"] = yafray::parameter_t(256); } } params["cache"] = yafray::parameter_t("on"); params["use_QMC"] = yafray::parameter_t("on"); params["threshold"] = yafray::parameter_t(re->r.GIrefinement); params["cache_size"] = yafray::parameter_t((2.0/float(re->winx))*re->r.GIpixelspersample); params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality); params["grid"] = yafray::parameter_t(82); params["search"] = yafray::parameter_t(35); } else { params["type"] = yafray::parameter_t("hemilight"); params["name"] = yafray::parameter_t("hemi_LT"); params["power"] = yafray::parameter_t(re->r.GIpower); if (fromAO) { // use minimum of 4 samples for lowest sample setting, single sample way too noisy params["samples"] = yafray::parameter_t(3 + world->aosamp*world->aosamp); params["maxdistance"] = yafray::parameter_t(world->aodist); params["use_QMC"] = yafray::parameter_t((world->aomode & WO_AORNDSMP) ? "off" : "on"); } else { switch (re->r.GIquality) { case 1 : case 2 : params["samples"]=yafray::parameter_t(16); break; case 3 : params["samples"]=yafray::parameter_t(36); break; case 4 : params["samples"]=yafray::parameter_t(64); break; case 5 : params["samples"]=yafray::parameter_t(128); break; default: params["samples"]=yafray::parameter_t(25); } } } yafrayGate->addLight(params); } void yafrayPluginRender_t::writePathlight() { if (re->r.GIphotons) { yafray::paramMap_t params; params["type"] = yafray::parameter_t("globalphotonlight"); params["name"] = yafray::parameter_t("gpm"); params["photons"] = yafray::parameter_t(re->r.GIphotoncount); params["radius"] = yafray::parameter_t(re->r.GIphotonradius); params["depth"] = yafray::parameter_t(((re->r.GIdepth>2) ? (re->r.GIdepth-1) : 1)); params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth); params["search"] = yafray::parameter_t(re->r.GImixphotons); yafrayGate->addLight(params); } yafray::paramMap_t params; params["type"] = yafray::parameter_t("pathlight"); params["name"] = yafray::parameter_t("path_LT"); params["power"] = yafray::parameter_t(re->r.GIindirpower); params["depth"] = yafray::parameter_t(((re->r.GIphotons) ? 1 : re->r.GIdepth)); params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth); if (re->r.GIdirect && re->r.GIphotons) params["direct"] = yafray::parameter_t("on"); if (re->r.GIcache && !(re->r.GIdirect && re->r.GIphotons)) { switch (re->r.GIquality) { case 1 : params["samples"] = yafray::parameter_t(128); break; case 2 : params["samples"] = yafray::parameter_t(256); break; case 3 : params["samples"] = yafray::parameter_t(512); break; case 4 : params["samples"] = yafray::parameter_t(1024); break; case 5 : params["samples"] = yafray::parameter_t(2048); break; default: params["samples"] = yafray::parameter_t(256); } params["cache"] = yafray::parameter_t("on"); params["use_QMC"] = yafray::parameter_t("on"); params["threshold"] = yafray::parameter_t(re->r.GIrefinement); params["cache_size"] = yafray::parameter_t((2.0/float(re->recty))*re->r.GIpixelspersample); params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality); params["grid"] = yafray::parameter_t(82); params["search"] = yafray::parameter_t(35); params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off"); } else { switch (re->r.GIquality) { case 1 : params["samples"] = yafray::parameter_t(16); break; case 2 : params["samples"] = yafray::parameter_t(36); break; case 3 : params["samples"] = yafray::parameter_t(64); break; case 4 : params["samples"] = yafray::parameter_t(128); break; case 5 : params["samples"] = yafray::parameter_t(256); break; default: params["samples"] = yafray::parameter_t(25); } } yafrayGate->addLight(params); } bool yafrayPluginRender_t::writeWorld() { World *world = G.scene->world; if (re->r.GIquality!=0) { if (re->r.GImethod==1) { if (world==NULL) cout << "WARNING: need world background for skydome!\n"; writeHemilight(); } else if (re->r.GImethod==2) writePathlight(); } if (world==NULL) return false; yafray::paramMap_t params; for (int i=0;imtex[i]; if (!wtex) continue; Image* wimg = wtex->tex->ima; // now always exports if image used as world texture (and 'Hori' mapping enabled) if ((wtex->tex->type==TEX_IMAGE) && (wimg!=NULL) && (wtex->mapto & WOMAP_HORIZ)) { string wt_path = wimg->name; adjustPath(wt_path); params["type"] = yafray::parameter_t("image"); params["name"] = yafray::parameter_t("world_background"); // exposure_adjust not restricted to integer range anymore params["exposure_adjust"] = yafray::parameter_t(wtex->tex->bright-1.f); if (wtex->texco & TEXCO_ANGMAP) params["mapping"] = yafray::parameter_t("probe"); else if (wtex->texco & TEXCO_H_SPHEREMAP) // in yafray full sphere params["mapping"] = yafray::parameter_t("sphere"); else // assume 'tube' for anything else params["mapping"] = yafray::parameter_t("tube"); params["filename"] = yafray::parameter_t(wt_path); params["interpolate"] = yafray::parameter_t((wtex->tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none"); if (wtex->tex->filtersize>1.f) params["prefilter"] = yafray::parameter_t("on"); yafrayGate->addBackground(params); return true; } } params.clear(); params["type"] = yafray::parameter_t("constant"); params["name"] = yafray::parameter_t("world_background"); // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it // (have to change method to init yafray vars in Blender) float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower; params["color"]=yafray::parameter_t(yafray::color_t(world->horr * bg_mult, world->horg * bg_mult, world->horb * bg_mult)); yafrayGate->addBackground(params); return true; } bool blenderYafrayOutput_t::putPixel(int x, int y, const yafray::color_t &c, yafray::CFLOAT alpha, yafray::PFLOAT depth) { // XXX how to get the image from Blender and write to it. This call doesn't allow to change buffer rects RenderResult rres; RE_GetResultImage(re, &rres); // rres.rectx, rres.recty is width/height // rres.rectf is float buffer, scanlines starting in bottom // rres.rectz is zbuffer, available when associated pass is set const unsigned int maxy = rres.recty-1; if (re->r.mode & R_BORDER) { // border render, blender renderwin is size of border region, // but yafray returns coords relative to full resolution x -= int(re->r.border.xmin * re->winx); y -= int((1.f-re->r.border.ymax) * re->winy); if ((x >= 0) && (x < re->rectx) && (y >= 0) && (y < re->recty)) { const unsigned int px = rres.rectx*(maxy - y); // rgba float* fpt = rres.rectf + ((px + x) << 2); *fpt++ = c.R; *fpt++ = c.G; *fpt++ = c.B; *fpt = alpha; // depth values if (rres.rectz) rres.rectz[px + x] = depth; // to simplify things a bit, just do complete redraw here... out++; if ((out==4096) || ((x+y*re->rectx) == ((re->rectx-1)+(re->recty-1)*re->rectx))) { re->result->renlay = render_get_active_layer(re, re->result); re->display_draw(re->result, NULL); out = 0; } } if (re->test_break()) return false; return true; } const unsigned int px = (maxy - y)*rres.rectx; // rgba float* fpt = rres.rectf + ((px + x) << 2); *fpt++ = c.R; *fpt++ = c.G; *fpt++ = c.B; *fpt = alpha; // depth values if (rres.rectz) rres.rectz[px + x] = depth; // attempt to optimize drawing, by only drawing the tile currently rendered by yafray, // and not the entire display every time (blender has to to do float->char conversion), // but since the tile is not actually known, it has to be calculated from the coords. // not sure if it really makes all that much difference at all... unless rendering really large pictures // (renderwin.c also had to be adapted for this) // tile start & end coords const int txs = x & 0xffffffc0, tys = y & 0xffffffc0; int txe = txs + 63, tye = tys + 63; // tile border clip if (txe >= rres.rectx) txe = rres.rectx-1; if (tye >= rres.recty) tye = maxy; // draw tile if last pixel reached if ((y*rres.rectx + x) == (tye*rres.rectx + txe)) { re->result->renlay = render_get_active_layer(re, re->result); // note: ymin/ymax swapped here, img. upside down! rcti rt = {txs, txe+1, maxy-tye, ((tys==0) ? maxy : (rres.recty-tys))}; // !!! tys can be zero re->display_draw(re->result, &rt); } if (re->test_break()) return false; return true; }