3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * Contributors: 2004/2005/2006 Blender Foundation, full recode
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/render/intern/source/envmap.c
35 /* external modules: */
36 #include "MEM_guardedalloc.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_threads.h"
41 #include "BLI_utildefines.h"
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h" /* for rectcpy */
46 #include "DNA_group_types.h"
47 #include "DNA_image_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_texture_types.h"
52 #include "BKE_library.h"
54 #include "BKE_image.h" // BKE_write_ibuf
55 #include "BKE_texture.h"
61 #include "render_types.h"
62 #include "renderpipeline.h"
64 #include "rendercore.h"
65 #include "renderdatabase.h"
68 #include "initrender.h"
71 /* ------------------------------------------------------------------------- */
73 static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
77 /* after lock we test cube[1], if set the other thread has done it fine */
78 BLI_lock_thread(LOCK_IMAGE);
79 if (env->cube[1]==NULL) {
81 BKE_free_envmapdata(env);
85 if (3*dx == ibuf->x) {
89 else if (ibuf->x == ibuf->y) {
90 env->type = ENV_PLANE;
94 printf("Incorrect envmap size\n");
100 if (env->type == ENV_CUBE) {
101 for (part=0; part<6; part++) {
102 env->cube[part]= IMB_allocImBuf(dx, dx, 24, IB_rect|IB_rectfloat);
104 IMB_float_from_rect(ibuf);
106 IMB_rectcpy(env->cube[0], ibuf,
108 IMB_rectcpy(env->cube[1], ibuf,
109 0, 0, dx, 0, dx, dx);
110 IMB_rectcpy(env->cube[2], ibuf,
111 0, 0, 2*dx, 0, dx, dx);
112 IMB_rectcpy(env->cube[3], ibuf,
113 0, 0, 0, dx, dx, dx);
114 IMB_rectcpy(env->cube[4], ibuf,
115 0, 0, dx, dx, dx, dx);
116 IMB_rectcpy(env->cube[5], ibuf,
117 0, 0, 2*dx, dx, dx, dx);
120 else { /* ENV_PLANE */
121 env->cube[1]= IMB_dupImBuf(ibuf);
122 IMB_float_from_rect(env->cube[1]);
126 BLI_unlock_thread(LOCK_IMAGE);
129 /* ------------------------------------------------------------------------- */
130 /* ****************** RENDER ********************** */
132 /* copy current render */
133 static Render *envmap_render_copy(Render *re, EnvMap *env)
139 envre= RE_NewRender("Envmap");
141 env->lastsize= re->r.size;
142 cuberes = (env->cuberes * re->r.size) / 100;
145 /* this flag has R_ZTRA in it for example */
146 envre->flag= re->flag;
148 /* set up renderdata */
150 envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
151 envre->r.layers.first= envre->r.layers.last= NULL;
152 envre->r.filtertype= 0;
153 envre->r.xparts= envre->r.yparts= 2;
155 envre->r.yasp= envre->r.xasp= 1;
157 RE_InitState(envre, NULL, &envre->r, NULL, cuberes, cuberes, NULL);
158 envre->scene= re->scene; /* unsure about this... */
161 /* view stuff in env render */
162 viewscale= (env->type == ENV_PLANE)? env->viewscale: 1.0f;
163 RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend);
166 envre->display_draw= re->display_draw;
168 envre->test_break= re->test_break;
171 /* and for the evil stuff; copy the database... */
172 envre->totvlak= re->totvlak;
173 envre->totvert= re->totvert;
174 envre->tothalo= re->tothalo;
175 envre->totstrand= re->totstrand;
176 envre->totlamp= re->totlamp;
177 envre->sortedhalos= re->sortedhalos;
178 envre->lights= re->lights;
179 envre->objecttable= re->objecttable;
180 envre->customdata_names= re->customdata_names;
181 envre->raytree= re->raytree;
182 envre->totinstance= re->totinstance;
183 envre->instancetable= re->instancetable;
184 envre->objectinstance= re->objectinstance;
185 envre->qmcsamplers= re->qmcsamplers;
190 static void envmap_free_render_copy(Render *envre)
198 envre->totinstance= 0;
199 envre->sortedhalos= NULL;
200 envre->lights.first= envre->lights.last= NULL;
201 envre->objecttable.first= envre->objecttable.last= NULL;
202 envre->customdata_names.first= envre->customdata_names.last= NULL;
203 envre->raytree= NULL;
204 envre->instancetable.first= envre->instancetable.last= NULL;
205 envre->objectinstance= NULL;
206 envre->qmcsamplers= NULL;
208 RE_FreeRender(envre);
211 /* ------------------------------------------------------------------------- */
213 static void envmap_transmatrix(float mat[][4], int part)
215 float tmat[4][4], eul[3], rotmat[4][4];
217 eul[0]= eul[1]= eul[2]= 0.0;
219 if (part==0) { /* neg z */
222 else if (part==1) { /* pos z */
225 else if (part==2) { /* pos y */
228 else if (part==3) { /* neg x */
232 else if (part==4) { /* neg y */
241 copy_m4_m4(tmat, mat);
242 eul_to_mat4( rotmat,eul);
243 mul_serie_m4(mat, tmat, rotmat,
248 /* ------------------------------------------------------------------------- */
250 static void env_rotate_scene(Render *re, float mat[][4], int mode)
254 ObjectInstanceRen *obi;
257 float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
261 invert_m4_m4(tmat, mat);
262 copy_m3_m4(imat, tmat);
265 copy_m4_m4(tmat, mat);
266 copy_m3_m4(imat, mat);
269 for (obi=re->instancetable.first; obi; obi=obi->next) {
270 /* append or set matrix depending on dupli */
271 if (obi->flag & R_DUPLI_TRANSFORMED) {
272 copy_m4_m4(tmpmat, obi->mat);
273 mult_m4_m4m4(obi->mat, tmat, tmpmat);
276 copy_m4_m4(obi->mat, tmat);
280 copy_m3_m4(cmat, obi->mat);
281 invert_m3_m3(obi->nmat, cmat);
282 transpose_m3(obi->nmat);
284 /* indicate the renderer has to use transform matrices */
286 obi->flag &= ~R_ENV_TRANSFORMED;
288 obi->flag |= R_ENV_TRANSFORMED;
292 for (obr=re->objecttable.first; obr; obr=obr->next) {
293 for (a=0; a<obr->tothalo; a++) {
294 if ((a & 255)==0) har= obr->bloha[a>>8];
297 mul_m4_v3(tmat, har->co);
301 for (go=re->lights.first; go; go= go->next) {
304 /* removed here some horrible code of someone in NaN who tried to fix
305 * prototypes... just solved by introducing a correct cmat[3][3] instead
306 * of using smat. this works, check square spots in reflections (ton) */
307 copy_m3_m3(cmat, lar->imat);
308 mul_m3_m3m3(lar->imat, cmat, imat);
310 mul_m3_v3(imat, lar->vec);
311 mul_m4_v3(tmat, lar->co);
313 lar->sh_invcampos[0]= -lar->co[0];
314 lar->sh_invcampos[1]= -lar->co[1];
315 lar->sh_invcampos[2]= -lar->co[2];
316 mul_m3_v3(lar->imat, lar->sh_invcampos);
317 lar->sh_invcampos[2]*= lar->sh_zfac;
321 invert_m4_m4(pmat, mat);
322 mult_m4_m4m4(smat, lar->shb->viewmat, pmat);
323 mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat);
325 else mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat);
331 /* ------------------------------------------------------------------------- */
333 static void env_layerflags(Render *re, unsigned int notlay)
339 /* invert notlay, so if face is in multiple layers it will still be visible,
340 * unless all 'notlay' bits match the face bits.
344 * now (face & ~not) is true
349 for (obr=re->objecttable.first; obr; obr=obr->next) {
350 if ((obr->lay & notlay)==0) {
351 for (a=0; a<obr->totvlak; a++) {
352 if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
355 vlr->flag |= R_HIDDEN;
361 static void env_hideobject(Render *re, Object *ob)
367 for (obr=re->objecttable.first; obr; obr=obr->next) {
368 for (a=0; a<obr->totvlak; a++) {
369 if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
373 vlr->flag |= R_HIDDEN;
378 static void env_showobjects(Render *re)
384 for (obr=re->objecttable.first; obr; obr=obr->next) {
385 for (a=0; a<obr->totvlak; a++) {
386 if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
389 vlr->flag &= ~R_HIDDEN;
394 /* ------------------------------------------------------------------------- */
396 static void env_set_imats(Render *re)
401 base= re->scene->base.first;
403 mult_m4_m4m4(mat, re->viewmat, base->object->obmat);
404 invert_m4_m4(base->object->imat, mat);
411 /* ------------------------------------------------------------------------- */
413 static void render_envmap(Render *re, EnvMap *env)
415 /* only the cubemap and planar map is implemented */
419 float oldviewinv[4][4], mat[4][4], tmat[4][4];
422 /* need a recalc: ortho-render has no correct viewinv */
423 invert_m4_m4(oldviewinv, re->viewmat);
425 envre= envmap_render_copy(re, env);
427 /* precalc orthmat for object */
428 copy_m4_m4(orthmat, env->object->obmat);
429 normalize_m4(orthmat);
431 /* need imat later for texture imat */
432 mult_m4_m4m4(mat, re->viewmat, orthmat);
433 invert_m4_m4(tmat, mat);
434 copy_m3_m4(env->obimat, tmat);
436 for (part=0; part<6; part++) {
437 if (env->type==ENV_PLANE && part!=1)
440 re->display_clear(re->dch, envre->result);
442 copy_m4_m4(tmat, orthmat);
443 envmap_transmatrix(tmat, part);
444 invert_m4_m4(mat, tmat);
445 /* mat now is the camera 'viewmat' */
447 copy_m4_m4(envre->viewmat, mat);
448 copy_m4_m4(envre->viewinv, tmat);
450 /* we have to correct for the already rotated vertexcoords */
451 mult_m4_m4m4(tmat, envre->viewmat, oldviewinv);
452 invert_m4_m4(env->imat, tmat);
454 env_rotate_scene(envre, tmat, 1);
455 init_render_world(envre);
456 project_renderdata(envre, projectverto, 0, 0, 1);
457 env_layerflags(envre, env->notlay);
458 env_hideobject(envre, env->object);
459 env_set_imats(envre);
461 if (re->test_break(re->tbh)==0) {
462 RE_TileProcessor(envre);
466 env_showobjects(envre);
467 env_rotate_scene(envre, tmat, 0);
469 if (re->test_break(re->tbh)==0) {
470 RenderLayer *rl= envre->result->layers.first;
474 ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect|IB_rectfloat);
475 memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
477 if (re->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
478 ibuf->profile = IB_PROFILE_LINEAR_RGB;
480 /* envmap renders without alpha */
481 alpha= ((float *)ibuf->rect_float)+3;
482 for (y= ibuf->x*ibuf->y - 1; y>=0; y--, alpha+=4)
485 env->cube[part]= ibuf;
488 if (re->test_break(re->tbh)) break;
492 if (re->test_break(re->tbh)) BKE_free_envmapdata(env);
494 if (envre->r.mode & R_OSA) env->ok= ENV_OSA;
495 else env->ok= ENV_NORMAL;
496 env->lastframe= re->scene->r.cfra;
500 envmap_free_render_copy(envre);
505 /* ------------------------------------------------------------------------- */
507 void make_envmaps(Render *re)
510 int do_init= 0, depth= 0, trace;
512 if (!(re->r.mode & R_ENVMAP)) return;
514 /* we don't raytrace, disabling the flag will cause ray_transp render solid */
515 trace= (re->r.mode & R_RAYTRACE);
516 re->r.mode &= ~R_RAYTRACE;
518 re->i.infostr= "Creating Environment maps";
519 re->stats_draw(re->sdh, &re->i);
521 /* 5 = hardcoded max recursion level */
523 tex= re->main->tex.first;
525 if (tex->id.us && tex->type==TEX_ENVMAP) {
526 if (tex->env && tex->env->object) {
527 EnvMap *env= tex->env;
529 if (env->object->lay & re->lay) {
530 if (env->stype==ENV_LOAD) {
531 float orthmat[4][4], mat[4][4], tmat[4][4];
533 /* precalc orthmat for object */
534 copy_m4_m4(orthmat, env->object->obmat);
535 normalize_m4(orthmat);
537 /* need imat later for texture imat */
538 mult_m4_m4m4(mat, re->viewmat, orthmat);
539 invert_m4_m4(tmat, mat);
540 copy_m3_m4(env->obimat, tmat);
544 /* decide if to render an envmap (again) */
545 if (env->depth >= depth) {
547 /* set 'recalc' to make sure it does an entire loop of recalcs */
550 /* free when OSA, and old one isn't OSA */
551 if ((re->r.mode & R_OSA) && env->ok==ENV_NORMAL)
552 BKE_free_envmapdata(env);
553 /* free when size larger */
554 else if (env->lastsize < re->r.size)
555 BKE_free_envmapdata(env);
556 /* free when env is in recalcmode */
557 else if (env->recalc)
558 BKE_free_envmapdata(env);
561 if (env->ok==0 && depth==0) env->recalc= 1;
565 render_envmap(re, env);
567 if (depth==env->depth) env->recalc= 0;
580 re->display_init(re->dih, re->result);
581 re->display_clear(re->dch, re->result);
582 // re->flag |= R_REDRAW_PRV;
589 /* ------------------------------------------------------------------------- */
591 static int envcube_isect(EnvMap *env, float *vec, float *answ)
596 if (env->type==ENV_PLANE) {
600 answ[0]= env->viewscale*labda*vec[0];
601 answ[1]= -env->viewscale*labda*vec[1];
605 if ( vec[2] <= -fabsf(vec[0]) && vec[2] <= -fabsf(vec[1]) ) {
608 answ[0]= labda*vec[0];
609 answ[1]= labda*vec[1];
611 else if (vec[2] >= fabsf(vec[0]) && vec[2] >= fabsf(vec[1])) {
614 answ[0]= labda*vec[0];
615 answ[1]= -labda*vec[1];
617 else if (vec[1] >= fabsf(vec[0])) {
620 answ[0]= labda*vec[0];
621 answ[1]= labda*vec[2];
623 else if (vec[0] <= -fabsf(vec[1])) {
626 answ[0]= labda*vec[1];
627 answ[1]= labda*vec[2];
629 else if (vec[1] <= -fabsf(vec[0])) {
632 answ[0]= -labda*vec[0];
633 answ[1]= labda*vec[2];
638 answ[0]= -labda*vec[1];
639 answ[1]= labda*vec[2];
643 answ[0]= 0.5f+0.5f*answ[0];
644 answ[1]= 0.5f+0.5f*answ[1];
648 /* ------------------------------------------------------------------------- */
650 static void set_dxtdyt(float *dxts, float *dyts, float *dxt, float *dyt, int face)
652 if (face==2 || face==4) {
658 else if (face==3 || face==5) {
672 /* ------------------------------------------------------------------------- */
674 int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
676 extern Render R; /* only in this call */
677 /* texvec should be the already reflected normal */
680 float fac, vec[3], sco[3], dxts[3], dyts[3];
684 if (env==NULL || (env->stype!=ENV_LOAD && env->object==NULL)) {
689 if (env->stype==ENV_LOAD) {
691 if (env->ima && env->ima->ok) {
692 if (env->cube[1]==NULL) {
693 ImBuf *ibuf_ima= BKE_image_get_ibuf(env->ima, NULL);
695 envmap_split_ima(env, ibuf_ima);
707 /* rotate to envmap space, if object is set */
708 copy_v3_v3(vec, texvec);
709 if (env->object) mul_m3_v3(env->obimat, vec);
710 else mul_mat3_m4_v3(R.viewinv, vec);
712 face= envcube_isect(env, vec, sco);
713 ibuf= env->cube[face];
717 mul_m3_v3(env->obimat, dxt);
718 mul_m3_v3(env->obimat, dyt);
721 mul_mat3_m4_v3(R.viewinv, dxt);
722 mul_mat3_m4_v3(R.viewinv, dyt);
724 set_dxtdyt(dxts, dyts, dxt, dyt, face);
725 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres);
729 if (texres->ta<1.0f) {
730 TexResult texr1, texr2;
732 texr1.nor= texr2.nor= NULL;
733 texr1.talpha= texr2.talpha= texres->talpha; /* boxclip expects this initialized */
736 face1= envcube_isect(env, vec, sco);
740 ibuf= env->cube[face1];
741 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
742 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1);
744 else texr1.tr= texr1.tg= texr1.tb= texr1.ta= 0.0;
746 /* here was the nasty bug! results were not zero-ed. FPE! */
749 face1= envcube_isect(env, vec, sco);
753 ibuf= env->cube[face1];
754 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
755 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2);
757 else texr2.tr= texr2.tg= texr2.tb= texr2.ta= 0.0;
759 fac= (texres->ta+texr1.ta+texr2.ta);
763 texres->tr= fac*(texres->ta*texres->tr + texr1.ta*texr1.tr + texr2.ta*texr2.tr );
764 texres->tg= fac*(texres->ta*texres->tg + texr1.ta*texr1.tg + texr2.ta*texr2.tg );
765 texres->tb= fac*(texres->ta*texres->tb + texr1.ta*texr1.tb + texr2.ta*texr2.tb );
771 imagewrap(tex, NULL, ibuf, sco, texres);
777 /* ------------------------------------------------------------------------- */