776 lines
19 KiB
C
776 lines
19 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* Contributors: 2004/2005/2006 Blender Foundation, full recode
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/render/intern/source/envmap.c
|
|
* \ingroup render
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
/* external modules: */
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_math.h"
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_threads.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BLF_translation.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h" /* for rectcpy */
|
|
|
|
#include "DNA_group_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "BKE_library.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_image.h" /* BKE_imbuf_write */
|
|
#include "BKE_texture.h"
|
|
|
|
|
|
|
|
|
|
/* this module */
|
|
#include "render_types.h"
|
|
#include "renderpipeline.h"
|
|
#include "envmap.h"
|
|
#include "rendercore.h"
|
|
#include "renderdatabase.h"
|
|
#include "texture.h"
|
|
#include "zbuf.h"
|
|
#include "initrender.h"
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
|
|
{
|
|
int dx, part;
|
|
|
|
/* after lock we test cube[1], if set the other thread has done it fine */
|
|
BLI_lock_thread(LOCK_IMAGE);
|
|
if (env->cube[1] == NULL) {
|
|
|
|
BKE_free_envmapdata(env);
|
|
|
|
dx = ibuf->y;
|
|
dx /= 2;
|
|
if (3 * dx == ibuf->x) {
|
|
env->type = ENV_CUBE;
|
|
env->ok = ENV_OSA;
|
|
}
|
|
else if (ibuf->x == ibuf->y) {
|
|
env->type = ENV_PLANE;
|
|
env->ok = ENV_OSA;
|
|
}
|
|
else {
|
|
printf("Incorrect envmap size\n");
|
|
env->ok = 0;
|
|
env->ima->ok = 0;
|
|
}
|
|
|
|
if (env->ok) {
|
|
if (env->type == ENV_CUBE) {
|
|
for (part = 0; part < 6; part++) {
|
|
env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect | IB_rectfloat);
|
|
}
|
|
IMB_float_from_rect(ibuf);
|
|
|
|
IMB_rectcpy(env->cube[0], ibuf,
|
|
0, 0, 0, 0, dx, dx);
|
|
IMB_rectcpy(env->cube[1], ibuf,
|
|
0, 0, dx, 0, dx, dx);
|
|
IMB_rectcpy(env->cube[2], ibuf,
|
|
0, 0, 2 * dx, 0, dx, dx);
|
|
IMB_rectcpy(env->cube[3], ibuf,
|
|
0, 0, 0, dx, dx, dx);
|
|
IMB_rectcpy(env->cube[4], ibuf,
|
|
0, 0, dx, dx, dx, dx);
|
|
IMB_rectcpy(env->cube[5], ibuf,
|
|
0, 0, 2 * dx, dx, dx, dx);
|
|
|
|
}
|
|
else { /* ENV_PLANE */
|
|
env->cube[1] = IMB_dupImBuf(ibuf);
|
|
IMB_float_from_rect(env->cube[1]);
|
|
}
|
|
}
|
|
}
|
|
BLI_unlock_thread(LOCK_IMAGE);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* ****************** RENDER ********************** */
|
|
|
|
/* copy current render */
|
|
static Render *envmap_render_copy(Render *re, EnvMap *env)
|
|
{
|
|
Render *envre;
|
|
float viewscale;
|
|
int cuberes;
|
|
|
|
envre = RE_NewRender("Envmap");
|
|
|
|
env->lastsize = re->r.size;
|
|
cuberes = (env->cuberes * re->r.size) / 100;
|
|
cuberes &= 0xFFFC;
|
|
|
|
/* this flag has R_ZTRA in it for example */
|
|
envre->flag = re->flag;
|
|
|
|
/* set up renderdata */
|
|
envre->r = re->r;
|
|
envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
|
|
envre->r.layers.first = envre->r.layers.last = NULL;
|
|
envre->r.filtertype = 0;
|
|
envre->r.tilex = envre->r.xsch / 2;
|
|
envre->r.tiley = envre->r.ysch / 2;
|
|
envre->r.size = 100;
|
|
envre->r.yasp = envre->r.xasp = 1;
|
|
|
|
RE_InitState(envre, NULL, &envre->r, NULL, cuberes, cuberes, NULL);
|
|
envre->scene = re->scene; /* unsure about this... */
|
|
envre->scene_color_manage = re->scene_color_manage;
|
|
envre->lay = re->lay;
|
|
|
|
/* view stuff in env render */
|
|
viewscale = (env->type == ENV_PLANE) ? env->viewscale : 1.0f;
|
|
RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend);
|
|
|
|
/* callbacks */
|
|
envre->display_draw = re->display_draw;
|
|
envre->ddh = re->ddh;
|
|
envre->test_break = re->test_break;
|
|
envre->tbh = re->tbh;
|
|
|
|
/* and for the evil stuff; copy the database... */
|
|
envre->totvlak = re->totvlak;
|
|
envre->totvert = re->totvert;
|
|
envre->tothalo = re->tothalo;
|
|
envre->totstrand = re->totstrand;
|
|
envre->totlamp = re->totlamp;
|
|
envre->sortedhalos = re->sortedhalos;
|
|
envre->lights = re->lights;
|
|
envre->objecttable = re->objecttable;
|
|
envre->customdata_names = re->customdata_names;
|
|
envre->raytree = re->raytree;
|
|
envre->totinstance = re->totinstance;
|
|
envre->instancetable = re->instancetable;
|
|
envre->objectinstance = re->objectinstance;
|
|
envre->qmcsamplers = re->qmcsamplers;
|
|
|
|
return envre;
|
|
}
|
|
|
|
static void envmap_free_render_copy(Render *envre)
|
|
{
|
|
|
|
envre->totvlak = 0;
|
|
envre->totvert = 0;
|
|
envre->tothalo = 0;
|
|
envre->totstrand = 0;
|
|
envre->totlamp = 0;
|
|
envre->totinstance = 0;
|
|
envre->sortedhalos = NULL;
|
|
envre->lights.first = envre->lights.last = NULL;
|
|
envre->objecttable.first = envre->objecttable.last = NULL;
|
|
envre->customdata_names.first = envre->customdata_names.last = NULL;
|
|
envre->raytree = NULL;
|
|
envre->instancetable.first = envre->instancetable.last = NULL;
|
|
envre->objectinstance = NULL;
|
|
envre->qmcsamplers = NULL;
|
|
|
|
RE_FreeRender(envre);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void envmap_transmatrix(float mat[4][4], int part)
|
|
{
|
|
float tmat[4][4], eul[3], rotmat[4][4];
|
|
|
|
eul[0] = eul[1] = eul[2] = 0.0;
|
|
|
|
if (part == 0) { /* neg z */
|
|
/* pass */
|
|
}
|
|
else if (part == 1) { /* pos z */
|
|
eul[0] = M_PI;
|
|
}
|
|
else if (part == 2) { /* pos y */
|
|
eul[0] = M_PI / 2.0;
|
|
}
|
|
else if (part == 3) { /* neg x */
|
|
eul[0] = M_PI / 2.0;
|
|
eul[2] = M_PI / 2.0;
|
|
}
|
|
else if (part == 4) { /* neg y */
|
|
eul[0] = M_PI / 2.0;
|
|
eul[2] = M_PI;
|
|
}
|
|
else { /* pos x */
|
|
eul[0] = M_PI / 2.0;
|
|
eul[2] = -M_PI / 2.0;
|
|
}
|
|
|
|
copy_m4_m4(tmat, mat);
|
|
eul_to_mat4(rotmat, eul);
|
|
mul_serie_m4(mat, tmat, rotmat,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL, NULL);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void env_rotate_scene(Render *re, float mat[4][4], int mode)
|
|
{
|
|
GroupObject *go;
|
|
ObjectRen *obr;
|
|
ObjectInstanceRen *obi;
|
|
LampRen *lar = NULL;
|
|
HaloRen *har = NULL;
|
|
float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
|
|
int a;
|
|
|
|
if (mode == 0) {
|
|
invert_m4_m4(tmat, mat);
|
|
copy_m3_m4(imat, tmat);
|
|
}
|
|
else {
|
|
copy_m4_m4(tmat, mat);
|
|
copy_m3_m4(imat, mat);
|
|
}
|
|
|
|
for (obi = re->instancetable.first; obi; obi = obi->next) {
|
|
/* append or set matrix depending on dupli */
|
|
if (obi->flag & R_DUPLI_TRANSFORMED) {
|
|
copy_m4_m4(tmpmat, obi->mat);
|
|
mult_m4_m4m4(obi->mat, tmat, tmpmat);
|
|
}
|
|
else if (mode == 1)
|
|
copy_m4_m4(obi->mat, tmat);
|
|
else
|
|
unit_m4(obi->mat);
|
|
|
|
copy_m3_m4(cmat, obi->mat);
|
|
invert_m3_m3(obi->nmat, cmat);
|
|
transpose_m3(obi->nmat);
|
|
|
|
/* indicate the renderer has to use transform matrices */
|
|
if (mode == 0)
|
|
obi->flag &= ~R_ENV_TRANSFORMED;
|
|
else
|
|
obi->flag |= R_ENV_TRANSFORMED;
|
|
}
|
|
|
|
|
|
for (obr = re->objecttable.first; obr; obr = obr->next) {
|
|
for (a = 0; a < obr->tothalo; a++) {
|
|
if ((a & 255) == 0) har = obr->bloha[a >> 8];
|
|
else har++;
|
|
|
|
mul_m4_v3(tmat, har->co);
|
|
}
|
|
}
|
|
|
|
for (go = re->lights.first; go; go = go->next) {
|
|
lar = go->lampren;
|
|
|
|
/* removed here some horrible code of someone in NaN who tried to fix
|
|
* prototypes... just solved by introducing a correct cmat[3][3] instead
|
|
* of using smat. this works, check square spots in reflections (ton) */
|
|
copy_m3_m3(cmat, lar->imat);
|
|
mul_m3_m3m3(lar->imat, cmat, imat);
|
|
|
|
mul_m3_v3(imat, lar->vec);
|
|
mul_m4_v3(tmat, lar->co);
|
|
|
|
lar->sh_invcampos[0] = -lar->co[0];
|
|
lar->sh_invcampos[1] = -lar->co[1];
|
|
lar->sh_invcampos[2] = -lar->co[2];
|
|
mul_m3_v3(lar->imat, lar->sh_invcampos);
|
|
lar->sh_invcampos[2] *= lar->sh_zfac;
|
|
|
|
if (lar->shb) {
|
|
if (mode == 1) {
|
|
invert_m4_m4(pmat, mat);
|
|
mult_m4_m4m4(smat, lar->shb->viewmat, pmat);
|
|
mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat);
|
|
}
|
|
else mult_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void env_layerflags(Render *re, unsigned int notlay)
|
|
{
|
|
ObjectRen *obr;
|
|
VlakRen *vlr = NULL;
|
|
int a;
|
|
|
|
/* invert notlay, so if face is in multiple layers it will still be visible,
|
|
* unless all 'notlay' bits match the face bits.
|
|
* face: 0110
|
|
* not: 0100
|
|
* ~not: 1011
|
|
* now (face & ~not) is true
|
|
*/
|
|
|
|
notlay = ~notlay;
|
|
|
|
for (obr = re->objecttable.first; obr; obr = obr->next) {
|
|
if ((obr->lay & notlay) == 0) {
|
|
for (a = 0; a < obr->totvlak; a++) {
|
|
if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
|
|
else vlr++;
|
|
|
|
vlr->flag |= R_HIDDEN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void env_hideobject(Render *re, Object *ob)
|
|
{
|
|
ObjectRen *obr;
|
|
VlakRen *vlr = NULL;
|
|
int a;
|
|
|
|
for (obr = re->objecttable.first; obr; obr = obr->next) {
|
|
for (a = 0; a < obr->totvlak; a++) {
|
|
if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
|
|
else vlr++;
|
|
|
|
if (obr->ob == ob)
|
|
vlr->flag |= R_HIDDEN;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void env_showobjects(Render *re)
|
|
{
|
|
ObjectRen *obr;
|
|
VlakRen *vlr = NULL;
|
|
int a;
|
|
|
|
for (obr = re->objecttable.first; obr; obr = obr->next) {
|
|
for (a = 0; a < obr->totvlak; a++) {
|
|
if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
|
|
else vlr++;
|
|
|
|
vlr->flag &= ~R_HIDDEN;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void env_set_imats(Render *re)
|
|
{
|
|
Base *base;
|
|
float mat[4][4];
|
|
|
|
base = re->scene->base.first;
|
|
while (base) {
|
|
mult_m4_m4m4(mat, re->viewmat, base->object->obmat);
|
|
invert_m4_m4(base->object->imat, mat);
|
|
|
|
base = base->next;
|
|
}
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void render_envmap(Render *re, EnvMap *env)
|
|
{
|
|
/* only the cubemap and planar map is implemented */
|
|
Render *envre;
|
|
ImBuf *ibuf;
|
|
float orthmat[4][4];
|
|
float oldviewinv[4][4], mat[4][4], tmat[4][4];
|
|
short part;
|
|
|
|
/* need a recalc: ortho-render has no correct viewinv */
|
|
invert_m4_m4(oldviewinv, re->viewmat);
|
|
|
|
envre = envmap_render_copy(re, env);
|
|
|
|
/* precalc orthmat for object */
|
|
copy_m4_m4(orthmat, env->object->obmat);
|
|
normalize_m4(orthmat);
|
|
|
|
/* need imat later for texture imat */
|
|
mult_m4_m4m4(mat, re->viewmat, orthmat);
|
|
invert_m4_m4(tmat, mat);
|
|
copy_m3_m4(env->obimat, tmat);
|
|
|
|
for (part = 0; part < 6; part++) {
|
|
if (env->type == ENV_PLANE && part != 1)
|
|
continue;
|
|
|
|
re->display_clear(re->dch, envre->result);
|
|
|
|
copy_m4_m4(tmat, orthmat);
|
|
envmap_transmatrix(tmat, part);
|
|
invert_m4_m4(mat, tmat);
|
|
/* mat now is the camera 'viewmat' */
|
|
|
|
copy_m4_m4(envre->viewmat, mat);
|
|
copy_m4_m4(envre->viewinv, tmat);
|
|
|
|
/* we have to correct for the already rotated vertexcoords */
|
|
mult_m4_m4m4(tmat, envre->viewmat, oldviewinv);
|
|
invert_m4_m4(env->imat, tmat);
|
|
|
|
env_rotate_scene(envre, tmat, 1);
|
|
init_render_world(envre);
|
|
project_renderdata(envre, projectverto, 0, 0, 1);
|
|
env_layerflags(envre, env->notlay);
|
|
env_hideobject(envre, env->object);
|
|
env_set_imats(envre);
|
|
|
|
if (re->test_break(re->tbh) == 0) {
|
|
RE_TileProcessor(envre);
|
|
}
|
|
|
|
/* rotate back */
|
|
env_showobjects(envre);
|
|
env_rotate_scene(envre, tmat, 0);
|
|
|
|
if (re->test_break(re->tbh) == 0) {
|
|
RenderLayer *rl = envre->result->layers.first;
|
|
int y;
|
|
float *alpha;
|
|
|
|
ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
|
|
memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
|
|
|
|
/* envmap renders without alpha */
|
|
alpha = ibuf->rect_float + 3;
|
|
for (y = ibuf->x * ibuf->y - 1; y >= 0; y--, alpha += 4)
|
|
*alpha = 1.0;
|
|
|
|
env->cube[part] = ibuf;
|
|
}
|
|
|
|
if (re->test_break(re->tbh)) break;
|
|
|
|
}
|
|
|
|
if (re->test_break(re->tbh)) BKE_free_envmapdata(env);
|
|
else {
|
|
if (envre->r.mode & R_OSA) env->ok = ENV_OSA;
|
|
else env->ok = ENV_NORMAL;
|
|
env->lastframe = re->scene->r.cfra;
|
|
}
|
|
|
|
/* restore */
|
|
envmap_free_render_copy(envre);
|
|
env_set_imats(re);
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
void make_envmaps(Render *re)
|
|
{
|
|
Tex *tex;
|
|
int do_init = FALSE, depth = 0, trace;
|
|
|
|
if (!(re->r.mode & R_ENVMAP)) return;
|
|
|
|
/* we don't raytrace, disabling the flag will cause ray_transp render solid */
|
|
trace = (re->r.mode & R_RAYTRACE);
|
|
re->r.mode &= ~R_RAYTRACE;
|
|
|
|
re->i.infostr = IFACE_("Creating Environment maps");
|
|
re->stats_draw(re->sdh, &re->i);
|
|
|
|
/* 5 = hardcoded max recursion level */
|
|
while (depth < 5) {
|
|
tex = re->main->tex.first;
|
|
while (tex) {
|
|
if (tex->id.us && tex->type == TEX_ENVMAP) {
|
|
if (tex->env && tex->env->object) {
|
|
EnvMap *env = tex->env;
|
|
|
|
if (env->object->lay & re->lay) {
|
|
if (env->stype == ENV_LOAD) {
|
|
float orthmat[4][4], mat[4][4], tmat[4][4];
|
|
|
|
/* precalc orthmat for object */
|
|
copy_m4_m4(orthmat, env->object->obmat);
|
|
normalize_m4(orthmat);
|
|
|
|
/* need imat later for texture imat */
|
|
mult_m4_m4m4(mat, re->viewmat, orthmat);
|
|
invert_m4_m4(tmat, mat);
|
|
copy_m3_m4(env->obimat, tmat);
|
|
}
|
|
else {
|
|
|
|
/* decide if to render an envmap (again) */
|
|
if (env->depth >= depth) {
|
|
|
|
/* set 'recalc' to make sure it does an entire loop of recalcs */
|
|
|
|
if (env->ok) {
|
|
/* free when OSA, and old one isn't OSA */
|
|
if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL)
|
|
BKE_free_envmapdata(env);
|
|
/* free when size larger */
|
|
else if (env->lastsize < re->r.size)
|
|
BKE_free_envmapdata(env);
|
|
/* free when env is in recalcmode */
|
|
else if (env->recalc)
|
|
BKE_free_envmapdata(env);
|
|
}
|
|
|
|
if (env->ok == 0 && depth == 0) env->recalc = 1;
|
|
|
|
if (env->ok == 0) {
|
|
do_init = TRUE;
|
|
render_envmap(re, env);
|
|
|
|
if (depth == env->depth) env->recalc = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tex = tex->id.next;
|
|
}
|
|
depth++;
|
|
}
|
|
|
|
if (do_init) {
|
|
re->display_init(re->dih, re->result);
|
|
re->display_clear(re->dch, re->result);
|
|
// re->flag |= R_REDRAW_PRV;
|
|
}
|
|
/* restore */
|
|
re->r.mode |= trace;
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int envcube_isect(EnvMap *env, const float vec[3], float answ[2])
|
|
{
|
|
float lambda;
|
|
int face;
|
|
|
|
if (env->type == ENV_PLANE) {
|
|
face = 1;
|
|
|
|
lambda = 1.0f / vec[2];
|
|
answ[0] = env->viewscale * lambda * vec[0];
|
|
answ[1] = -env->viewscale * lambda * vec[1];
|
|
}
|
|
else {
|
|
/* which face */
|
|
if (vec[2] <= -fabsf(vec[0]) && vec[2] <= -fabsf(vec[1]) ) {
|
|
face = 0;
|
|
lambda = -1.0f / vec[2];
|
|
answ[0] = lambda * vec[0];
|
|
answ[1] = lambda * vec[1];
|
|
}
|
|
else if (vec[2] >= fabsf(vec[0]) && vec[2] >= fabsf(vec[1])) {
|
|
face = 1;
|
|
lambda = 1.0f / vec[2];
|
|
answ[0] = lambda * vec[0];
|
|
answ[1] = -lambda * vec[1];
|
|
}
|
|
else if (vec[1] >= fabsf(vec[0])) {
|
|
face = 2;
|
|
lambda = 1.0f / vec[1];
|
|
answ[0] = lambda * vec[0];
|
|
answ[1] = lambda * vec[2];
|
|
}
|
|
else if (vec[0] <= -fabsf(vec[1])) {
|
|
face = 3;
|
|
lambda = -1.0f / vec[0];
|
|
answ[0] = lambda * vec[1];
|
|
answ[1] = lambda * vec[2];
|
|
}
|
|
else if (vec[1] <= -fabsf(vec[0])) {
|
|
face = 4;
|
|
lambda = -1.0f / vec[1];
|
|
answ[0] = -lambda * vec[0];
|
|
answ[1] = lambda * vec[2];
|
|
}
|
|
else {
|
|
face = 5;
|
|
lambda = 1.0f / vec[0];
|
|
answ[0] = -lambda * vec[1];
|
|
answ[1] = lambda * vec[2];
|
|
}
|
|
}
|
|
|
|
answ[0] = 0.5f + 0.5f * answ[0];
|
|
answ[1] = 0.5f + 0.5f * answ[1];
|
|
return face;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const float dyt[3], int face)
|
|
{
|
|
if (face == 2 || face == 4) {
|
|
r_dxt[0] = dxt[0];
|
|
r_dyt[0] = dyt[0];
|
|
r_dxt[1] = dxt[2];
|
|
r_dyt[1] = dyt[2];
|
|
}
|
|
else if (face == 3 || face == 5) {
|
|
r_dxt[0] = dxt[1];
|
|
r_dxt[1] = dxt[2];
|
|
r_dyt[0] = dyt[1];
|
|
r_dyt[1] = dyt[2];
|
|
}
|
|
else {
|
|
r_dxt[0] = dxt[0];
|
|
r_dyt[0] = dyt[0];
|
|
r_dxt[1] = dxt[1];
|
|
r_dyt[1] = dyt[1];
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool)
|
|
{
|
|
extern Render R; /* only in this call */
|
|
/* texvec should be the already reflected normal */
|
|
EnvMap *env;
|
|
ImBuf *ibuf;
|
|
float fac, vec[3], sco[3], dxts[3], dyts[3];
|
|
int face, face1;
|
|
|
|
env = tex->env;
|
|
if (env == NULL || (env->stype != ENV_LOAD && env->object == NULL)) {
|
|
texres->tin = 0.0;
|
|
return 0;
|
|
}
|
|
|
|
if (env->stype == ENV_LOAD) {
|
|
env->ima = tex->ima;
|
|
if (env->ima && env->ima->ok) {
|
|
if (env->cube[1] == NULL) {
|
|
ImBuf *ibuf_ima = BKE_image_pool_acquire_ibuf(env->ima, NULL, pool);
|
|
if (ibuf_ima)
|
|
envmap_split_ima(env, ibuf_ima);
|
|
else
|
|
env->ok = 0;
|
|
BKE_image_pool_release_ibuf(env->ima, ibuf_ima, pool);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (env->ok == 0) {
|
|
texres->tin = 0.0;
|
|
return 0;
|
|
}
|
|
|
|
/* rotate to envmap space, if object is set */
|
|
copy_v3_v3(vec, texvec);
|
|
if (env->object) mul_m3_v3(env->obimat, vec);
|
|
else mul_mat3_m4_v3(R.viewinv, vec);
|
|
|
|
face = envcube_isect(env, vec, sco);
|
|
ibuf = env->cube[face];
|
|
|
|
if (osatex) {
|
|
if (env->object) {
|
|
mul_m3_v3(env->obimat, dxt);
|
|
mul_m3_v3(env->obimat, dyt);
|
|
}
|
|
else {
|
|
mul_mat3_m4_v3(R.viewinv, dxt);
|
|
mul_mat3_m4_v3(R.viewinv, dyt);
|
|
}
|
|
set_dxtdyt(dxts, dyts, dxt, dyt, face);
|
|
imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool);
|
|
|
|
/* edges? */
|
|
|
|
if (texres->ta < 1.0f) {
|
|
TexResult texr1, texr2;
|
|
|
|
texr1.nor = texr2.nor = NULL;
|
|
texr1.talpha = texr2.talpha = texres->talpha; /* boxclip expects this initialized */
|
|
|
|
add_v3_v3(vec, dxt);
|
|
face1 = envcube_isect(env, vec, sco);
|
|
sub_v3_v3(vec, dxt);
|
|
|
|
if (face != face1) {
|
|
ibuf = env->cube[face1];
|
|
set_dxtdyt(dxts, dyts, dxt, dyt, face1);
|
|
imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool);
|
|
}
|
|
else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0;
|
|
|
|
/* here was the nasty bug! results were not zero-ed. FPE! */
|
|
|
|
add_v3_v3(vec, dyt);
|
|
face1 = envcube_isect(env, vec, sco);
|
|
sub_v3_v3(vec, dyt);
|
|
|
|
if (face != face1) {
|
|
ibuf = env->cube[face1];
|
|
set_dxtdyt(dxts, dyts, dxt, dyt, face1);
|
|
imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool);
|
|
}
|
|
else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0;
|
|
|
|
fac = (texres->ta + texr1.ta + texr2.ta);
|
|
if (fac != 0.0f) {
|
|
fac = 1.0f / fac;
|
|
|
|
texres->tr = fac * (texres->ta * texres->tr + texr1.ta * texr1.tr + texr2.ta * texr2.tr);
|
|
texres->tg = fac * (texres->ta * texres->tg + texr1.ta * texr1.tg + texr2.ta * texr2.tg);
|
|
texres->tb = fac * (texres->ta * texres->tb + texr1.ta * texr1.tb + texr2.ta * texr2.tb);
|
|
}
|
|
texres->ta = 1.0;
|
|
}
|
|
}
|
|
else {
|
|
imagewrap(tex, NULL, ibuf, sco, texres, pool);
|
|
}
|
|
|
|
return 1;
|
|
}
|