Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2018-04-19 18:34:44 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-04-19 18:35:25 +0300
commit51b796ff1528c52cc8b4079fab1003671652a4d9 (patch)
tree0dfc2d2dabe5e77959264f5b6667897569290a41 /source/blender/render/intern
parent785e8a636a293941a4295e669cb5aeecfafae039 (diff)
Remove Blender Internal and legacy viewport from Blender 2.8.
Brecht authored this commit, but he gave me the honours to actually do it. Here it goes; Blender Internal. Bye bye, you did great! * Point density, voxel data, ocean, environment map textures were removed, as these only worked within BI rendering. Note that the ocean modifier and the Cycles point density shader node continue to work. * Dynamic paint using material shading was removed, as this only worked with BI. If we ever wanted to support this again probably it should go through the baking API. * GPU shader export through the Python API was removed. This only worked for the old BI GLSL shaders, which no longer exists. Doing something similar for Eevee would be significantly more complicated because it uses a lot of multiplass rendering and logic outside the shader, it's probably impractical. * Collada material import / export code is mostly gone, as it only worked for BI materials. We need to add Cycles / Eevee material support at some point. * The mesh noise operator was removed since it only worked with BI material texture slots. A displacement modifier can be used instead. * The delete texture paint slot operator was removed since it only worked for BI material texture slots. Could be added back with node support. * Not all legacy viewport features are supported in the new viewport, but their code was removed. If we need to bring anything back we can look at older git revisions. * There is some legacy viewport code that I could not remove yet, and some that I probably missed. * Shader node execution code was left mostly intact, even though it is not used anywhere now. We may eventually use this to replace the texture nodes with Cycles / Eevee shader nodes. * The Cycles Bake panel now includes settings for baking multires normal and displacement maps. The underlying code needs to be merged properly, and we plan to add back support for multires AO baking and add support to Cycles baking for features like vertex color, displacement, and other missing baking features. * This commit removes DNA and the Python API for BI material, lamp, world and scene settings. This breaks a lot of addons. * There is more DNA that can be removed or renamed, where Cycles or Eevee are reusing some old BI properties but the names are not really correct anymore. * Texture slots for materials, lamps and world were removed. They remain for brushes, particles and freestyle linestyles. * 'BLENDER_RENDER' remains in the COMPAT_ENGINES of UI panels. Cycles and other renderers use this to find all panels to show, minus a few panels that they have their own replacement for.
Diffstat (limited to 'source/blender/render/intern')
-rw-r--r--source/blender/render/intern/include/envmap.h54
-rw-r--r--source/blender/render/intern/include/initrender.h7
-rw-r--r--source/blender/render/intern/include/occlusion.h49
-rw-r--r--source/blender/render/intern/include/pixelblending.h65
-rw-r--r--source/blender/render/intern/include/pixelshading.h62
-rw-r--r--source/blender/render/intern/include/pointdensity.h52
-rw-r--r--source/blender/render/intern/include/raycounter.h74
-rw-r--r--source/blender/render/intern/include/rayintersection.h136
-rw-r--r--source/blender/render/intern/include/rayobject.h121
-rw-r--r--source/blender/render/intern/include/render_result.h2
-rw-r--r--source/blender/render/intern/include/render_types.h529
-rw-r--r--source/blender/render/intern/include/rendercore.h105
-rw-r--r--source/blender/render/intern/include/renderdatabase.h175
-rw-r--r--source/blender/render/intern/include/renderpipeline.h3
-rw-r--r--source/blender/render/intern/include/shadbuf.h112
-rw-r--r--source/blender/render/intern/include/shading.h105
-rw-r--r--source/blender/render/intern/include/sss.h67
-rw-r--r--source/blender/render/intern/include/strand.h99
-rw-r--r--source/blender/render/intern/include/sunsky.h81
-rw-r--r--source/blender/render/intern/include/texture.h17
-rw-r--r--source/blender/render/intern/include/texture_ocean.h35
-rw-r--r--source/blender/render/intern/include/volume_precache.h39
-rw-r--r--source/blender/render/intern/include/volumetric.h51
-rw-r--r--source/blender/render/intern/include/voxeldata.h47
-rw-r--r--source/blender/render/intern/include/zbuf.h101
-rw-r--r--source/blender/render/intern/raytrace/bvh.h407
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp534
-rw-r--r--source/blender/render/intern/raytrace/rayobject_empty.cpp81
-rw-r--r--source/blender/render/intern/raytrace/rayobject_hint.h72
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp211
-rw-r--r--source/blender/render/intern/raytrace/rayobject_internal.h157
-rw-r--r--source/blender/render/intern/raytrace/rayobject_octree.cpp1101
-rw-r--r--source/blender/render/intern/raytrace/rayobject_qbvh.cpp160
-rw-r--r--source/blender/render/intern/raytrace/rayobject_raycounter.cpp91
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp531
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.h125
-rw-r--r--source/blender/render/intern/raytrace/rayobject_svbvh.cpp192
-rw-r--r--source/blender/render/intern/raytrace/rayobject_vbvh.cpp206
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h513
-rw-r--r--source/blender/render/intern/raytrace/svbvh.h317
-rw-r--r--source/blender/render/intern/raytrace/vbvh.h238
-rw-r--r--source/blender/render/intern/source/bake.c1343
-rw-r--r--source/blender/render/intern/source/bake_api.c70
-rw-r--r--source/blender/render/intern/source/convertblender.c5974
-rw-r--r--source/blender/render/intern/source/envmap.c819
-rw-r--r--source/blender/render/intern/source/external_engine.c23
-rw-r--r--source/blender/render/intern/source/imagetexture.c61
-rw-r--r--source/blender/render/intern/source/initrender.c340
-rw-r--r--source/blender/render/intern/source/multires_bake.c100
-rw-r--r--source/blender/render/intern/source/occlusion.c1533
-rw-r--r--source/blender/render/intern/source/pipeline.c1210
-rw-r--r--source/blender/render/intern/source/pixelblending.c400
-rw-r--r--source/blender/render/intern/source/pixelshading.c650
-rw-r--r--source/blender/render/intern/source/pointdensity.c125
-rw-r--r--source/blender/render/intern/source/rayshade.c2474
-rw-r--r--source/blender/render/intern/source/render_result.c23
-rw-r--r--source/blender/render/intern/source/render_texture.c2510
-rw-r--r--source/blender/render/intern/source/rendercore.c2028
-rw-r--r--source/blender/render/intern/source/renderdatabase.c1603
-rw-r--r--source/blender/render/intern/source/shadbuf.c2647
-rw-r--r--source/blender/render/intern/source/shadeinput.c1451
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2162
-rw-r--r--source/blender/render/intern/source/sss.c1074
-rw-r--r--source/blender/render/intern/source/strand.c1069
-rw-r--r--source/blender/render/intern/source/sunsky.c506
-rw-r--r--source/blender/render/intern/source/texture_ocean.c160
-rw-r--r--source/blender/render/intern/source/volume_precache.c855
-rw-r--r--source/blender/render/intern/source/volumetric.c834
-rw-r--r--source/blender/render/intern/source/voxeldata.c571
-rw-r--r--source/blender/render/intern/source/zbuf.c3498
70 files changed, 214 insertions, 43023 deletions
diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h
deleted file mode 100644
index 627e6c0e1e6..00000000000
--- a/source/blender/render/intern/include/envmap.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * envmap_ext.h
- *
- *
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/envmap.h
- * \ingroup render
- */
-
-
-#ifndef __ENVMAP_H__
-#define __ENVMAP_H__
-
-/**
- * Make environment maps for all objects in the scene that have an
- * environment map as texture.
- * (initrender.c)
- */
-
-struct Render;
-struct TexResult;
-struct ImagePool;
-
-void make_envmaps(struct Render *re);
-int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load);
-void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate);
-
-#endif /* __ENVMAP_H__ */
-
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
index 87e2d2519d5..e7ff3c7097c 100644
--- a/source/blender/render/intern/include/initrender.h
+++ b/source/blender/render/intern/include/initrender.h
@@ -33,16 +33,11 @@
#ifndef __INITRENDER_H__
#define __INITRENDER_H__
-
/* Functions */
-void free_sample_tables(Render *re);
-void make_sample_tables(Render *re);
-
-void RE_parts_init(Render *re, bool do_crop);
+void RE_parts_init(Render *re);
void RE_parts_free(Render *re);
void RE_parts_clamp(Render *re);
-
#endif /* __INITRENDER_H__ */
diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/render/intern/include/occlusion.h
deleted file mode 100644
index 4a70d691436..00000000000
--- a/source/blender/render/intern/include/occlusion.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * ***** 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) 2008 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/occlusion.h
- * \ingroup render
- */
-
-
-#ifndef __OCCLUSION_H__
-#define __OCCLUSION_H__
-
-struct Render;
-struct ShadeInput;
-struct RenderPart;
-struct ShadeSample;
-
-void make_occ_tree(struct Render *re);
-void free_occ(struct Render *re);
-void sample_occ(struct Render *re, struct ShadeInput *shi);
-
-void cache_occ_samples(struct Render *re, struct RenderPart *pa, struct ShadeSample *ssamp);
-void free_occ_samples(struct Render *re, struct RenderPart *pa);
-
-#endif
-
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
deleted file mode 100644
index 17a872a0676..00000000000
--- a/source/blender/render/intern/include/pixelblending.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): 2004-2006 Blender Foundation, full recode
- *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pixelblending.h
- * \ingroup render
- */
-
-
-#ifndef __PIXELBLENDING_H__
-#define __PIXELBLENDING_H__
-
-
-/**
- * add 1 pixel to into filtered three lines
- * (float vecs to float vec)
- */
-void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w);
-void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask);
-void mask_array(unsigned int mask, float filt[3][3]);
-
-/**
- * Alpha-over blending for floats.
- */
-void addAlphaOverFloat(float dest[4], const float source[4]);
-
-/**
- * Alpha-under blending for floats.
- */
-void addAlphaUnderFloat(float dest[4], const float source[4]);
-
-
-/**
- * Same for floats
- */
-void addalphaAddfacFloat(float dest[4], const float source[4], char addfac);
-
-/**
- * dest = dest + source
- */
-void addalphaAddFloat(float dest[4], const float source[4]);
-
-#endif /* __PIXELBLENDING_H__ */
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
deleted file mode 100644
index 8f23455564f..00000000000
--- a/source/blender/render/intern/include/pixelshading.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pixelshading.h
- * \ingroup render
- *
- * These functions determine what actual color a pixel will have.
- */
-
-#ifndef __PIXELSHADING_H__
-#define __PIXELSHADING_H__
-
-
-/**
- * Render the pixel at (x,y) for object ap. Apply the jitter mask.
- * Output is given in float collector[4]. The type vector:
- * t[0] - min. distance
- * t[1] - face/halo index
- * t[2] - jitter mask
- * t[3] - type ZB_POLY or ZB_HALO
- * t[4] - max. distance
- * mask is pixel coverage in bits
- * \return pointer to the object
- */
-int shadeHaloFloat(HaloRen *har,
- float *col, int zz,
- float dist, float xn,
- float yn, short flarec);
-
-/**
- * Render the sky at pixel (x, y).
- */
-void shadeSkyPixel(float collector[4], float fx, float fy, short thread);
-void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread);
-void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance);
-void shadeSunView(float col_r[3], const float view[3]);
-/* ------------------------------------------------------------------------- */
-
-#endif
-
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
deleted file mode 100644
index 263fa44f9c4..00000000000
--- a/source/blender/render/intern/include/pointdensity.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pointdensity.h
- * \ingroup render
- */
-
-
-#ifndef __POINTDENSITY_H__
-#define __POINTDENSITY_H__
-
-/**
- * Make point density kd-trees for all point density textures in the scene
- */
-
-struct Depsgraph;
-struct PointDensity;
-struct Render;
-struct TexResult;
-
-void free_pointdensity(struct PointDensity *pd);
-void cache_pointdensity(struct Depsgraph *depsgraph, struct Render *re, struct PointDensity *pd);
-void make_pointdensities(struct Depsgraph *depsgraph, struct Render *re);
-void free_pointdensities(struct Render *re);
-int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
-
-#endif /* __POINTDENSITY_H__ */
-
diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h
deleted file mode 100644
index 1694273df0e..00000000000
--- a/source/blender/render/intern/include/raycounter.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/raycounter.h
- * \ingroup render
- */
-
-
-#ifndef __RAYCOUNTER_H__
-#define __RAYCOUNTER_H__
-
-//#define RE_RAYCOUNTER /* enable counters per ray, useful for measuring raytrace structures performance */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef RE_RAYCOUNTER
-
-/* ray counter functions */
-
-typedef struct RayCounter {
- struct {
- unsigned long long test, hit;
- } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit;
-} RayCounter;
-
-#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter)
-void RE_RC_INFO(RayCounter *rc);
-void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp);
-#define RE_RC_COUNT(var) (var)++
-
-extern RayCounter re_rc_counter[];
-
-#else
-
-/* ray counter stubs */
-
-#define RE_RC_INIT(isec,shi)
-#define RE_RC_INFO(rc)
-#define RE_RC_MERGE(dest,src)
-#define RE_RC_COUNT(var)
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
deleted file mode 100644
index 1935e4ef59c..00000000000
--- a/source/blender/render/intern/include/rayintersection.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
- */
-
-/** \file blender/render/intern/include/rayintersection.h
- * \ingroup render
- */
-
-
-#ifndef __RAYINTERSECTION_H__
-#define __RAYINTERSECTION_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "BLI_math_geom.h"
-
-struct RayObject;
-
-/* Ray Hints */
-
-#define RE_RAY_LCTS_MAX_SIZE 256
-#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */
-//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */
-
-typedef struct LCTSHint {
- int size;
- struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
-} LCTSHint;
-
-typedef struct RayHint {
- union { LCTSHint lcts; } data;
-} RayHint;
-
-/* Ray Intersection */
-
-typedef struct Isect {
- /* ray start, direction (normalized vector), and max distance. on hit,
- * the distance is modified to be the distance to the hit point. */
- float start[3];
- float dir[3];
- float dist;
-
- /* for envmap and incremental view update renders */
- float origstart[3];
- float origdir[3];
-
- /* precomputed values to accelerate bounding box intersection */
- int bv_index[6];
- float idot_axis[3];
-
- /* intersection options */
- int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
- int lay; /* -1 default, set for layer lamps */
- int skip; /* skip flags */
- int check; /* check flags */
- void *userdata; /* used by bake check */
-
- /* hit information */
- float u, v;
- int isect; /* which half of quad */
-
- struct {
- void *ob;
- void *face;
- } hit, orig;
-
- /* last hit optimization */
- struct RayObject *last_hit;
-
- /* hints */
-#ifdef RT_USE_HINT
- RayTraceHint *hint, *hit_hint;
-#endif
- RayHint *hint;
-
- /* ray counter */
-#ifdef RE_RAYCOUNTER
- RayCounter *raycounter;
-#endif
-
- /* Precalculated coefficients for watertight intersection check. */
- struct IsectRayPrecalc isect_precalc;
-} Isect;
-
-/* ray types */
-#define RE_RAY_SHADOW 0
-#define RE_RAY_MIRROR 1
-#define RE_RAY_SHADOW_TRA 2
-
-/* skip options */
-#define RE_SKIP_CULLFACE (1 << 0)
-/* if using this flag then *face should be a pointer to a VlakRen */
-#define RE_SKIP_VLR_NEIGHBOUR (1 << 1)
-
-/* check options */
-#define RE_CHECK_VLR_NONE 0
-#define RE_CHECK_VLR_RENDER 1
-#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2
-#define RE_CHECK_VLR_BAKE 3
-
-/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */
-#define RE_RAYTRACE_MAXDIST 1e15f
-#define RE_RAYTRACE_EPSILON 0.0f
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYINTERSECTION_H__ */
-
diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h
deleted file mode 100644
index 63135d01c23..00000000000
--- a/source/blender/render/intern/include/rayobject.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/rayobject.h
- * \ingroup render
- */
-
-
-#ifndef __RAYOBJECT_H__
-#define __RAYOBJECT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct Isect;
-struct ObjectInstanceRen;
-struct RayHint;
-struct VlakRen;
-
-/* RayObject
- * Can be a face/triangle, bvh tree, object instance, etc. This is the
- * public API used by the renderer, see rayobject_internal.h for the
- * internal implementation details.
- * */
-typedef struct RayObject RayObject;
-
-/* Intersection, see rayintersection.h */
-
-int RE_rayobject_raycast(RayObject *r, struct Isect *i);
-
-/* Acceleration Structures */
-
-RayObject *RE_rayobject_octree_create(int ocres, int size);
-RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob);
-RayObject *RE_rayobject_empty_create(void);
-
-RayObject *RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */
-RayObject *RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */
-RayObject *RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */
-
-/* Building */
-
-void RE_rayobject_add(RayObject *r, RayObject *);
-void RE_rayobject_done(RayObject *r);
-void RE_rayobject_free(RayObject *r);
-
-void RE_rayobject_set_control(RayObject *r, void *data, int (*test_break)(void *data));
-
-/* RayObject representing faces, all data is locally available instead
- * of referring to some external data structure, for possibly faster
- * intersection tests. */
-
-typedef struct RayFace {
- float v1[4], v2[4], v3[4], v4[3];
- int quad;
- void *ob;
- void *face;
-} RayFace;
-
-#define RE_rayface_isQuad(a) ((a)->quad)
-
-RayObject *RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-
-RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4);
-
-/* RayObject representing faces directly from a given VlakRen structure. Thus
- * allowing to save memory, but making code triangle intersection dependent on
- * render structures. */
-
-typedef struct VlakPrimitive {
- struct ObjectInstanceRen *ob;
- struct VlakRen *face;
-} VlakPrimitive;
-
-RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-
-/* Bounding Box */
-
-/* extend min/max coords so that the rayobject is inside them */
-void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
-
-/* initializes an hint for optimizing raycast where it is know that a ray will pass by the given BB often the origin point */
-void RE_rayobject_hint_bb(RayObject *r, struct RayHint *hint, float min[3], float max[3]);
-
-/* initializes an hint for optimizing raycast where it is know that a ray will be contained inside the given cone*/
-/* void RE_rayobject_hint_cone(RayObject *r, struct RayHint *hint, float *); */
-
-/* Internals */
-
-#include "../raytrace/rayobject_internal.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 03292579d90..9a1b1b5abe8 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -55,8 +55,6 @@ struct ColorManagedViewSettings;
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname);
-struct RenderResult *render_result_new_full_sample(struct Render *re,
- struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname);
struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 97224d3aec0..8308b5e76e4 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -35,58 +35,19 @@
/* exposed internal in render module only! */
/* ------------------------------------------------------------------------- */
-#include "DNA_color_types.h"
-#include "DNA_customdata_types.h"
#include "DNA_scene_types.h"
-#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "DNA_vec_types.h"
#include "BLI_threads.h"
#include "BKE_main.h"
#include "RE_pipeline.h"
-#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */
-#include "sunsky.h"
-#include "BLI_sys_types.h" // for intptr_t support
-
-struct Depsgraph;
struct Object;
-struct MemArena;
-struct VertTableNode;
-struct VlakTableNode;
-struct GHash;
-struct ObjectInstanceRen;
-struct RayObject;
-struct RayFace;
struct RenderEngine;
struct ReportList;
struct Main;
-struct ImagePool;
-
-#define TABLEINITSIZE 1024
-
-typedef struct SampleTables {
- float centLut[16];
- float *fmask1[9], *fmask2[9];
- char cmask[256], *centmask;
-
-} SampleTables;
-
-typedef struct QMCSampler {
- struct QMCSampler *next, *prev;
- int type;
- int tot;
- int used;
- double *samp2d;
- double offs[BLENDER_MAX_THREADS][2];
-} QMCSampler;
-
-// #define SAMP_TYPE_JITTERED 0 // UNUSED
-#define SAMP_TYPE_HALTON 1
-#define SAMP_TYPE_HAMMERSLEY 2
/* this is handed over to threaded hiding/passes/shading engine */
typedef struct RenderPart {
@@ -95,24 +56,10 @@ typedef struct RenderPart {
RenderResult *result; /* result of part rendering */
ListBase fullresult; /* optional full sample buffers */
- int *recto; /* object table for objects */
- int *rectp; /* polygon index table */
- int *rectz; /* zbuffer */
- int *rectmask; /* negative zmask */
- intptr_t *rectdaps; /* delta acum buffer for pixel structs */
- int *rectbacko; /* object table for backside sss */
- int *rectbackp; /* polygon index table for backside sss */
- int *rectbackz; /* zbuffer for backside sss */
- intptr_t *rectall; /* buffer for all faces for sss */
-
rcti disprect; /* part coordinates within total picture */
int rectx, recty; /* the size */
int nr; /* nr is partnr */
- short crop, status; /* crop is amount of pixels we crop, for filter */
- short sample; /* sample can be used by zbuffers */
- short thread; /* thread id */
-
- char *clipflag; /* clipflags for part zbuffering */
+ short status;
} RenderPart;
enum {
@@ -129,10 +76,7 @@ struct Render {
int slot;
/* state settings */
- short flag, osa, ok, result_ok;
-
- /* due to performance issues, getting initialized from color management settings once on Render initialization */
- bool scene_color_manage;
+ short flag, ok, result_ok;
/* result of rendering */
RenderResult *result;
@@ -150,8 +94,6 @@ struct Render {
* without border & crop. convert to long before multiplying together to avoid overflow. */
rcti disprect; /* part within winx winy */
rctf viewplane; /* mapped on winx winy */
- float viewdx, viewdy; /* size of 1 pixel */
- float clipcrop; /* 2 pixel boundary to prevent clip when filter used */
/* final picture width and height (within disprect) */
int rectx, recty;
@@ -160,14 +102,7 @@ struct Render {
* partx*xparts can be larger than rectx, in that case last part is smaller */
int partx, party;
- /* values for viewing */
- float ycor; /* (scene->xasp / scene->yasp), multiplied with 'winy' */
-
- float panophi, panosi, panoco, panodxp, panodxv;
-
- /* Matrices */
- float grvec[3]; /* for world */
- float imat[3][3]; /* copy of viewinv */
+ /* Camera transform, only used by Freestyle. */
float viewmat[4][4], viewinv[4][4];
float viewmat_orig[4][4]; /* for incremental render */
float winmat[4][4];
@@ -176,23 +111,12 @@ struct Render {
float clipsta;
float clipend;
- /* samples */
- SampleTables *samples;
- float jit[32][2];
- float mblur_jit[32][2];
- ListBase *qmcsamplers;
- int num_qmc_samplers;
-
- /* shadow counter, detect shadow-reuse for shaders */
- int shadowsamplenr[BLENDER_MAX_THREADS];
-
/* main, scene, and its full copy of renderdata and world */
struct Main *main;
Scene *scene;
RenderData r;
ListBase view_layers;
int active_view_layer;
- World wrld;
struct Object *camera_override;
unsigned int lay, layer_override;
@@ -202,56 +126,11 @@ struct Render {
/* render engine */
struct RenderEngine *engine;
- /* octree tables and variables for raytrace */
- struct RayObject *raytree;
- struct RayFace *rayfaces;
- struct VlakPrimitive *rayprimitives;
- float maxdist; /* needed for keeping an incorrect behavior of SUN and HEMI lights (avoid breaking old scenes) */
-
- /* occlusion tree */
- void *occlusiontree;
- ListBase strandsurface;
-
- /* use this instead of R.r.cfra */
- float mblur_offs, field_offs;
-
- /* render database */
- int totvlak, totvert, tothalo, totstrand, totlamp;
- struct HaloRen **sortedhalos;
-
- ListBase lights; /* GroupObject pointers */
- ListBase lampren; /* storage, for free */
-
- ListBase objecttable;
-
- struct ObjectInstanceRen *objectinstance;
- ListBase instancetable;
- int totinstance;
-
- struct Image *bakebuf;
-
- struct GHash *orco_hash;
-
- struct GHash *sss_hash;
- ListBase *sss_points;
- struct Material *sss_mat;
-
- ListBase customdata_names;
-
- struct Object *excludeob;
- ListBase render_volumes_inside;
- ListBase volumes;
-
#ifdef WITH_FREESTYLE
struct Main *freestyle_bmain;
ListBase freestyle_renders;
#endif
- /* arena for allocating data for use during render, for
- * example dynamic TFaces to go in the VlakRen structure.
- */
- struct MemArena *memArena;
-
/* callbacks */
void (*display_init)(void *handle, RenderResult *rr);
void *dih;
@@ -276,414 +155,14 @@ struct Render {
struct ReportList *reports;
- struct ImagePool *pool;
-
void **movie_ctx_arr;
char viewname[MAX_NAME];
};
-/* ------------------------------------------------------------------------- */
-
-struct ISBData;
-
-typedef struct DeepSample {
- int z;
- float v;
-} DeepSample;
-
-typedef struct ShadSampleBuf {
- struct ShadSampleBuf *next, *prev;
- intptr_t *zbuf;
- char *cbuf;
- DeepSample **deepbuf;
- int *totbuf;
-} ShadSampleBuf;
-
-typedef struct ShadBuf {
- /* regular shadowbuffer */
- short samp, shadhalostep, totbuf;
- float persmat[4][4];
- float viewmat[4][4];
- float winmat[4][4];
- float *jit, *weight;
- float d, clipend, pixsize, soft, compressthresh;
- int co[3];
- int size, bias;
- ListBase buffers;
-
- /* irregular shadowbufer, result stored per thread */
- struct ISBData *isb_result[BLENDER_MAX_THREADS];
-} ShadBuf;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct ObjectRen {
- struct ObjectRen *next, *prev;
- struct Object *ob, *par;
- struct Scene *sce;
- int index, psysindex, flag, lay;
-
- float boundbox[2][3];
-
- int totvert, totvlak, totstrand, tothalo;
- int vertnodeslen, vlaknodeslen, strandnodeslen, blohalen;
- struct VertTableNode *vertnodes;
- struct VlakTableNode *vlaknodes;
- struct StrandTableNode *strandnodes;
- struct HaloRen **bloha;
- struct StrandBuffer *strandbuf;
-
- char (*mtface)[MAX_CUSTOMDATA_LAYER_NAME];
- char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
- int actmtface, actmcol, bakemtface;
-
- short tangent_mask; /* which tangent layer should be calculated */
-
- float obmat[4][4]; /* only used in convertblender.c, for instancing */
-
- /* used on makeraytree */
- struct RayObject *raytree;
- struct RayFace *rayfaces;
- struct VlakPrimitive *rayprimitives;
- struct ObjectInstanceRen *rayobi;
-
-} ObjectRen;
-
-typedef struct ObjectInstanceRen {
- struct ObjectInstanceRen *next, *prev;
-
- ObjectRen *obr;
- Object *ob, *par;
- int index, psysindex, lay;
-
- float mat[4][4], imat[4][4];
- float nmat[3][3]; /* nmat is inverse mat tranposed */
-
- float obmat[4][4], obinvmat[4][4];
- float localtoviewmat[4][4], localtoviewinvmat[4][4];
-
- short flag;
-
- float dupliorco[3], dupliuv[2];
- float (*duplitexmat)[4];
-
- struct VolumePrecache *volume_precache;
-
- float *vectors; /* (RE_WINSPEED_ELEMS * VertRen.index) */
- int totvector;
-
- /* used on makeraytree */
- struct RayObject *raytree;
- int transform_primitives;
-
- /* Particle info */
- float part_index;
- float part_age;
- float part_lifetime;
- float part_size;
- float part_co[3];
- float part_vel[3];
- float part_avel[3];
-
- unsigned int random_id;
-} ObjectInstanceRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct VertRen {
- float co[3];
- float n[3];
- float *orco;
- unsigned int flag; /* in use for clipping zbuffer parts, temp setting stuff in convertblender.c
- * only an 'int' because of alignment, could be a char too */
- float accum; /* accum for radio weighting, and for strand texco static particles */
- int index; /* index allows extending vertren with any property */
-} VertRen;
-
-/* ------------------------------------------------------------------------- */
-
-struct halosort {
- struct HaloRen *har;
- int z;
-};
-
-/* ------------------------------------------------------------------------- */
-struct Material;
-struct ImagePool;
-
-typedef struct RadFace {
- float unshot[3], totrad[3];
- float norm[3], cent[3], area;
- int flag;
-} RadFace;
-
-typedef struct VlakRen {
- struct VertRen *v1, *v2, *v3, *v4; /* keep in order for ** addressing */
- float n[3];
- struct Material *mat;
- char puno;
- char flag, ec;
-#ifdef WITH_FREESTYLE
- char freestyle_edge_mark;
- char freestyle_face_mark;
-#endif
- int index;
-} VlakRen;
-
-typedef struct HaloRen {
- short miny, maxy;
- float alfa, xs, ys, rad, radsq, sin, cos, co[3], no[3];
- float hard, b, g, r;
- int zs, zd;
- int zBufDist; /* depth in the z-buffer coordinate system */
- char starpoints, type, add, tex;
- char linec, ringc, seed;
- short flarec; /* used to be a char. why ?*/
- float hasize;
- int pixels;
- unsigned int lay;
- struct Material *mat;
- struct ImagePool *pool;
- bool skip_load_image, texnode_preview;
-} HaloRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct StrandVert {
- float co[3];
- float strandco;
-} StrandVert;
-
-typedef struct StrandSurface {
- struct StrandSurface *next, *prev;
- ObjectRen obr;
- int (*face)[4];
- float (*co)[3];
- /* for occlusion caching */
- float (*ao)[3];
- float (*env)[3];
- float (*indirect)[3];
- /* for speedvectors */
- float (*prevco)[3], (*nextco)[3];
- int totvert, totface;
-} StrandSurface;
-
-typedef struct StrandBound {
- int start, end;
- float boundbox[2][3];
-} StrandBound;
-
-typedef struct StrandBuffer {
- struct StrandBuffer *next, *prev;
- struct StrandVert *vert;
- struct StrandBound *bound;
- int totvert, totbound;
-
- struct ObjectRen *obr;
- struct Material *ma;
- struct StrandSurface *surface;
- unsigned int lay;
- int overrideuv;
- int flag, maxdepth;
- float adaptcos, minwidth, widthfade;
-
- float maxwidth; /* for cliptest of strands in blender unit */
-
- float winmat[4][4];
- int winx, winy;
-} StrandBuffer;
-
-typedef struct StrandRen {
- StrandVert *vert;
- StrandBuffer *buffer;
- int totvert, flag;
- int clip, index;
- float orco[3];
-} StrandRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct VolumeOb {
- struct VolumeOb *next, *prev;
- struct Material *ma;
- struct ObjectRen *obr;
-} VolumeOb;
-
-typedef struct MatInside {
- struct MatInside *next, *prev;
- struct Material *ma;
- struct ObjectInstanceRen *obi;
-} MatInside;
-
-typedef struct VolPrecachePart {
- struct VolPrecachePart *next, *prev;
- struct RayObject *tree;
- struct ShadeInput *shi;
- struct ObjectInstanceRen *obi;
- float viewmat[4][4];
- int num;
- int minx, maxx;
- int miny, maxy;
- int minz, maxz;
- int res[3];
- float bbmin[3];
- float voxel[3];
- struct Render *re;
-} VolPrecachePart;
-
-typedef struct VolumePrecache {
- int res[3];
- float *bbmin, *bbmax;
- float *data_r;
- float *data_g;
- float *data_b;
-} VolumePrecache;
-
-/* ------------------------------------------------------------------------- */
-
-struct LampRen;
-struct MTex;
-
-/**
- * For each lamp in a scene, a LampRen is created. It determines the
- * properties of a lightsource.
- */
-
-typedef struct LampShadowSubSample {
- int samplenr;
- float shadfac[4]; /* rgba shadow */
-} LampShadowSubSample;
-
-typedef struct LampShadowSample {
- LampShadowSubSample s[16]; /* MAX OSA */
-} LampShadowSample;
-
-typedef struct LampRen {
- struct LampRen *next, *prev;
-
- float xs, ys, dist;
- float co[3];
- short type;
- int mode;
- float r, g, b, k;
- float shdwr, shdwg, shdwb;
- float energy, haint;
- int lay;
- float spotsi, spotbl;
- float vec[3];
- float xsp, ysp, distkw, inpr;
- float halokw, halo;
-
- short falloff_type;
- float ld1, ld2;
- float coeff_const, coeff_lin, coeff_quad;
- struct CurveMapping *curfalloff;
-
- /* copied from Lamp, to decouple more rendering stuff */
- /** Size of the shadowbuffer */
- short bufsize;
- /** Number of samples for the shadows */
- short samp;
- /** Softness factor for shadow */
- float soft;
- /** amount of subsample buffers and type of filter for sampling */
- short buffers, filtertype;
- /** shadow buffer type (regular, irregular) */
- short buftype;
- /** autoclip */
- short bufflag;
- /** shadow plus halo: detail level */
- short shadhalostep;
- /** Near clip of the lamp */
- float clipsta;
- /** Far clip of the lamp */
- float clipend;
- /** A small depth offset to prevent self-shadowing. */
- float bias;
- /* Compression threshold for deep shadow maps */
- float compressthresh;
-
- short ray_samp, ray_sampy, ray_sampz, ray_samp_method, ray_samp_type, area_shape, ray_totsamp;
- short xold[BLENDER_MAX_THREADS], yold[BLENDER_MAX_THREADS]; /* last jitter table for area lights */
- float area_size, area_sizey, area_sizez;
- float adapt_thresh;
-
- /* sun/sky */
- struct SunSky *sunsky;
-
- struct ShadBuf *shb;
- float *jitter;
-
- float imat[3][3];
- float spottexfac;
- float sh_invcampos[3], sh_zfac; /* sh_= spothalo */
-
- float lampmat[4][4]; /* worls space lamp matrix, used for scene rotation */
-
- float mat[3][3]; /* 3x3 part from lampmat x viewmat */
- float area[8][3], areasize;
-
- /* passes & node shader support: all shadow info for a pixel */
- LampShadowSample *shadsamp;
-
- /* ray optim */
- struct RayObject *last_hit[BLENDER_MAX_THREADS];
-
- struct MTex *mtex[MAX_MTEX];
-
- /* threading */
- int thread_assigned;
- int thread_ready;
-} LampRen;
-
/* **************** defines ********************* */
-/* R.r.mode flag is same as for renderdata */
-
/* R.flag */
-#define R_ZTRA 1
-#define R_HALO 2
-#define R_SEC_FIELD 4
-#define R_LAMPHALO 8
-#define R_NEED_TANGENT 16
-#define R_BAKE_TRACE 32
-#define R_BAKING 64
-#define R_ANIMATION 128
-#define R_NEED_VCOL 256
-
-/* vlakren->flag (vlak = face in dutch) char!!! */
-#define R_SMOOTH 1
-#define R_HIDDEN 2
-/* strand flag, means special handling */
-#define R_STRAND 4
-#define R_FULL_OSA 8
-#define R_FACE_SPLIT 16
-/* Tells render to divide face other way. */
-#define R_DIVIDE_24 32
-/* vertex normals are tangent or view-corrected vector, for hair strands */
-#define R_TANGENT 64
-#define R_TRACEBLE 128
-
-/* vlakren->freestyle_edge_mark */
-#ifdef WITH_FREESTYLE
-# define R_EDGE_V1V2 1
-# define R_EDGE_V2V3 2
-# define R_EDGE_V3V4 4
-# define R_EDGE_V3V1 4
-# define R_EDGE_V4V1 8
-#endif
-
-/* strandbuffer->flag */
-#define R_STRAND_BSPLINE 1
-#define R_STRAND_B_UNITS 2
-
-/* objectren->flag */
-#define R_INSTANCEABLE 1
-
-/* objectinstance->flag */
-#define R_DUPLI_TRANSFORMED 1
-#define R_ENV_TRANSFORMED 2
-#define R_TRANSFORMED (1|2)
+#define R_ANIMATION 1
#endif /* __RENDER_TYPES_H__ */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
deleted file mode 100644
index c01db7db53e..00000000000
--- a/source/blender/render/intern/include/rendercore.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __RENDERCORE_H__
-#define __RENDERCORE_H__
-
-/** \file blender/render/intern/include/rendercore.h
- * \ingroup render
- */
-
-#include "render_types.h"
-
-#include "RE_engine.h"
-
-#include "DNA_node_types.h"
-
-#include "NOD_composite.h"
-
-struct ShadeInput;
-struct ShadeResult;
-struct World;
-struct RenderPart;
-struct RenderLayer;
-struct RayObject;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct PixStr {
- struct PixStr *next;
- int obi, facenr, z, maskz;
- unsigned short mask;
- short shadfac;
-} PixStr;
-
-typedef struct PixStrMain {
- struct PixStrMain *next, *prev;
- struct PixStr *ps;
- int counter;
-} PixStrMain;
-
-/* ------------------------------------------------------------------------- */
-
-
-void calc_view_vector(float view[3], float x, float y);
-float mistfactor(float zcor, const float co[3]); /* dist and height, return alpha */
-
-void renderspothalo(struct ShadeInput *shi, float col[4], float alpha);
-void add_halo_flare(Render *re);
-
-void calc_renderco_zbuf(float co[3], const float view[3], int z);
-void calc_renderco_ortho(float co[3], float x, float y, int z);
-
-int count_mask(unsigned short mask);
-
-void zbufshade_tile(struct RenderPart *pa);
-void zbufshadeDA_tile(struct RenderPart *pa);
-
-void zbufshade_sss_tile(struct RenderPart *pa);
-
-int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp);
-
-void render_internal_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer);
-
-
-/* -------- ray.c ------- */
-
-struct RayObject *RE_rayobject_create(int type, int size, int octree_resolution);
-
-extern void freeraytree(Render *re);
-extern void makeraytree(Render *re);
-struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
-
-extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
-extern void ray_trace(ShadeInput *shi, ShadeResult *);
-extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
-extern void init_jitter_plane(LampRen *lar);
-extern void init_ao_sphere(Render *re, struct World *wrld);
-extern void init_render_qmcsampler(Render *re);
-extern void free_render_qmcsampler(Render *re);
-
-#endif /* __RENDERCORE_H__ */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
deleted file mode 100644
index 6b2deea57d8..00000000000
--- a/source/blender/render/intern/include/renderdatabase.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * ***** 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) 2006 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/renderdatabase.h
- * \ingroup render
- */
-
-
-#ifndef __RENDERDATABASE_H__
-#define __RENDERDATABASE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct Object;
-struct VlakRen;
-struct VertRen;
-struct Depsgraph;
-struct HaloRen;
-struct Main;
-struct Material;
-struct Render;
-struct MCol;
-struct MTFace;
-struct CustomData;
-struct StrandBuffer;
-struct StrandRen;
-struct ObjectInstanceRen;
-struct RadFace;
-struct Isect;
-
-#define RE_QUAD_MASK 0x7FFFFFF
-#define RE_QUAD_OFFS 0x8000000
-
-/* render allocates totvert/256 of these nodes, for lookup and quick alloc */
-typedef struct VertTableNode {
- struct VertRen *vert;
- float *rad;
- float *strand;
- float *tangent;
- float *stress;
- float *winspeed;
- /* Index of vertex in source mesh (before modifiers). */
- int *origindex;
-} VertTableNode;
-
-typedef struct VlakTableNode {
- struct VlakRen *vlak;
- struct MTFace *mtface;
- struct MCol *mcol;
- /* Index of mpoly in source mesh (before tessellation). */
- int *origindex;
- int totmtface, totmcol;
- float *surfnor;
- float *tangent_arrays[MAX_MTFACE];
- struct RadFace **radface;
-} VlakTableNode;
-
-typedef struct StrandTableNode {
- struct StrandRen *strand;
- float *winspeed;
- float *surfnor;
- float *simplify;
- int *face;
- struct MCol *mcol;
- float *uv;
- int totuv, totmcol;
-} StrandTableNode;
-
-/* renderdatabase.c */
-void free_renderdata_tables(struct Render *re);
-void free_renderdata_vertnodes(struct VertTableNode *vertnodes);
-void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
-
-void project_renderdata(struct Render *re, void (*projectfunc)(const float *, float mat[4][4], float *), bool do_pano, float xoffs, bool do_buckets);
-int clip_render_object(float boundbox[2][3], float bounds[4], float mat[4][4]);
-
-/* functions are not exported... so wrong names */
-
-struct VlakRen *RE_findOrAddVlak(struct ObjectRen *obr, int nr);
-struct VertRen *RE_findOrAddVert(struct ObjectRen *obr, int nr);
-struct StrandRen *RE_findOrAddStrand(struct ObjectRen *obr, int nr);
-struct HaloRen *RE_findOrAddHalo(struct ObjectRen *obr, int nr);
-struct HaloRen *RE_inithalo(struct Render *re, struct ObjectRen *obr, struct Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, float hasize, float vectsize, int seed);
-struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, struct Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, const float *uvco, float hasize, float vectsize, int seed,
- const float pa_co[3]);
-struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert);
-
-struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay);
-struct ObjectInstanceRen *RE_addRenderInstance(
- struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par,
- int index, int psysindex, float mat[4][4], int lay, const struct DupliObject *dob);
-void RE_makeRenderInstances(struct Render *re);
-void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag);
-
-void RE_instance_rotate_ray_start(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray_dir(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray_restore(struct ObjectInstanceRen *obi, struct Isect *is);
-
-float *RE_vertren_get_stress(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_rad(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_strand(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_tangent(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ver, int verify);
-int *RE_vertren_get_origindex(struct ObjectRen *obr, VertRen *ver, int verify);
-
-struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
-struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
-int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify);
-float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
-float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify);
-RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
-void RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor);
-
-float *RE_strandren_get_surfnor(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-float *RE_strandren_get_uv(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
-struct MCol *RE_strandren_get_mcol(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
-float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-int *RE_strandren_get_face(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-float *RE_strandren_get_winspeed(struct ObjectInstanceRen *obi, struct StrandRen *strand, int verify);
-
-struct VertRen *RE_vertren_copy(struct ObjectRen *obr, struct VertRen *ver);
-struct VlakRen *RE_vlakren_copy(struct ObjectRen *obr, struct VlakRen *vlr);
-
-void RE_set_customdata_names(struct ObjectRen *obr, struct CustomData *data);
-
-void area_lamp_vectors(struct LampRen *lar);
-
-
-/* haloren->type: flags */
-#define HA_ONLYSKY 1
-#define HA_VECT 2
-#define HA_XALPHA 4
-#define HA_FLARECIRC 8
-
-/* convertblender.c */
-void init_render_world(Render *re);
-void RE_Database_FromScene_Vectors(struct Depsgraph *depsgraph, Render *re, struct Main *bmain, struct Scene *sce, unsigned int lay);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RENDERDATABASE_H__ */
-
diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h
index 8c23eb0d4cb..68fbc01b914 100644
--- a/source/blender/render/intern/include/renderpipeline.h
+++ b/source/blender/render/intern/include/renderpipeline.h
@@ -38,13 +38,10 @@ struct Render;
struct RenderData;
struct RenderLayer;
struct RenderResult;
-struct ViewRender;
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
-float panorama_pixel_rot(struct Render *re);
void render_update_anim_renderdata(struct Render *re, struct RenderData *rd, struct ListBase *render_layers);
void render_copy_renderdata(struct RenderData *to, struct RenderData *from);
-void render_copy_viewrender(struct ViewRender *to, struct ViewRender *from);
#endif /* __RENDERPIPELINE_H__ */
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
deleted file mode 100644
index ddf5de8d974..00000000000
--- a/source/blender/render/intern/include/shadbuf.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __SHADBUF_H__
-#define __SHADBUF_H__
-
-/** \file blender/render/intern/include/shadbuf.h
- * \ingroup render
- */
-
-#include "render_types.h"
-
-
-/**
- * Calculates shadowbuffers for a vector of shadow-giving lamps
- * \param lar The vector of lamps
- */
-void makeshadowbuf(struct Render *re, LampRen *lar);
-void freeshadowbuf(struct LampRen *lar);
-
-void threaded_makeshadowbufs(struct Render *re);
-
-/**
- * Determines the shadow factor for a face and lamp. There is some
- * communication with global variables here.
- * \return The shadow factors: 1.0 for no shadow, 0.0 for complete
- * shadow.
- * \param shb The shadowbuffer to find the shadow factor in.
- * \param inp The inproduct between viewvector and ?
- *
- */
-float testshadowbuf(struct Render *re, struct ShadBuf *shb, const float rco[3], const float dxco[3], const float dyco[3], float inp, float mat_bias);
-
-/**
- * Determines the shadow factor for lamp \a lar, between \a p1 and \a p2. (Which CS?)
- */
-float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]);
-
-/**
- * Irregular shadowbuffer
- */
-
-struct MemArena;
-struct APixstr;
-
-void ISB_create(RenderPart *pa, struct APixstr *apixbuf);
-void ISB_free(RenderPart *pa);
-float ISB_getshadow(ShadeInput *shi, ShadBuf *shb);
-
-/* data structures have to be accessible both in camview(x, y) as in lampview(x, y) */
-/* since they're created per tile rendered, speed goes over memory requirements */
-
-
-/* buffer samples, allocated in camera buffer and pointed to in lampbuffer nodes */
-typedef struct ISBSample {
- float zco[3]; /* coordinate in lampview projection */
- short *shadfac; /* initialized zero = full lighted */
- int obi; /* object for face lookup */
- int facenr; /* index in faces list */
-} ISBSample;
-
-/* transparent version of buffer sample */
-typedef struct ISBSampleA {
- float zco[3]; /* coordinate in lampview projection */
- short *shadfac; /* NULL = full lighted */
- int obi; /* object for face lookup */
- int facenr; /* index in faces list */
- struct ISBSampleA *next; /* in end, we want the first items to align with ISBSample */
-} ISBSampleA;
-
-/* used for transparent storage only */
-typedef struct ISBShadfacA {
- struct ISBShadfacA *next;
- int obi;
- int facenr;
- float shadfac;
-} ISBShadfacA;
-
-/* What needs to be stored to evaluate shadow, for each thread in ShadBuf */
-typedef struct ISBData {
- short *shadfacs; /* simple storage for solid only */
- ISBShadfacA **shadfaca;
- struct MemArena *memarena;
- int minx, miny, rectx, recty; /* copy from part disprect */
-} ISBData;
-
-#endif /* __SHADBUF_H__ */
-
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
deleted file mode 100644
index 3ef6e9d7476..00000000000
--- a/source/blender/render/intern/include/shading.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * ***** 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) 2006 Blender Foundation
- * All rights reserved.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/shading.h
- * \ingroup render
- */
-
-
-struct ShadeInput;
-struct ShadeResult;
-struct RenderPart;
-struct RenderLayer;
-struct PixStr;
-struct LampRen;
-struct VlakRen;
-struct StrandPoint;
-struct ObjectInstanceRen;
-struct Isect;
-
-/* shadeinput.c */
-
-#define RE_MAX_OSA 16
-
-/* needed to calculate shadow and AO for an entire pixel */
-typedef struct ShadeSample {
- int tot; /* amount of shi in use, can be 1 for not FULL_OSA */
-
- RenderLayer *rlpp[RE_MAX_OSA]; /* fast lookup from sample to renderlayer (fullsample buf) */
-
- /* could be malloced once */
- ShadeInput shi[RE_MAX_OSA];
- ShadeResult shr[RE_MAX_OSA];
-} ShadeSample;
-
-
- /* also the node shader callback */
-void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
-void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip);
-void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
-void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]);
-void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z);
-void shade_input_set_uv(struct ShadeInput *shi);
-void shade_input_set_normals(struct ShadeInput *shi);
-void shade_input_set_vertex_normals(struct ShadeInput *shi);
-void shade_input_flip_normals(struct ShadeInput *shi);
-void shade_input_set_shade_texco(struct ShadeInput *shi);
-void shade_input_set_strand(struct ShadeInput *shi, struct StrandRen *strand, struct StrandPoint *spoint);
-void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint);
-void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_input_init_material(struct ShadeInput *shi);
-void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
-
-void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
-void shade_samples_do_AO(struct ShadeSample *ssamp);
-void shade_samples_fill_with_ps(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
-int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
-
-void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);
-
-void calc_R_ref(struct ShadeInput *shi);
-
-void barycentric_differentials_from_position(
- const float co[3], const float v1[3], const float v2[3], const float v3[3],
- const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
- float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v);
-
-/* shadeoutput. */
-void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_color(struct ShadeInput *shi, ShadeResult *shr);
-
-void ambient_occlusion(struct ShadeInput *shi);
-void environment_lighting_apply(struct ShadeInput *shi, struct ShadeResult *shr);
-
-ListBase *get_lights(struct ShadeInput *shi);
-float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist);
-void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real);
-
-float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac);
-
-/* rayshade.c */
-extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
deleted file mode 100644
index 0952c6bff65..00000000000
--- a/source/blender/render/intern/include/sss.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/sss.h
- * \ingroup render
- */
-
-
-#ifndef __SSS_H__
-#define __SSS_H__
-
-/* Generic multiple scattering API */
-
-struct ScatterSettings;
-typedef struct ScatterSettings ScatterSettings;
-
-struct ScatterTree;
-typedef struct ScatterTree ScatterTree;
-
-ScatterSettings *scatter_settings_new(float refl, float radius, float ior,
- float reflfac, float frontweight, float backweight);
-void scatter_settings_free(ScatterSettings *ss);
-
-ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
- float (*co)[3], float (*color)[3], float *area, int totpoint);
-void scatter_tree_build(ScatterTree *tree);
-void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3]);
-void scatter_tree_free(ScatterTree *tree);
-
-/* Internal renderer API */
-
-struct Render;
-struct Material;
-
-void make_sss_tree(struct Render *re);
-void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint);
-void free_sss(struct Render *re);
-
-int sample_sss(struct Render *re, struct Material *mat, const float co[3], float color[3]);
-int sss_pass_done(struct Render *re, struct Material *mat);
-
-#endif /*__SSS_H__*/
-
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
deleted file mode 100644
index 5687ef3c837..00000000000
--- a/source/blender/render/intern/include/strand.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/strand.h
- * \ingroup render
- */
-
-
-#ifndef __STRAND_H__
-#define __STRAND_H__
-
-struct StrandVert;
-struct StrandRen;
-struct StrandBuffer;
-struct ShadeSample;
-struct StrandPart;
-struct Render;
-struct ZSpan;
-struct ObjectInstanceRen;
-struct StrandSurface;
-struct DerivedMesh;
-struct ObjectRen;
-
-typedef struct StrandPoint {
- /* position within segment */
- float t;
-
- /* camera space */
- float co[3];
- float nor[3];
- float tan[3];
- float strandco;
- float width;
-
- /* derivatives */
- float dtco[3], dsco[3];
- float dtstrandco;
-
- /* outer points */
- float co1[3], co2[3];
- float hoco1[4], hoco2[4];
- float zco1[3], zco2[3];
- int clip1, clip2;
-
- /* screen space */
- float hoco[4];
- float x, y;
-
- /* simplification */
- float alpha;
-} StrandPoint;
-
-typedef struct StrandSegment {
- struct StrandVert *v[4];
- struct StrandRen *strand;
- struct StrandBuffer *buffer;
- struct ObjectInstanceRen *obi;
- float sqadaptcos;
-
- StrandPoint point1, point2;
- int shaded;
-} StrandSegment;
-
-struct StrandShadeCache;
-typedef struct StrandShadeCache StrandShadeCache;
-
-void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
-void render_strand_segment(struct Render *re, float winmat[4][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg);
-void strand_minmax(struct StrandRen *strand, float min[3], float max[3], const float width);
-
-struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[4][4], int timeoffset);
-void free_strand_surface(struct Render *re);
-
-struct StrandShadeCache *strand_shade_cache_create(void);
-void strand_shade_cache_free(struct StrandShadeCache *cache);
-void strand_shade_segment(struct Render *re, struct StrandShadeCache *cache, struct StrandSegment *sseg, struct ShadeSample *ssamp, float t, float s, int addpassflag);
-void strand_shade_unref(struct StrandShadeCache *cache, struct ObjectInstanceRen *obi, struct StrandVert *svert);
-
-#endif
-
diff --git a/source/blender/render/intern/include/sunsky.h b/source/blender/render/intern/include/sunsky.h
deleted file mode 100644
index 60fa8aa51ba..00000000000
--- a/source/blender/render/intern/include/sunsky.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): zaghaghi
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/sunsky.h
- * \ingroup render
- */
-
-#ifndef __SUNSKY_H__
-#define __SUNSKY_H__
-
-// #define SPECTRUM_MAX_COMPONENTS 100
-
-typedef struct SunSky {
- short effect_type, skyblendtype, sky_colorspace;
- float turbidity;
- float theta, phi;
-
- float toSun[3];
-
- /*float sunSpectralRaddata[SPECTRUM_MAX_COMPONENTS];*/
- float sunSolidAngle;
-
- float zenith_Y, zenith_x, zenith_y;
-
- float perez_Y[5], perez_x[5], perez_y[5];
-
- /* suggested by glome in patch [#8063] */
- float horizon_brightness;
- float spread;
- float sun_brightness;
- float sun_size;
- float backscattered_light;
- float skyblendfac;
- float sky_exposure;
-
- float atm_HGg;
-
- float atm_SunIntensity;
- float atm_InscatteringMultiplier;
- float atm_ExtinctionMultiplier;
- float atm_BetaRayMultiplier;
- float atm_BetaMieMultiplier;
- float atm_DistanceMultiplier;
-
- float atm_BetaRay[3];
- float atm_BetaDashRay[3];
- float atm_BetaMie[3];
- float atm_BetaDashMie[3];
- float atm_BetaRM[3];
-} SunSky;
-
-void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
- float spread, float sun_brightness, float sun_size, float back_scatter,
- float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace);
-
-void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3]);
-void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3]);
-void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf, float inscattf, float extincf, float disf);
-void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3]);
-void ClipColor(float c[3]);
-
-#endif /*__SUNSKY_H__*/
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index dfb491f46b0..71000e38960 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -63,29 +63,12 @@
} \
} \
-struct HaloRen;
-struct ShadeInput;
struct TexResult;
struct Tex;
struct Image;
struct ImBuf;
struct ImagePool;
-/* texture.h */
-
-void do_halo_tex(struct HaloRen *har, float xn, float yn, float col_r[4]);
-void do_sky_tex(
- const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
- float hor[3], float zen[3], float *blend, int skyflag, short thread);
-void do_material_tex(struct ShadeInput *shi, struct Render *re);
-void do_lamp_tex(LampRen *la, const float lavec[3], struct ShadeInput *shi, float col_r[3], int effect);
-void do_volume_tex(struct ShadeInput *shi, const float xyz[3], int mapto_flag, float col_r[3], float *val, struct Render *re);
-
-void init_render_textures(Render *re);
-void end_render_textures(Render *re);
-
-void render_realtime_texture(struct ShadeInput *shi, struct Image *ima);
-
/* imagetexture.h */
int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image);
diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/render/intern/include/texture_ocean.h
deleted file mode 100644
index 4a71aff930a..00000000000
--- a/source/blender/render/intern/include/texture_ocean.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * ***** 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: Matt Ebb
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __TEXTURE_OCEAN_H__
-#define __TEXTURE_OCEAN_H__
-
-/** \file blender/render/intern/include/texture_ocean.h
- * \ingroup render
- */
-
-int ocean_texture(struct Tex *tex, const float texvec[2], struct TexResult *texres);
-
-#endif /* __TEXTURE_OCEAN_H__ */
diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/render/intern/include/volume_precache.h
deleted file mode 100644
index 9aa280d8276..00000000000
--- a/source/blender/render/intern/include/volume_precache.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/volume_precache.h
- * \ingroup render
- */
-
-
-void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3]);
-int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3]);
-
-void volume_precache(Render *re);
-void free_volume_precache(Render *re);
-
-#define VOL_MS_TIMESTEP 0.1f
diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h
deleted file mode 100644
index 3805478fed0..00000000000
--- a/source/blender/render/intern/include/volumetric.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/volumetric.h
- * \ingroup render
- */
-
-
-struct Isect;
-struct ShadeInput;
-struct ShadeResult;
-
-float vol_get_density(struct ShadeInput *shi, const float co[3]);
-void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3]);
-
-void shade_volume_outside(ShadeInput *shi, ShadeResult *shr);
-void shade_volume_inside(ShadeInput *shi, ShadeResult *shr);
-void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is);
-
-#define VOL_IS_BACKFACE 1
-#define VOL_IS_SAMEMATERIAL 2
-
-#define VOL_BOUNDS_DEPTH 0
-#define VOL_BOUNDS_SS 1
-
-#define VOL_SHADE_OUTSIDE 0
-#define VOL_SHADE_INSIDE 1
diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h
deleted file mode 100644
index dd2262e0357..00000000000
--- a/source/blender/render/intern/include/voxeldata.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/voxeldata.h
- * \ingroup render
- */
-
-#ifndef __VOXELDATA_H__
-#define __VOXELDATA_H__
-
-struct Render;
-struct TexResult;
-
-typedef struct VoxelDataHeader {
- int resolX, resolY, resolZ;
- int frames;
-} VoxelDataHeader;
-
-void cache_voxeldata(Tex *tex, int scene_frame);
-void make_voxeldata(struct Render *re);
-int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
-
-#endif /* __VOXELDATA_H__ */
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index 6fc1a4c2656..1a93fc6c3b2 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -33,57 +33,6 @@
#ifndef __ZBUF_H__
#define __ZBUF_H__
-struct RenderPart;
-struct RenderLayer;
-struct LampRen;
-struct ListBase;
-struct ZSpan;
-struct APixstrand;
-struct APixstr;
-struct StrandShadeCache;
-
-void fillrect(int *rect, int x, int y, int val);
-
-/**
- * Converts a world coordinate into a homogeneous coordinate in view
- * coordinates.
- */
-void projectvert(const float v1[3], float winmat[4][4], float adr[4]);
-void projectverto(const float v1[3], float winmat[4][4], float adr[4]);
-int testclip(const float v[3]);
-
-void zbuffer_shadow(struct Render *re, float winmat[4][4], struct LampRen *lar, int *rectz, int size, float jitx, float jity);
-void zbuffer_abuf_shadow(struct Render *re, struct LampRen *lar, float winmat[4][4], struct APixstr *APixbuf, struct APixstrand *apixbuf, struct ListBase *apsmbase, int size, int samples, float (*jit)[2]);
-void zbuffer_solid(struct RenderPart *pa, struct RenderLayer *rl, void (*fillfunc)(struct RenderPart *, struct ZSpan *, int, void *), void *data);
-
-unsigned short *zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass, struct ListBase *psmlist);
-void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int, int));
-int zbuffer_strands_abuf(struct Render *re, struct RenderPart *pa, struct APixstrand *apixbuf, struct ListBase *apsmbase, unsigned int lay, int negzmask, float winmat[4][4], int winx, int winy, int sample, float (*jit)[2], float clipcrop, int shadow, struct StrandShadeCache *cache);
-
-typedef struct APixstr {
- unsigned short mask[4]; /* jitter mask */
- int z[4]; /* distance */
- int p[4]; /* index */
- int obi[4]; /* object instance */
- short shadfac[4]; /* optimize storage for irregular shadow */
- struct APixstr *next;
-} APixstr;
-
-typedef struct APixstrand {
- unsigned short mask[4]; /* jitter mask */
- int z[4]; /* distance */
- int p[4]; /* index */
- int obi[4]; /* object instance */
- int seg[4]; /* for strands, segment number */
- float u[4], v[4]; /* for strands, u,v coordinate in segment */
- struct APixstrand *next;
-} APixstrand;
-
-typedef struct APixstrMain {
- struct APixstrMain *next, *prev;
- void *ps;
-} APixstrMain;
-
/* span fill in method, is also used to localize data for zbuffering */
typedef struct ZSpan {
int rectx, recty; /* range for clipping */
@@ -91,61 +40,13 @@ typedef struct ZSpan {
int miny1, maxy1, miny2, maxy2; /* actual filled in range */
const float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */
float *span1, *span2;
-
- float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */
-
- int *rectz, *arectz; /* zbuffers, arectz is for transparent */
- int *rectz1; /* secondary z buffer for shadowbuffer (2nd closest z) */
- int *rectp; /* polygon index buffer */
- int *recto; /* object buffer */
- int *rectmask; /* negative zmask buffer */
- APixstr *apixbuf, *curpstr; /* apixbuf for transparent */
- APixstrand *curpstrand; /* same for strands */
- struct ListBase *apsmbase;
-
- int polygon_offset; /* offset in Z */
- float shad_alpha; /* copy from material, used by irregular shadbuf */
- int mask, apsmcounter; /* in use by apixbuf */
- int apstrandmcounter;
-
- float clipcrop; /* for shadow, was in R global before */
-
- void *sss_handle; /* used by sss */
- void (*sss_func)(void *, int, int, int, int, int);
-
- void (*zbuffunc)(struct ZSpan *, int, int, const float *, const float *, const float *, const float *);
- void (*zbuflinefunc)(struct ZSpan *, int, int, const float *, const float *);
-
} ZSpan;
-/* exported to shadbuf.c */
-void zbufclip4(struct ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4], const float f4[4],
- const int c1, const int c2, const int c3, const int c4);
+void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
void zbuf_free_span(struct ZSpan *zspan);
-void freepsA(struct ListBase *lb);
-/* to rendercore.c */
void zspan_scanconvert(struct ZSpan *zpan, void *handle, float *v1, float *v2, float *v3,
void (*func)(void *, int, int, float, float) );
-/* exported to edge render... */
-void zbufclip(struct ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4],
- const int c1, const int c2, const int c3);
-void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty, float clipcrop);
-void zbufclipwire(struct ZSpan *zspan, int obi, int zvlnr, int ec,
- const float ho1[4], const float ho2[4], const float ho3[4], const float ho4[4],
- const int c1, const int c2, const int c3, const int c4);
-
-/* exported to shadeinput.c */
-void zbuf_make_winmat(Render *re, float winmat[4][4]);
-void zbuf_render_project(float winmat[4][4], const float co[3], float ho[4]);
-
-/* should not really be exposed, bad! */
-void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4]);
-void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) );
-void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, const float ho1[4], const float ho2[4]);
-
#endif
diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h
deleted file mode 100644
index 25fdb41bb3a..00000000000
--- a/source/blender/render/intern/raytrace/bvh.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/bvh.h
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-
-#include "raycounter.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rayobject_hint.h"
-#include "rayobject_rtbuild.h"
-
-#include <assert.h>
-
-#ifdef __SSE__
-#include <xmmintrin.h>
-#endif
-
-#ifndef __BVH_H__
-#define __BVH_H__
-
-#ifdef __SSE__
-inline int test_bb_group4(__m128 *bb_group, const Isect *isec)
-{
- const __m128 tmin0 = _mm_setzero_ps();
- const __m128 tmax0 = _mm_set_ps1(isec->dist);
-
- float start[3], idot_axis[3];
- copy_v3_v3(start, isec->start);
- copy_v3_v3(idot_axis, isec->idot_axis);
-
- const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
- const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
- const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
- const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
- const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
- const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
-
- return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
-}
-#endif
-
-/*
- * Determines the distance that the ray must travel to hit the bounding volume of the given node
- * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
- * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
- */
-static inline int rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
-{
- const float *bb = _bb;
-
- float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
- float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
- float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
- float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
- float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
- float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
-
- RE_RC_COUNT(isec->raycounter->bb.test);
-
- if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
- if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
- if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
- RE_RC_COUNT(isec->raycounter->bb.hit);
-
- return 1;
-}
-
-/* bvh tree generics */
-template<class Tree> static void bvh_add(Tree *obj, RayObject *ob)
-{
- rtbuild_add(obj->builder, ob);
-}
-
-template<class Node>
-inline bool is_leaf(Node *node)
-{
- return !RE_rayobject_isAligned(node);
-}
-
-template<class Tree> static void bvh_done(Tree *obj);
-
-template<class Tree>
-static void bvh_free(Tree *obj)
-{
- if (obj->builder)
- rtbuild_free(obj->builder);
-
- if (obj->node_arena)
- BLI_memarena_free(obj->node_arena);
-
- MEM_freeN(obj);
-}
-
-template<class Tree>
-static void bvh_bb(Tree *obj, float *min, float *max)
-{
- if (obj->root)
- bvh_node_merge_bb(obj->root, min, max);
-}
-
-
-template<class Tree>
-static float bvh_cost(Tree *obj)
-{
- assert(obj->cost >= 0.0f);
- return obj->cost;
-}
-
-
-
-/* bvh tree nodes generics */
-template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
-{
- return rayobject_bb_intersect_test(isec, (const float *)node->bb);
-}
-
-
-template<class Node>
-static inline void bvh_node_merge_bb(Node *node, float min[3], float max[3])
-{
- if (is_leaf(node)) {
- RE_rayobject_merge_bb((RayObject *)node, min, max);
- }
- else {
- DO_MIN(node->bb, min);
- DO_MAX(node->bb + 3, max);
- }
-}
-
-
-
-/*
- * recursively transverse a BVH looking for a rayhit using a local stack
- */
-template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
-
-template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT, bool SHADOW>
-static int bvh_node_stack_raycast(Node *root, Isect *isec)
-{
- Node *stack[MAX_STACK_SIZE];
- int hit = 0, stack_pos = 0;
-
- if (!TEST_ROOT && !is_leaf(root))
- bvh_node_push_childs(root, isec, stack, stack_pos);
- else
- stack[stack_pos++] = root;
-
- while (stack_pos) {
- Node *node = stack[--stack_pos];
- if (!is_leaf(node)) {
- if (bvh_node_hit_test(node, isec)) {
- bvh_node_push_childs(node, isec, stack, stack_pos);
- assert(stack_pos <= MAX_STACK_SIZE);
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node, isec);
- if (SHADOW && hit) return hit;
- }
- }
- return hit;
-}
-
-
-#ifdef __SSE__
-/*
- * Generic SIMD bvh recursion
- * this was created to be able to use any simd (with the cost of some memmoves)
- * it can take advantage of any SIMD width and doens't needs any special tree care
- */
-template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT>
-static int bvh_node_stack_raycast_simd(Node *root, Isect *isec)
-{
- Node *stack[MAX_STACK_SIZE];
-
- int hit = 0, stack_pos = 0;
-
- if (!TEST_ROOT) {
- if (!is_leaf(root)) {
- if (!is_leaf(root->child))
- bvh_node_push_childs(root, isec, stack, stack_pos);
- else
- return RE_rayobject_intersect( (RayObject *)root->child, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *)root, isec);
- }
- else {
- if (!is_leaf(root))
- stack[stack_pos++] = root;
- else
- return RE_rayobject_intersect( (RayObject *)root, isec);
- }
-
- while (true) {
- //Use SIMD 4
- if (stack_pos >= 4) {
- __m128 t_bb[6];
- Node *t_node[4];
-
- stack_pos -= 4;
-
- /* prepare the 4BB for SIMD */
- t_node[0] = stack[stack_pos + 0]->child;
- t_node[1] = stack[stack_pos + 1]->child;
- t_node[2] = stack[stack_pos + 2]->child;
- t_node[3] = stack[stack_pos + 3]->child;
-
- const float *bb0 = stack[stack_pos + 0]->bb;
- const float *bb1 = stack[stack_pos + 1]->bb;
- const float *bb2 = stack[stack_pos + 2]->bb;
- const float *bb3 = stack[stack_pos + 3]->bb;
-
- const __m128 x0y0x1y1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(1, 0, 1, 0) );
- const __m128 x2y2x3y3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(1, 0, 1, 0) );
- t_bb[0] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[1] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(3, 1, 3, 1) );
-
- const __m128 z0X0z1X1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(3, 2, 3, 2) );
- const __m128 z2X2z3X3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(3, 2, 3, 2) );
- t_bb[2] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[3] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(3, 1, 3, 1) );
-
- const __m128 Y0Z0Y1Z1 = _mm_shuffle_ps(_mm_load_ps(bb0 + 4), _mm_load_ps(bb1 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
- const __m128 Y2Z2Y3Z3 = _mm_shuffle_ps(_mm_load_ps(bb2 + 4), _mm_load_ps(bb3 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
- t_bb[4] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[5] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(3, 1, 3, 1) );
-#if 0
- for (int i = 0; i < 4; i++)
- {
- Node *t = stack[stack_pos + i];
- assert(!is_leaf(t));
-
- float *bb = ((float *)t_bb) + i;
- bb[4 * 0] = t->bb[0];
- bb[4 * 1] = t->bb[1];
- bb[4 * 2] = t->bb[2];
- bb[4 * 3] = t->bb[3];
- bb[4 * 4] = t->bb[4];
- bb[4 * 5] = t->bb[5];
- t_node[i] = t->child;
- }
-#endif
- RE_RC_COUNT(isec->raycounter->simd_bb.test);
- int res = test_bb_group4(t_bb, isec);
-
- for (int i = 0; i < 4; i++)
- if (res & (1 << i)) {
- RE_RC_COUNT(isec->raycounter->simd_bb.hit);
- if (!is_leaf(t_node[i])) {
- for (Node *t = t_node[i]; t; t = t->sibling) {
- assert(stack_pos < MAX_STACK_SIZE);
- stack[stack_pos++] = t;
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)t_node[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- else if (stack_pos > 0) {
- Node *node = stack[--stack_pos];
- assert(!is_leaf(node));
-
- if (bvh_node_hit_test(node, isec)) {
- if (!is_leaf(node->child)) {
- bvh_node_push_childs(node, isec, stack, stack_pos);
- assert(stack_pos <= MAX_STACK_SIZE);
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child, isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- else break;
- }
- return hit;
-}
-#endif
-
-/*
- * recursively transverse a BVH looking for a rayhit using system stack
- */
-#if 0
-template<class Node>
-static int bvh_node_raycast(Node *node, Isect *isec)
-{
- int hit = 0;
- if (bvh_test_node(node, isec))
- {
- if (isec->idot_axis[node->split_axis] > 0.0f)
- {
- int i;
- for (i = 0; i < BVH_NCHILDS; i++)
- if (!is_leaf(node->child[i]))
- {
- if (node->child[i] == 0) break;
-
- hit |= bvh_node_raycast(node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else {
- int i;
- for (i = BVH_NCHILDS - 1; i >= 0; i--)
- if (!is_leaf(node->child[i]))
- {
- if (node->child[i])
- {
- hit |= dfs_raycast(node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- return hit;
-}
-#endif
-
-template<class Node, class HintObject>
-static void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject)
-{
- assert(hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE);
-
- if (is_leaf(node)) {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- else {
- int childs = count_childs(node);
- if (hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) {
- int result = hint_test_bb(hintObject, node->bb, node->bb + 3);
- if (result == HINT_RECURSE) {
- /* We are 100% sure the ray will be pass inside this node */
- bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject);
- }
- else if (result == HINT_ACCEPT) {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- }
- else {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- }
-}
-
-
-template<class Tree>
-static RayObjectAPI *bvh_get_api(int maxstacksize);
-
-
-template<class Tree, int DFS_STACK_SIZE>
-static inline RayObject *bvh_create_tree(int size)
-{
- Tree *obj = (Tree *)MEM_callocN(sizeof(Tree), "BVHTree");
- assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */
-
- obj->rayobj.api = bvh_get_api<Tree>(DFS_STACK_SIZE);
- obj->root = NULL;
-
- obj->node_arena = NULL;
- obj->builder = rtbuild_create(size);
-
- return RE_rayobject_unalignRayAPI((RayObject *) obj);
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
deleted file mode 100644
index c16ef5500df..00000000000
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_material_types.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "raycounter.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-
-/* RayFace
- *
- * note we force always inline here, because compiler refuses to otherwise
- * because function is too long. Since this is code that is called billions
- * of times we really do want to inline. */
-
-MALWAYS_INLINE RayObject *rayface_from_coords(RayFace *rayface, void *ob, void *face,
- float *v1, float *v2, float *v3, float *v4)
-{
- rayface->ob = ob;
- rayface->face = face;
-
- copy_v3_v3(rayface->v1, v1);
- copy_v3_v3(rayface->v2, v2);
- copy_v3_v3(rayface->v3, v3);
-
- if (v4) {
- copy_v3_v3(rayface->v4, v4);
- rayface->quad = 1;
- }
- else {
- rayface->quad = 0;
- }
-
- return RE_rayobject_unalignRayFace(rayface);
-}
-
-MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
-
- if (obi->transform_primitives) {
- mul_m4_v3(obi->mat, rayface->v1);
- mul_m4_v3(obi->mat, rayface->v2);
- mul_m4_v3(obi->mat, rayface->v3);
-
- if (RE_rayface_isQuad(rayface))
- mul_m4_v3(obi->mat, rayface->v4);
- }
-}
-
-RayObject *RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
-}
-
-RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
-{
- return rayface_from_coords(rayface, ob, face, v1, v2, v3, v4);
-}
-
-/* VlakPrimitive */
-
-RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
-{
- face->ob = obi;
- face->face = vlr;
-
- return RE_rayobject_unalignVlakPrimitive(face);
-}
-
-/* Checks for ignoring faces or materials */
-
-MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- /* for baking selected to active non-traceable materials might still
- * be in the raytree */
- if (!(vlr->flag & R_TRACEBLE))
- return 0;
-
- /* I know... cpu cycle waste, might do smarter once */
- if (is->mode == RE_RAY_MIRROR)
- return !(vlr->mat->mode & MA_ONLYCAST);
- else
- return (vlr->mat->mode2 & MA_CASTSHADOW) && (is->lay & obi->lay);
-}
-
-MALWAYS_INLINE int vlr_check_intersect_solid(Isect *UNUSED(is), ObjectInstanceRen *UNUSED(obi), VlakRen *vlr)
-{
- /* solid material types only */
- if (vlr->mat->material_type == MA_TYPE_SURFACE)
- return 1;
- else
- return 0;
-}
-
-MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UNUSED(vlr))
-{
- return (obi->obr->ob != is->userdata) && (obi->obr->ob->flag & SELECT);
-}
-
-/* Ray Triangle/Quad Intersection */
-
-static bool isect_ray_tri_watertight_no_sign_check_v3(
- const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
- const float v0[3], const float v1[3], const float v2[3],
- float *r_lambda, float r_uv[2])
-{
- const int kx = isect_precalc->kx;
- const int ky = isect_precalc->ky;
- const int kz = isect_precalc->kz;
- const float sx = isect_precalc->sx;
- const float sy = isect_precalc->sy;
- const float sz = isect_precalc->sz;
-
- /* Calculate vertices relative to ray origin. */
- const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
- const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
- const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
-
- const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
- const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
- const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
-
- /* Perform shear and scale of vertices. */
- const float ax = a_kx - sx * a_kz;
- const float ay = a_ky - sy * a_kz;
- const float bx = b_kx - sx * b_kz;
- const float by = b_ky - sy * b_kz;
- const float cx = c_kx - sx * c_kz;
- const float cy = c_ky - sy * c_kz;
-
- /* Calculate scaled barycentric coordinates. */
- const float u = cx * by - cy * bx;
- const float v = ax * cy - ay * cx;
- const float w = bx * ay - by * ax;
- float det;
-
- if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
- (u > 0.0f || v > 0.0f || w > 0.0f))
- {
- return false;
- }
-
- /* Calculate determinant. */
- det = u + v + w;
- if (UNLIKELY(det == 0.0f)) {
- return false;
- }
- else {
- /* Calculate scaled z-coordinates of vertices and use them to calculate
- * the hit distance.
- */
- const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
- /* Normalize u, v and t. */
- const float inv_det = 1.0f / det;
- if (r_uv) {
- r_uv[0] = u * inv_det;
- r_uv[1] = v * inv_det;
- }
- *r_lambda = t * inv_det;
- return true;
- }
-}
-
-MALWAYS_INLINE int isec_tri_quad(const float start[3],
- const struct IsectRayPrecalc *isect_precalc,
- const RayFace *face,
- float r_uv[2], float *r_lambda)
-{
- float uv[2], l;
-
- if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
- r_uv[0] = -uv[0];
- r_uv[1] = -uv[1];
- *r_lambda = l;
- return 1;
- }
- }
-
- /* intersect second triangle in quad */
- if (RE_rayface_isQuad(face)) {
- if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
- r_uv[0] = -uv[0];
- r_uv[1] = -uv[1];
- *r_lambda = l;
- return 2;
- }
- }
- }
-
- return 0;
-}
-
-/* Simpler yes/no Ray Triangle/Quad Intersection */
-
-MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3],
- const float dir[3],
- const RayFace *face)
-{
- float r[3];
- struct IsectRayPrecalc isect_precalc;
- float uv[2], l;
-
- negate_v3_v3(r, dir); /* note, different than above function */
-
- isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
-
- if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
- return 1;
- }
-
- /* intersect second triangle in quad */
- if (RE_rayface_isQuad(face)) {
- if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
- return 2;
- }
- }
-
- return 0;
-}
-
-/* RayFace intersection with checks and neighbor verifaction included,
- * Isect is modified if the face is hit. */
-
-MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
-{
- float dist, uv[2];
- int ok = 0;
-
- /* avoid self-intersection */
- if (is->orig.ob == face->ob && is->orig.face == face->face)
- return 0;
-
- /* check if we should intersect this face */
- if (is->check == RE_CHECK_VLR_RENDER) {
- if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
- else if (is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) {
- if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- if (vlr_check_intersect_solid(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
- else if (is->check == RE_CHECK_VLR_BAKE) {
- if (vlr_check_bake(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
-
- /* ray counter */
- RE_RC_COUNT(is->raycounter->faces.test);
-
- dist = is->dist;
- ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
-
- if (ok) {
-
- /* when a shadow ray leaves a face, it can be little outside the edges
- * of it, causing intersection to be detected in its neighbor face */
- if (is->skip & RE_SKIP_VLR_NEIGHBOUR) {
- if (dist < 0.1f && is->orig.ob == face->ob) {
- VlakRen *a = (VlakRen *)is->orig.face;
- VlakRen *b = (VlakRen *)face->face;
- ObjectRen *obr = ((ObjectInstanceRen *)face->ob)->obr;
-
- VertRen **va, **vb;
- int *org_idx_a, *org_idx_b;
- int i, j;
- bool is_neighbor = false;
-
- /* "same" vertex means either the actual same VertRen, or the same 'final org index', if available
- * (autosmooth only, currently). */
- for (i = 0, va = &a->v1; !is_neighbor && i < 4 && *va; ++i, ++va) {
- org_idx_a = RE_vertren_get_origindex(obr, *va, false);
- for (j = 0, vb = &b->v1; !is_neighbor && j < 4 && *vb; ++j, ++vb) {
- if (*va == *vb) {
- is_neighbor = true;
- }
- else if (org_idx_a) {
- org_idx_b = RE_vertren_get_origindex(obr, *vb, 0);
- if (org_idx_b && *org_idx_a == *org_idx_b) {
- is_neighbor = true;
- }
- }
- }
- }
-
- /* So there's a shared edge or vertex, let's intersect ray with self, if that's true
- * we can safely return 1, otherwise we assume the intersection is invalid, 0 */
- if (is_neighbor) {
- /* create RayFace from original face, transformed if necessary */
- RayFace origface;
- ObjectInstanceRen *ob = (ObjectInstanceRen *)is->orig.ob;
- rayface_from_vlak(&origface, ob, (VlakRen *)is->orig.face);
-
- if (!isec_tri_quad_neighbour(is->start, is->dir, &origface)) {
- return 0;
- }
- }
- }
- }
-
- RE_RC_COUNT(is->raycounter->faces.hit);
-
- is->isect = ok; // which half of the quad
- is->dist = dist;
- is->u = uv[0]; is->v = uv[1];
-
- is->hit.ob = face->ob;
- is->hit.face = face->face;
-#ifdef RT_USE_LAST_HIT
- is->last_hit = hit_obj;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-/* Intersection */
-
-int RE_rayobject_raycast(RayObject *r, Isect *isec)
-{
- int i;
-
- /* Pre-calculate orientation for watertight intersection checks. */
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- RE_RC_COUNT(isec->raycounter->raycast.test);
-
- /* setup vars used on raycast */
- for (i = 0; i < 3; i++) {
- isec->idot_axis[i] = 1.0f / isec->dir[i];
-
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
-#ifdef RT_USE_LAST_HIT
- /* last hit heuristic */
- if (isec->mode == RE_RAY_SHADOW && isec->last_hit) {
- RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
-
- if (RE_rayobject_intersect(isec->last_hit, isec)) {
- RE_RC_COUNT(isec->raycounter->raycast.hit);
- RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit);
- return 1;
- }
- }
-#endif
-
-#ifdef RT_USE_HINT
- isec->hit_hint = 0;
-#endif
-
- if (RE_rayobject_intersect(r, isec)) {
- RE_RC_COUNT(isec->raycounter->raycast.hit);
-
-#ifdef RT_USE_HINT
- isec->hint = isec->hit_hint;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-int RE_rayobject_intersect(RayObject *r, Isect *i)
-{
- if (RE_rayobject_isRayFace(r)) {
- return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i);
- }
- else if (RE_rayobject_isVlakPrimitive(r)) {
- //TODO optimize (useless copy to RayFace to avoid duplicate code)
- VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
- RayFace nface;
- rayface_from_vlak(&nface, face->ob, face->face);
-
- return intersect_rayface(r, &nface, i);
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->raycast(r, i);
- }
- else {
- assert(0);
- return 0;
- }
-}
-
-/* Building */
-
-void RE_rayobject_add(RayObject *r, RayObject *o)
-{
- r = RE_rayobject_align(r);
- return r->api->add(r, o);
-}
-
-void RE_rayobject_done(RayObject *r)
-{
- r = RE_rayobject_align(r);
- r->api->done(r);
-}
-
-void RE_rayobject_free(RayObject *r)
-{
- r = RE_rayobject_align(r);
- r->api->free(r);
-}
-
-float RE_rayobject_cost(RayObject *r)
-{
- if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
- return 1.0f;
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->cost(r);
- }
- else {
- assert(0);
- return 1.0f;
- }
-}
-
-/* Bounding Boxes */
-
-void RE_rayobject_merge_bb(RayObject *r, float min[3], float max[3])
-{
- if (RE_rayobject_isRayFace(r)) {
- RayFace *face = (RayFace *) RE_rayobject_align(r);
-
- DO_MINMAX(face->v1, min, max);
- DO_MINMAX(face->v2, min, max);
- DO_MINMAX(face->v3, min, max);
- if (RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max);
- }
- else if (RE_rayobject_isVlakPrimitive(r)) {
- VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
- RayFace nface;
- rayface_from_vlak(&nface, face->ob, face->face);
-
- DO_MINMAX(nface.v1, min, max);
- DO_MINMAX(nface.v2, min, max);
- DO_MINMAX(nface.v3, min, max);
- if (RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max);
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->api->bb(r, min, max);
- }
- else
- assert(0);
-}
-
-/* Hints */
-
-void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
-{
- if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
- return;
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->hint_bb(r, hint, min, max);
- }
- else
- assert(0);
-}
-
-/* RayObjectControl */
-
-int RE_rayobjectcontrol_test_break(RayObjectControl *control)
-{
- if (control->test_break)
- return control->test_break(control->data);
-
- return 0;
-}
-
-void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break)
-{
- if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->control.data = data;
- r->control.test_break = test_break;
- }
-}
-
diff --git a/source/blender/render/intern/raytrace/rayobject_empty.cpp b/source/blender/render/intern/raytrace/rayobject_empty.cpp
deleted file mode 100644
index eacec0b7eb9..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_empty.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_empty.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "rayobject.h"
-
-#include "BLI_utildefines.h"
-
-/*
- * Empty raytree
- */
-
-static int RE_rayobject_empty_intersect(RayObject *UNUSED(o), Isect *UNUSED(is))
-{
- return 0;
-}
-
-static void RE_rayobject_empty_free(RayObject *UNUSED(o))
-{
-}
-
-static void RE_rayobject_empty_bb(RayObject *UNUSED(o), float *UNUSED(min), float *UNUSED(max))
-{
- return;
-}
-
-static float RE_rayobject_empty_cost(RayObject *UNUSED(o))
-{
- return 0.0;
-}
-
-static void RE_rayobject_empty_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{}
-
-static RayObjectAPI empty_api =
-{
- RE_rayobject_empty_intersect,
- NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
- NULL, //static void RE_rayobject_instance_done(RayObject *o);
- RE_rayobject_empty_free,
- RE_rayobject_empty_bb,
- RE_rayobject_empty_cost,
- RE_rayobject_empty_hint_bb
-};
-
-static RayObject empty_raytree = { &empty_api, {NULL, NULL} };
-
-RayObject *RE_rayobject_empty_create()
-{
- return RE_rayobject_unalignRayAPI( &empty_raytree );
-}
-
diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h
deleted file mode 100644
index 6eb3c035935..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_hint.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_hint.h
- * \ingroup render
- */
-
-
-#ifndef __RAYOBJECT_HINT_H__
-#define __RAYOBJECT_HINT_H__
-
-#define HINT_RECURSE 1
-#define HINT_ACCEPT 0
-#define HINT_DISCARD -1
-
-struct HintBB {
- float bb[6];
-};
-
-inline int hint_test_bb(HintBB *obj, float *Nmin, float *Nmax)
-{
- if (bb_fits_inside(Nmin, Nmax, obj->bb, obj->bb + 3) )
- return HINT_RECURSE;
- else
- return HINT_ACCEPT;
-}
-#if 0
-struct HintFrustum {
- float co[3];
- float no[4][3];
-};
-
-inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax)
-{
- //if frustum inside BB
- {
- return HINT_RECURSE;
- }
- //if BB outside frustum
- {
- return HINT_DISCARD;
- }
-
- return HINT_ACCEPT;
-}
-#endif
-
-#endif /* __RAYOBJECT_HINT_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
deleted file mode 100644
index 349f0fc6844..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_instance.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-
-#define RE_COST_INSTANCE (1.0f)
-
-static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
-static void RE_rayobject_instance_free(RayObject *o);
-static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
-static float RE_rayobject_instance_cost(RayObject *o);
-
-static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{}
-
-static RayObjectAPI instance_api =
-{
- RE_rayobject_instance_intersect,
- NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
- NULL, //static void RE_rayobject_instance_done(RayObject *o);
- RE_rayobject_instance_free,
- RE_rayobject_instance_bb,
- RE_rayobject_instance_cost,
- RE_rayobject_instance_hint_bb
-};
-
-typedef struct InstanceRayObject {
- RayObject rayobj;
- RayObject *target;
-
- void *ob; //Object represented by this instance
- void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
-
- float global2target[4][4];
- float target2global[4][4];
-
-} InstanceRayObject;
-
-
-RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob)
-{
- InstanceRayObject *obj = (InstanceRayObject *)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
- assert(RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
-
- obj->rayobj.api = &instance_api;
- obj->target = target;
- obj->ob = ob;
- obj->target_ob = target_ob;
-
- copy_m4_m4(obj->target2global, transform);
- invert_m4_m4(obj->global2target, obj->target2global);
-
- return RE_rayobject_unalignRayAPI((RayObject *) obj);
-}
-
-static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- float start[3], dir[3], idot_axis[3], dist;
- int changed = 0, i, res;
-
- // TODO - this is disabling self intersection on instances
- if (isec->orig.ob == obj->ob && obj->ob) {
- changed = 1;
- isec->orig.ob = obj->target_ob;
- }
-
- // backup old values
- copy_v3_v3(start, isec->start);
- copy_v3_v3(dir, isec->dir);
- copy_v3_v3(idot_axis, isec->idot_axis);
- dist = isec->dist;
-
- // transform to target coordinates system
- mul_m4_v3(obj->global2target, isec->start);
- mul_mat3_m4_v3(obj->global2target, isec->dir);
- isec->dist *= normalize_v3(isec->dir);
-
- // update idot_axis and bv_index
- for (i = 0; i < 3; i++) {
- isec->idot_axis[i] = 1.0f / isec->dir[i];
-
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
- // Pre-calculate orientation for watertight intersection checks.
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- // raycast
- res = RE_rayobject_intersect(obj->target, isec);
-
- // map dist into original coordinate space
- if (res == 0) {
- isec->dist = dist;
- }
- else {
- // note we don't just multiply dist, because of possible
- // non-uniform scaling in the transform matrix
- float vec[3];
-
- mul_v3_v3fl(vec, isec->dir, isec->dist);
- mul_mat3_m4_v3(obj->target2global, vec);
-
- isec->dist = len_v3(vec);
- isec->hit.ob = obj->ob;
-
-#ifdef RT_USE_LAST_HIT
- // TODO support for last hit optimization in instances that can jump
- // directly to the last hit face.
- // For now it jumps directly to the last-hit instance root node.
- isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj);
-#endif
- }
-
- // restore values
- copy_v3_v3(isec->start, start);
- copy_v3_v3(isec->dir, dir);
- copy_v3_v3(isec->idot_axis, idot_axis);
-
- if (changed)
- isec->orig.ob = obj->ob;
-
- // restore bv_index
- for (i = 0; i < 3; i++) {
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
- // Pre-calculate orientation for watertight intersection checks.
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- return res;
-}
-
-static void RE_rayobject_instance_free(RayObject *o)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- MEM_freeN(obj);
-}
-
-static float RE_rayobject_instance_cost(RayObject *o)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
-}
-
-static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
-{
- //TODO:
- // *better bb.. calculated without rotations of bb
- // *maybe cache that better-fitted-BB at the InstanceRayObject
- InstanceRayObject *obj = (InstanceRayObject *)o;
-
- float m[3], M[3], t[3];
- int i, j;
- INIT_MINMAX(m, M);
- RE_rayobject_merge_bb(obj->target, m, M);
-
- //There must be a faster way than rotating all the 8 vertexs of the BB
- for (i = 0; i < 8; i++) {
- for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
- mul_m4_v3(obj->target2global, t);
- DO_MINMAX(t, min, max);
- }
-}
-
diff --git a/source/blender/render/intern/raytrace/rayobject_internal.h b/source/blender/render/intern/raytrace/rayobject_internal.h
deleted file mode 100644
index 5b8a43eab03..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_internal.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __RAYOBJECT_INTERNAL_H__
-#define __RAYOBJECT_INTERNAL_H__
-
-/** \file blender/render/intern/raytrace/rayobject_internal.h
- * \ingroup render
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* RayObjectControl
- *
- * This class is intended as a place holder for control, configuration of the
- * rayobject like:
- * - stop building (TODO maybe when porting build to threads this could be
- * implemented with some thread_cancel function)
- * - max number of threads and threads callback to use during build
- * ...
- */
-
-typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data);
-
-typedef struct RayObjectControl {
- void *data;
- RE_rayobjectcontrol_test_break_callback test_break;
-} RayObjectControl;
-
-/* Returns true if for some reason a heavy processing function should stop
- * (eg.: user asked to stop during a tree a build)
- */
-
-int RE_rayobjectcontrol_test_break(RayObjectControl *c);
-
-/* RayObject
- *
- * A ray object is everything where we can cast rays like:
- * * a face/triangle
- * * an octree
- * * a bvh tree
- * * an octree of bvh's
- * * a bvh of bvh's
- *
- *
- * All types of RayObjects can be created by implementing the
- * callbacks of the RayObject.
- *
- * Due to high computing time evolved with casting on faces
- * there is a special type of RayObject (named RayFace)
- * which won't use callbacks like other generic nodes.
- *
- * In order to allow a mixture of RayFace+RayObjects,
- * all RayObjects must be 4byte aligned, allowing us to use the
- * 2 least significant bits (with the mask 0x03) to define the
- * type of RayObject.
- *
- * This leads to 4 possible types of RayObject:
- *
- * addr&3 - type of object
- * 0 Self (reserved for each structure)
- * 1 RayFace (tri/quad primitive)
- * 2 RayObject (generic with API callbacks)
- * 3 VlakPrimitive
- * (vlak primitive - to be used when we have a vlak describing the data
- * eg.: on render code)
- *
- * 0 means it's reserved and has it own meaning inside each ray acceleration structure
- * (this way each structure can use the align offset to determine if a node represents a
- * RayObject primitive, which can be used to save memory)
- */
-
-/* used to test the type of ray object */
-#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0)
-#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1)
-#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2)
-#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3)
-
-/* used to align a given ray object */
-#define RE_rayobject_align(o) ((RayObject *)(((intptr_t)o)&(~3)))
-
-/* used to unalign a given ray object */
-#define RE_rayobject_unalignRayFace(o) ((RayObject *)(((intptr_t)o)|1))
-#define RE_rayobject_unalignRayAPI(o) ((RayObject *)(((intptr_t)o)|2))
-#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject *)(((intptr_t)o)|3))
-
-/*
- * This rayobject represents a generic object. With it's own callbacks for raytrace operations.
- * It's suitable to implement things like LOD.
- */
-
-struct RayObject {
- struct RayObjectAPI *api;
- struct RayObjectControl control;
-};
-
-typedef int (*RE_rayobject_raycast_callback)(RayObject *, struct Isect *);
-typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject);
-typedef void (*RE_rayobject_done_callback)(RayObject *);
-typedef void (*RE_rayobject_free_callback)(RayObject *);
-typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float min[3], float max[3]);
-typedef float (*RE_rayobject_cost_callback)(RayObject *);
-typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, struct RayHint *, float min[3], float max[3]);
-
-typedef struct RayObjectAPI {
- RE_rayobject_raycast_callback raycast;
- RE_rayobject_add_callback add;
- RE_rayobject_done_callback done;
- RE_rayobject_free_callback free;
- RE_rayobject_merge_bb_callback bb;
- RE_rayobject_cost_callback cost;
- RE_rayobject_hint_bb_callback hint_bb;
-} RayObjectAPI;
-
-/*
- * Returns the expected cost of raycast on this node, primitives have a cost of 1
- */
-float RE_rayobject_cost(RayObject *r);
-
-/*
- * This function differs from RE_rayobject_raycast
- * RE_rayobject_intersect does NOT perform last-hit optimization
- * So this is probably a function to call inside raytrace structures
- */
-int RE_rayobject_intersect(RayObject *r, struct Isect *i);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYOBJECT_INTERNAL_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp
deleted file mode 100644
index b21197e728d..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_octree.cpp
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_octree.cpp
- * \ingroup render
- */
-
-
-/* IMPORTANT NOTE: this code must be independent of any other render code
- * to use it outside the renderer! */
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <float.h>
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-
-/* ********** structs *************** */
-#define BRANCH_ARRAY 1024
-#define NODE_ARRAY 4096
-
-typedef struct Branch {
- struct Branch *b[8];
-} Branch;
-
-typedef struct OcVal {
- short ocx, ocy, ocz;
-} OcVal;
-
-typedef struct Node {
- struct RayFace *v[8];
- struct OcVal ov[8];
- struct Node *next;
-} Node;
-
-typedef struct Octree {
- RayObject rayobj;
-
- struct Branch **adrbranch;
- struct Node **adrnode;
- float ocsize; /* ocsize: mult factor, max size octree */
- float ocfacx, ocfacy, ocfacz;
- float min[3], max[3];
- int ocres;
- int branchcount, nodecount;
-
- /* during building only */
- char *ocface;
-
- RayFace **ro_nodes;
- int ro_nodes_size, ro_nodes_used;
-
-} Octree;
-
-static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec);
-static void RE_rayobject_octree_add(RayObject *o, RayObject *ob);
-static void RE_rayobject_octree_done(RayObject *o);
-static void RE_rayobject_octree_free(RayObject *o);
-static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max);
-
-/*
- * This function is not expected to be called by current code state.
- */
-static float RE_rayobject_octree_cost(RayObject *UNUSED(o))
-{
- return 1.0;
-}
-
-static void RE_rayobject_octree_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{
- return;
-}
-
-static RayObjectAPI octree_api =
-{
- RE_rayobject_octree_intersect,
- RE_rayobject_octree_add,
- RE_rayobject_octree_done,
- RE_rayobject_octree_free,
- RE_rayobject_octree_bb,
- RE_rayobject_octree_cost,
- RE_rayobject_octree_hint_bb
-};
-
-/* **************** ocval method ******************* */
-/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
-
-#define OCVALRES 15
-#define BROW16(min, max) \
- (((max) >= OCVALRES ? 0xFFFF : (1 << ((max) + 1)) - 1) - (((min) > 0) ? ((1 << (min)) - 1) : 0))
-
-static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
-{
- float min[3], max[3];
- int ocmin, ocmax;
-
- copy_v3_v3(min, v1);
- copy_v3_v3(max, v1);
- DO_MINMAX(v2, min, max);
- DO_MINMAX(v3, min, max);
- if (v4) {
- DO_MINMAX(v4, min, max);
- }
-
- ocmin = OCVALRES * (min[0] - x);
- ocmax = OCVALRES * (max[0] - x);
- ov->ocx = BROW16(ocmin, ocmax);
-
- ocmin = OCVALRES * (min[1] - y);
- ocmax = OCVALRES * (max[1] - y);
- ov->ocy = BROW16(ocmin, ocmax);
-
- ocmin = OCVALRES * (min[2] - z);
- ocmax = OCVALRES * (max[2] - z);
- ov->ocz = BROW16(ocmin, ocmax);
-
-}
-
-static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2)
-{
- int ocmin, ocmax;
-
- if (vec1[0] < vec2[0]) {
- ocmin = OCVALRES * (vec1[0] - xo);
- ocmax = OCVALRES * (vec2[0] - xo);
- }
- else {
- ocmin = OCVALRES * (vec2[0] - xo);
- ocmax = OCVALRES * (vec1[0] - xo);
- }
- ov->ocx = BROW16(ocmin, ocmax);
-
- if (vec1[1] < vec2[1]) {
- ocmin = OCVALRES * (vec1[1] - yo);
- ocmax = OCVALRES * (vec2[1] - yo);
- }
- else {
- ocmin = OCVALRES * (vec2[1] - yo);
- ocmax = OCVALRES * (vec1[1] - yo);
- }
- ov->ocy = BROW16(ocmin, ocmax);
-
- if (vec1[2] < vec2[2]) {
- ocmin = OCVALRES * (vec1[2] - zo);
- ocmax = OCVALRES * (vec2[2] - zo);
- }
- else {
- ocmin = OCVALRES * (vec2[2] - zo);
- ocmax = OCVALRES * (vec1[2] - zo);
- }
- ov->ocz = BROW16(ocmin, ocmax);
-}
-
-/* ************* octree ************** */
-
-static Branch *addbranch(Octree *oc, Branch *br, short ocb)
-{
- int index;
-
- if (br->b[ocb]) return br->b[ocb];
-
- oc->branchcount++;
- index = oc->branchcount >> 12;
-
- if (oc->adrbranch[index] == NULL)
- oc->adrbranch[index] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "new oc branch");
-
- if (oc->branchcount >= BRANCH_ARRAY * 4096) {
- printf("error; octree branches full\n");
- oc->branchcount = 0;
- }
-
- return br->b[ocb] = oc->adrbranch[index] + (oc->branchcount & 4095);
-}
-
-static Node *addnode(Octree *oc)
-{
- int index;
-
- oc->nodecount++;
- index = oc->nodecount >> 12;
-
- if (oc->adrnode[index] == NULL)
- oc->adrnode[index] = (Node *)MEM_callocN(4096 * sizeof(Node), "addnode");
-
- if (oc->nodecount > NODE_ARRAY * NODE_ARRAY) {
- printf("error; octree nodes full\n");
- oc->nodecount = 0;
- }
-
- return oc->adrnode[index] + (oc->nodecount & 4095);
-}
-
-static bool face_in_node(RayFace *face, short x, short y, short z, float rtf[4][3])
-{
- static float nor[3], d;
- float fx, fy, fz;
-
- // init static vars
- if (face) {
- normal_tri_v3(nor, rtf[0], rtf[1], rtf[2]);
- d = -nor[0] * rtf[0][0] - nor[1] * rtf[0][1] - nor[2] * rtf[0][2];
- return 0;
- }
-
- fx = x;
- fy = y;
- fz = z;
-
- if ((fx) * nor[0] + (fy) * nor[1] + (fz) * nor[2] + d > 0.0f) {
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
-
- if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- }
- else {
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
-
- if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- }
-
- return 0;
-}
-
-static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[4][3])
-{
- Branch *br;
- Node *no;
- short a, oc0, oc1, oc2, oc3, oc4, oc5;
-
- x <<= 2;
- y <<= 1;
-
- br = oc->adrbranch[0];
-
- if (oc->ocres == 512) {
- oc0 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
- br = addbranch(oc, br, oc0);
- }
- if (oc->ocres >= 256) {
- oc0 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
- br = addbranch(oc, br, oc0);
- }
- if (oc->ocres >= 128) {
- oc0 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
- br = addbranch(oc, br, oc0);
- }
-
- oc0 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
- oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
- oc2 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
- oc3 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
- oc4 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
- oc5 = ((x & 4) + (y & 2) + (z & 1));
-
- br = addbranch(oc, br, oc0);
- br = addbranch(oc, br, oc1);
- br = addbranch(oc, br, oc2);
- br = addbranch(oc, br, oc3);
- br = addbranch(oc, br, oc4);
- no = (Node *)br->b[oc5];
- if (no == NULL) br->b[oc5] = (Branch *)(no = addnode(oc));
-
- while (no->next) no = no->next;
-
- a = 0;
- if (no->v[7]) { /* node full */
- no->next = addnode(oc);
- no = no->next;
- }
- else {
- while (no->v[a] != NULL) a++;
- }
-
- no->v[a] = (RayFace *) RE_rayobject_align(face);
-
- if (quad)
- calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x >> 2, y >> 1, z, &no->ov[a]);
- else
- calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x >> 2, y >> 1, z, &no->ov[a]);
-}
-
-static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[4][3], float rtf[4][3])
-{
- int ocx1, ocx2, ocy1, ocy2;
- int x, y, dx = 0, dy = 0;
- float ox1, ox2, oy1, oy2;
- float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
-
- ocx1 = rts[b1][c1];
- ocy1 = rts[b1][c2];
- ocx2 = rts[b2][c1];
- ocy2 = rts[b2][c2];
-
- if (ocx1 == ocx2 && ocy1 == ocy2) {
- ocface[oc->ocres * ocx1 + ocy1] = 1;
- return;
- }
-
- ox1 = rtf[b1][c1];
- oy1 = rtf[b1][c2];
- ox2 = rtf[b2][c1];
- oy2 = rtf[b2][c2];
-
- if (ox1 != ox2) {
- if (ox2 - ox1 > 0.0f) {
- lambda_x = (ox1 - ocx1 - 1.0f) / (ox1 - ox2);
- ldx = -1.0f / (ox1 - ox2);
- dx = 1;
- }
- else {
- lambda_x = (ox1 - ocx1) / (ox1 - ox2);
- ldx = 1.0f / (ox1 - ox2);
- dx = -1;
- }
- }
- else {
- lambda_x = 1.0f;
- ldx = 0;
- }
-
- if (oy1 != oy2) {
- if (oy2 - oy1 > 0.0f) {
- lambda_y = (oy1 - ocy1 - 1.0f) / (oy1 - oy2);
- ldy = -1.0f / (oy1 - oy2);
- dy = 1;
- }
- else {
- lambda_y = (oy1 - ocy1) / (oy1 - oy2);
- ldy = 1.0f / (oy1 - oy2);
- dy = -1;
- }
- }
- else {
- lambda_y = 1.0f;
- ldy = 0;
- }
-
- x = ocx1; y = ocy1;
- lambda = MIN2(lambda_x, lambda_y);
-
- while (true) {
-
- if (x < 0 || y < 0 || x >= oc->ocres || y >= oc->ocres) {
- /* pass*/
- }
- else {
- ocface[oc->ocres * x + y] = 1;
- }
-
- lambda_o = lambda;
- if (lambda_x == lambda_y) {
- lambda_x += ldx;
- x += dx;
- lambda_y += ldy;
- y += dy;
- }
- else {
- if (lambda_x < lambda_y) {
- lambda_x += ldx;
- x += dx;
- }
- else {
- lambda_y += ldy;
- y += dy;
- }
- }
- lambda = MIN2(lambda_x, lambda_y);
- if (lambda == lambda_o) break;
- if (lambda >= 1.0f) break;
- }
- ocface[oc->ocres * ocx2 + ocy2] = 1;
-}
-
-static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax)
-{
- int a, x, y, y1, y2;
-
- for (x = ocmin[c1]; x <= ocmax[c1]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[c2]; y <= ocmax[c2]; y++) {
- if (ocface[a + y]) {
- y++;
- while (ocface[a + y] && y != ocmax[c2]) y++;
- for (y1 = ocmax[c2]; y1 > y; y1--) {
- if (ocface[a + y1]) {
- for (y2 = y; y2 <= y1; y2++) ocface[a + y2] = 1;
- y1 = 0;
- }
- }
- y = ocmax[c2];
- }
- }
- }
-}
-
-static void RE_rayobject_octree_free(RayObject *tree)
-{
- Octree *oc = (Octree *)tree;
-
-#if 0
- printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount);
- printf("raycount %d\n", raycount);
- printf("ray coherent %d\n", coherent_ray);
- printf("accepted %d rejected %d\n", accepted, rejected);
-#endif
- if (oc->ocface)
- MEM_freeN(oc->ocface);
-
- if (oc->adrbranch) {
- int a = 0;
- while (oc->adrbranch[a]) {
- MEM_freeN(oc->adrbranch[a]);
- oc->adrbranch[a] = NULL;
- a++;
- }
- MEM_freeN(oc->adrbranch);
- oc->adrbranch = NULL;
- }
- oc->branchcount = 0;
-
- if (oc->adrnode) {
- int a = 0;
- while (oc->adrnode[a]) {
- MEM_freeN(oc->adrnode[a]);
- oc->adrnode[a] = NULL;
- a++;
- }
- MEM_freeN(oc->adrnode);
- oc->adrnode = NULL;
- }
- oc->nodecount = 0;
-
- MEM_freeN(oc);
-}
-
-
-RayObject *RE_rayobject_octree_create(int ocres, int size)
-{
- Octree *oc = (Octree *)MEM_callocN(sizeof(Octree), "Octree");
- assert(RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */
-
- oc->rayobj.api = &octree_api;
-
- oc->ocres = ocres;
-
- oc->ro_nodes = (RayFace **)MEM_callocN(sizeof(RayFace *) * size, "octree rayobject nodes");
- oc->ro_nodes_size = size;
- oc->ro_nodes_used = 0;
-
-
- return RE_rayobject_unalignRayAPI((RayObject *) oc);
-}
-
-
-static void RE_rayobject_octree_add(RayObject *tree, RayObject *node)
-{
- Octree *oc = (Octree *)tree;
-
- assert(RE_rayobject_isRayFace(node) );
- assert(oc->ro_nodes_used < oc->ro_nodes_size);
- oc->ro_nodes[oc->ro_nodes_used++] = (RayFace *)RE_rayobject_align(node);
-}
-
-static void octree_fill_rayface(Octree *oc, RayFace *face)
-{
- float ocfac[3], rtf[4][3];
- float co1[3], co2[3], co3[3], co4[3];
- short rts[4][3];
- short ocmin[3], ocmax[3];
- char *ocface = oc->ocface; // front, top, size view of face, to fill in
- int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
-
- ocfac[0] = oc->ocfacx;
- ocfac[1] = oc->ocfacy;
- ocfac[2] = oc->ocfacz;
-
- ocres2 = oc->ocres * oc->ocres;
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
- if (RE_rayface_isQuad(face))
- copy_v3_v3(co4, face->v4);
-
- for (c = 0; c < 3; c++) {
- rtf[0][c] = (co1[c] - oc->min[c]) * ocfac[c];
- rts[0][c] = (short)rtf[0][c];
- rtf[1][c] = (co2[c] - oc->min[c]) * ocfac[c];
- rts[1][c] = (short)rtf[1][c];
- rtf[2][c] = (co3[c] - oc->min[c]) * ocfac[c];
- rts[2][c] = (short)rtf[2][c];
- if (RE_rayface_isQuad(face)) {
- rtf[3][c] = (co4[c] - oc->min[c]) * ocfac[c];
- rts[3][c] = (short)rtf[3][c];
- }
- }
-
- for (c = 0; c < 3; c++) {
- oc1 = rts[0][c];
- oc2 = rts[1][c];
- oc3 = rts[2][c];
- if (!RE_rayface_isQuad(face)) {
- ocmin[c] = min_iii(oc1, oc2, oc3);
- ocmax[c] = max_iii(oc1, oc2, oc3);
- }
- else {
- oc4 = rts[3][c];
- ocmin[c] = min_iiii(oc1, oc2, oc3, oc4);
- ocmax[c] = max_iiii(oc1, oc2, oc3, oc4);
- }
- if (ocmax[c] > oc->ocres - 1) ocmax[c] = oc->ocres - 1;
- if (ocmin[c] < 0) ocmin[c] = 0;
- }
-
- if (ocmin[0] == ocmax[0] && ocmin[1] == ocmax[1] && ocmin[2] == ocmax[2]) {
- ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf);
- }
- else {
-
- d2dda(oc, 0, 1, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 0, 1, 0, 2, ocface, rts, rtf);
- d2dda(oc, 0, 1, 1, 2, ocface + 2 * ocres2, rts, rtf);
- d2dda(oc, 1, 2, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 1, 2, 0, 2, ocface, rts, rtf);
- d2dda(oc, 1, 2, 1, 2, ocface + 2 * ocres2, rts, rtf);
- if (!RE_rayface_isQuad(face)) {
- d2dda(oc, 2, 0, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 2, 0, 0, 2, ocface, rts, rtf);
- d2dda(oc, 2, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
- }
- else {
- d2dda(oc, 2, 3, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 2, 3, 0, 2, ocface, rts, rtf);
- d2dda(oc, 2, 3, 1, 2, ocface + 2 * ocres2, rts, rtf);
- d2dda(oc, 3, 0, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 3, 0, 0, 2, ocface, rts, rtf);
- d2dda(oc, 3, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
- }
- /* nothing todo with triangle..., just fills :) */
- filltriangle(oc, 0, 1, ocface + ocres2, ocmin, ocmax);
- filltriangle(oc, 0, 2, ocface, ocmin, ocmax);
- filltriangle(oc, 1, 2, ocface + 2 * ocres2, ocmin, ocmax);
-
- /* init static vars here */
- face_in_node(face, 0, 0, 0, rtf);
-
- for (x = ocmin[0]; x <= ocmax[0]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[1]; y <= ocmax[1]; y++) {
- if (ocface[a + y + ocres2]) {
- b = oc->ocres * y + 2 * ocres2;
- for (z = ocmin[2]; z <= ocmax[2]; z++) {
- if (ocface[b + z] && ocface[a + z]) {
- if (face_in_node(NULL, x, y, z, rtf))
- ocwrite(oc, face, RE_rayface_isQuad(face), x, y, z, rtf);
- }
- }
- }
- }
- }
-
- /* same loops to clear octree, doubt it can be done smarter */
- for (x = ocmin[0]; x <= ocmax[0]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[1]; y <= ocmax[1]; y++) {
- /* x-y */
- ocface[a + y + ocres2] = 0;
-
- b = oc->ocres * y + 2 * ocres2;
- for (z = ocmin[2]; z <= ocmax[2]; z++) {
- /* y-z */
- ocface[b + z] = 0;
- /* x-z */
- ocface[a + z] = 0;
- }
- }
- }
- }
-}
-
-static void RE_rayobject_octree_done(RayObject *tree)
-{
- Octree *oc = (Octree *)tree;
- int c;
- float t00, t01, t02;
- int ocres2 = oc->ocres * oc->ocres;
-
- INIT_MINMAX(oc->min, oc->max);
-
- /* Calculate Bounding Box */
- for (c = 0; c < oc->ro_nodes_used; c++)
- RE_rayobject_merge_bb(RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max);
-
- /* Alloc memory */
- oc->adrbranch = (Branch **)MEM_callocN(sizeof(void *) * BRANCH_ARRAY, "octree branches");
- oc->adrnode = (Node **)MEM_callocN(sizeof(void *) * NODE_ARRAY, "octree nodes");
-
- oc->adrbranch[0] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "makeoctree");
-
- /* the lookup table, per face, for which nodes to fill in */
- oc->ocface = (char *)MEM_callocN(3 * ocres2 + 8, "ocface");
- memset(oc->ocface, 0, 3 * ocres2);
-
- for (c = 0; c < 3; c++) { /* octree enlarge, still needed? */
- oc->min[c] -= 0.01f;
- oc->max[c] += 0.01f;
- }
-
- t00 = oc->max[0] - oc->min[0];
- t01 = oc->max[1] - oc->min[1];
- t02 = oc->max[2] - oc->min[2];
-
- /* this minus 0.1 is old safety... seems to be needed? */
- oc->ocfacx = (oc->ocres - 0.1f) / t00;
- oc->ocfacy = (oc->ocres - 0.1f) / t01;
- oc->ocfacz = (oc->ocres - 0.1f) / t02;
-
- oc->ocsize = sqrtf(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */
-
- for (c = 0; c < oc->ro_nodes_used; c++) {
- octree_fill_rayface(oc, oc->ro_nodes[c]);
- }
-
- MEM_freeN(oc->ocface);
- oc->ocface = NULL;
- MEM_freeN(oc->ro_nodes);
- oc->ro_nodes = NULL;
-
-#if 0
- printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx);
- printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy);
- printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz);
-#endif
-}
-
-static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max)
-{
- Octree *oc = (Octree *)tree;
- DO_MINMAX(oc->min, min, max);
- DO_MINMAX(oc->max, min, max);
-}
-
-/* check all faces in this node */
-static int testnode(Octree *UNUSED(oc), Isect *is, Node *no, OcVal ocval)
-{
- short nr = 0;
-
- /* return on any first hit */
- if (is->mode == RE_RAY_SHADOW) {
-
- for (; no; no = no->next) {
- for (nr = 0; nr < 8; nr++) {
- RayFace *face = no->v[nr];
- OcVal *ov = no->ov + nr;
-
- if (!face) break;
-
- if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
- if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) )
- return 1;
- }
- }
- }
- }
- else {
- /* else mirror or glass or shadowtra, return closest face */
- int found = 0;
-
- for (; no; no = no->next) {
- for (nr = 0; nr < 8; nr++) {
- RayFace *face = no->v[nr];
- OcVal *ov = no->ov + nr;
-
- if (!face) break;
-
- if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
- if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) ) {
- found = 1;
- }
- }
- }
- }
-
- return found;
- }
-
- return 0;
-}
-
-/* find the Node for the octree coord x y z */
-static Node *ocread(Octree *oc, int x, int y, int z)
-{
- Branch *br;
- int oc1;
-
- x <<= 2;
- y <<= 1;
-
- br = oc->adrbranch[0];
-
- if (oc->ocres == 512) {
- oc1 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
- if (oc->ocres >= 256) {
- oc1 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
- if (oc->ocres >= 128) {
- oc1 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
-
- oc1 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 4) + (y & 2) + (z & 1));
- return (Node *)br->b[oc1];
- }
- }
- }
- }
- }
-
- return NULL;
-}
-
-static int cliptest(float p, float q, float *u1, float *u2)
-{
- float r;
-
- if (p < 0.0f) {
- if (q < p) return 0;
- else if (q < 0.0f) {
- r = q / p;
- if (r > *u2) return 0;
- else if (r > *u1) *u1 = r;
- }
- }
- else {
- if (p > 0.0f) {
- if (q < 0.0f) return 0;
- else if (q < p) {
- r = q / p;
- if (r < *u1) return 0;
- else if (r < *u2) *u2 = r;
- }
- }
- else if (q < 0.0f) return 0;
- }
- return 1;
-}
-
-/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we
- * need better methods, sample code commented out below (ton) */
-
-#if 0
-
-in top : static int coh_nodes[16 * 16 * 16][6];
-in makeoctree : memset(coh_nodes, 0, sizeof(coh_nodes));
-
-static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
-{
- short *sp;
-
- sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
- sp[0] = ocx1; sp[1] = ocy1; sp[2] = ocz1;
- sp[3] = ocx2; sp[4] = ocy2; sp[5] = ocz2;
-
-}
-
-static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
-{
- short *sp;
-
- sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
- if (sp[0] == ocx1 && sp[1] == ocy1 && sp[2] == ocz1 &&
- sp[3] == ocx2 && sp[4] == ocy2 && sp[5] == ocz2) return 1;
- return 0;
-}
-
-#endif
-
-/* return 1: found valid intersection */
-/* starts with is->orig.face */
-static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
-{
- Octree *oc = (Octree *)tree;
- Node *no;
- OcVal ocval;
- float vec1[3], vec2[3], start[3], end[3];
- float u1, u2, ox1, ox2, oy1, oy2, oz1, oz2;
- float lambda_o, lambda_x, ldx, lambda_y, ldy, lambda_z, ldz, dda_lambda;
- float o_lambda = 0;
- int dx, dy, dz;
- int xo, yo, zo, c1 = 0;
- int ocx1, ocx2, ocy1, ocy2, ocz1, ocz2;
-
- /* clip with octree */
- if (oc->branchcount == 0) return 0;
-
- /* do this before intersect calls */
-#if 0
- is->facecontr = NULL; /* to check shared edge */
- is->obcontr = 0;
- is->faceisect = is->isect = 0; /* shared edge, quad half flag */
- is->userdata = oc->userdata;
-#endif
-
- copy_v3_v3(start, is->start);
- madd_v3_v3v3fl(end, is->start, is->dir, is->dist);
- ldx = is->dir[0] * is->dist;
- o_lambda = is->dist;
- u1 = 0.0f;
- u2 = 1.0f;
-
- /* clip with octree cube */
- if (cliptest(-ldx, start[0] - oc->min[0], &u1, &u2)) {
- if (cliptest(ldx, oc->max[0] - start[0], &u1, &u2)) {
- ldy = is->dir[1] * is->dist;
- if (cliptest(-ldy, start[1] - oc->min[1], &u1, &u2)) {
- if (cliptest(ldy, oc->max[1] - start[1], &u1, &u2)) {
- ldz = is->dir[2] * is->dist;
- if (cliptest(-ldz, start[2] - oc->min[2], &u1, &u2)) {
- if (cliptest(ldz, oc->max[2] - start[2], &u1, &u2)) {
- c1 = 1;
- if (u2 < 1.0f) {
- end[0] = start[0] + u2 * ldx;
- end[1] = start[1] + u2 * ldy;
- end[2] = start[2] + u2 * ldz;
- }
-
- if (u1 > 0.0f) {
- start[0] += u1 * ldx;
- start[1] += u1 * ldy;
- start[2] += u1 * ldz;
- }
- }
- }
- }
- }
- }
- }
-
- if (c1 == 0) return 0;
-
- /* reset static variables in ocread */
- //ocread(oc, oc->ocres, 0, 0);
-
- /* setup 3dda to traverse octree */
- ox1 = (start[0] - oc->min[0]) * oc->ocfacx;
- oy1 = (start[1] - oc->min[1]) * oc->ocfacy;
- oz1 = (start[2] - oc->min[2]) * oc->ocfacz;
- ox2 = (end[0] - oc->min[0]) * oc->ocfacx;
- oy2 = (end[1] - oc->min[1]) * oc->ocfacy;
- oz2 = (end[2] - oc->min[2]) * oc->ocfacz;
-
- ocx1 = (int)ox1;
- ocy1 = (int)oy1;
- ocz1 = (int)oz1;
- ocx2 = (int)ox2;
- ocy2 = (int)oy2;
- ocz2 = (int)oz2;
-
- if (ocx1 == ocx2 && ocy1 == ocy2 && ocz1 == ocz2) {
- no = ocread(oc, ocx1, ocy1, ocz1);
- if (no) {
- /* exact intersection with node */
- vec1[0] = ox1; vec1[1] = oy1; vec1[2] = oz1;
- vec2[0] = ox2; vec2[1] = oy2; vec2[2] = oz2;
- calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
- if (testnode(oc, is, no, ocval) ) return 1;
- }
- }
- else {
- int found = 0;
- //static int coh_ocx1, coh_ocx2, coh_ocy1, coh_ocy2, coh_ocz1, coh_ocz2;
- float dox, doy, doz;
- int eqval;
-
- /* calc lambda en ld */
- dox = ox1 - ox2;
- doy = oy1 - oy2;
- doz = oz1 - oz2;
-
- if (dox < -FLT_EPSILON) {
- ldx = -1.0f / dox;
- lambda_x = (ocx1 - ox1 + 1.0f) * ldx;
- dx = 1;
- }
- else if (dox > FLT_EPSILON) {
- ldx = 1.0f / dox;
- lambda_x = (ox1 - ocx1) * ldx;
- dx = -1;
- }
- else {
- lambda_x = 1.0f;
- ldx = 0;
- dx = 0;
- }
-
- if (doy < -FLT_EPSILON) {
- ldy = -1.0f / doy;
- lambda_y = (ocy1 - oy1 + 1.0f) * ldy;
- dy = 1;
- }
- else if (doy > FLT_EPSILON) {
- ldy = 1.0f / doy;
- lambda_y = (oy1 - ocy1) * ldy;
- dy = -1;
- }
- else {
- lambda_y = 1.0f;
- ldy = 0;
- dy = 0;
- }
-
- if (doz < -FLT_EPSILON) {
- ldz = -1.0f / doz;
- lambda_z = (ocz1 - oz1 + 1.0f) * ldz;
- dz = 1;
- }
- else if (doz > FLT_EPSILON) {
- ldz = 1.0f / doz;
- lambda_z = (oz1 - ocz1) * ldz;
- dz = -1;
- }
- else {
- lambda_z = 1.0f;
- ldz = 0;
- dz = 0;
- }
-
- xo = ocx1; yo = ocy1; zo = ocz1;
- dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
-
- vec2[0] = ox1;
- vec2[1] = oy1;
- vec2[2] = oz1;
-
- /* this loop has been constructed to make sure the first and last node of ray
- * are always included, even when dda_lambda==1.0f or larger */
-
- while (true) {
-
- no = ocread(oc, xo, yo, zo);
- if (no) {
-
- /* calculate ray intersection with octree node */
- copy_v3_v3(vec1, vec2);
- // dox, y, z is negative
- vec2[0] = ox1 - dda_lambda * dox;
- vec2[1] = oy1 - dda_lambda * doy;
- vec2[2] = oz1 - dda_lambda * doz;
- calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
-
- //is->dist = (u1 + dda_lambda * (u2 - u1)) * o_lambda;
- if (testnode(oc, is, no, ocval) )
- found = 1;
-
- if (is->dist < (u1 + dda_lambda * (u2 - u1)) * o_lambda)
- return found;
- }
-
-
- lambda_o = dda_lambda;
-
- /* traversing octree nodes need careful detection of smallest values, with proper
- * exceptions for equal lambdas */
- eqval = (lambda_x == lambda_y);
- if (lambda_y == lambda_z) eqval += 2;
- if (lambda_x == lambda_z) eqval += 4;
-
- if (eqval) { // only 4 cases exist!
- if (eqval == 7) { // x=y=z
- xo += dx; lambda_x += ldx;
- yo += dy; lambda_y += ldy;
- zo += dz; lambda_z += ldz;
- }
- else if (eqval == 1) { // x=y
- if (lambda_y < lambda_z) {
- xo += dx; lambda_x += ldx;
- yo += dy; lambda_y += ldy;
- }
- else {
- zo += dz; lambda_z += ldz;
- }
- }
- else if (eqval == 2) { // y=z
- if (lambda_x < lambda_y) {
- xo += dx; lambda_x += ldx;
- }
- else {
- yo += dy; lambda_y += ldy;
- zo += dz; lambda_z += ldz;
- }
- }
- else { // x=z
- if (lambda_y < lambda_x) {
- yo += dy; lambda_y += ldy;
- }
- else {
- xo += dx; lambda_x += ldx;
- zo += dz; lambda_z += ldz;
- }
- }
- }
- else { // all three different, just three cases exist
- eqval = (lambda_x < lambda_y);
- if (lambda_y < lambda_z) eqval += 2;
- if (lambda_x < lambda_z) eqval += 4;
-
- if (eqval == 7 || eqval == 5) { // x smallest
- xo += dx; lambda_x += ldx;
- }
- else if (eqval == 2 || eqval == 6) { // y smallest
- yo += dy; lambda_y += ldy;
- }
- else { // z smallest
- zo += dz; lambda_z += ldz;
- }
-
- }
-
- dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
- if (dda_lambda == lambda_o) break;
- /* to make sure the last node is always checked */
- if (lambda_o >= 1.0f) break;
- }
- }
-
- /* reached end, no intersections found */
- return 0;
-}
-
-
-
diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
deleted file mode 100644
index 5b90ae77732..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_qbvh.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "vbvh.h"
-#include "svbvh.h"
-#include "reorganize.h"
-
-#ifdef __SSE__
-
-#define DFS_STACK_SIZE 256
-
-struct QBVHTree {
- RayObject rayobj;
-
- SVBVHNode *root;
- MemArena *node_arena;
-
- float cost;
- RTBuilder *builder;
-};
-
-
-template<>
-void bvh_done<QBVHTree>(QBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena 2");
- BLI_memarena_use_malloc(arena2);
- BLI_memarena_use_align(arena2, 16);
-
- //Build and optimize the tree
- //TODO do this in 1 pass (half memory usage during building)
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- if (root) {
- pushup_simd<VBVHNode, 4>(root);
- obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
- }
- else
- obj->root = NULL;
-
- //Free data
- BLI_memarena_free(arena1);
-
- obj->node_arena = arena2;
- obj->cost = 1.0;
-
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-}
-
-template<int StackSize>
-static int intersect(QBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
- else
- return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect((RayObject *)obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return NULL;
-}
-
-RayObject *RE_rayobject_qbvh_create(int size)
-{
- return bvh_create_tree<QBVHTree, DFS_STACK_SIZE>(size);
-}
-
-#else
-
-RayObject *RE_rayobject_qbvh_create(int UNUSED(size))
-{
- puts("WARNING: SSE disabled at compile time\n");
- return NULL;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
deleted file mode 100644
index 5335bf50cbc..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_raycounter.cpp
- * \ingroup render
- */
-
-
-#include "rayobject.h"
-#include "raycounter.h"
-
-#ifdef RE_RAYCOUNTER
-
-void RE_RC_INFO(RayCounter *info)
-{
- printf("----------- Raycast counter --------\n");
- printf("Rays total: %llu\n", info->raycast.test );
- printf("Rays hit: %llu\n", info->raycast.hit );
- printf("\n");
- printf("BB tests: %llu\n", info->bb.test );
- printf("BB hits: %llu\n", info->bb.hit );
- printf("\n");
- printf("SIMD BB tests: %llu\n", info->simd_bb.test );
- printf("SIMD BB hits: %llu\n", info->simd_bb.hit );
- printf("\n");
- printf("Primitives tests: %llu\n", info->faces.test );
- printf("Primitives hits: %llu\n", info->faces.hit );
- printf("------------------------------------\n");
- printf("Shadow last-hit tests per ray: %f\n", info->rayshadow_last_hit.test / ((float)info->raycast.test) );
- printf("Shadow last-hit hits per ray: %f\n", info->rayshadow_last_hit.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("Hint tests per ray: %f\n", info->raytrace_hint.test / ((float)info->raycast.test) );
- printf("Hint hits per ray: %f\n", info->raytrace_hint.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("BB tests per ray: %f\n", info->bb.test / ((float)info->raycast.test) );
- printf("BB hits per ray: %f\n", info->bb.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("SIMD tests per ray: %f\n", info->simd_bb.test / ((float)info->raycast.test) );
- printf("SIMD hits per ray: %f\n", info->simd_bb.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("Primitives tests per ray: %f\n", info->faces.test / ((float)info->raycast.test) );
- printf("Primitives hits per ray: %f\n", info->faces.hit / ((float)info->raycast.test) );
- printf("------------------------------------\n");
-}
-
-void RE_RC_MERGE(RayCounter *dest, RayCounter *tmp)
-{
- dest->faces.test += tmp->faces.test;
- dest->faces.hit += tmp->faces.hit;
-
- dest->bb.test += tmp->bb.test;
- dest->bb.hit += tmp->bb.hit;
-
- dest->simd_bb.test += tmp->simd_bb.test;
- dest->simd_bb.hit += tmp->simd_bb.hit;
-
- dest->raycast.test += tmp->raycast.test;
- dest->raycast.hit += tmp->raycast.hit;
-
- dest->rayshadow_last_hit.test += tmp->rayshadow_last_hit.test;
- dest->rayshadow_last_hit.hit += tmp->rayshadow_last_hit.hit;
-
- dest->raytrace_hint.test += tmp->raytrace_hint.test;
- dest->raytrace_hint.hit += tmp->raytrace_hint.hit;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
deleted file mode 100644
index 103fa3e6034..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_rtbuild.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-#include <stdlib.h>
-#include <algorithm>
-
-#if __cplusplus >= 201103L
-#include <cmath>
-using std::isfinite;
-#else
-#include <math.h>
-#endif
-
-#include "rayobject_rtbuild.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-static bool selected_node(RTBuilder::Object *node)
-{
- return node->selected;
-}
-
-static void rtbuild_init(RTBuilder *b)
-{
- b->split_axis = -1;
- b->primitives.begin = NULL;
- b->primitives.end = NULL;
- b->primitives.maxsize = 0;
- b->depth = 0;
-
- for (int i = 0; i < RTBUILD_MAX_CHILDS; i++)
- b->child_offset[i] = 0;
-
- for (int i = 0; i < 3; i++)
- b->sorted_begin[i] = b->sorted_end[i] = NULL;
-
- INIT_MINMAX(b->bb, b->bb + 3);
-}
-
-RTBuilder *rtbuild_create(int size)
-{
- RTBuilder *builder = (RTBuilder *) MEM_mallocN(sizeof(RTBuilder), "RTBuilder");
- RTBuilder::Object *memblock = (RTBuilder::Object *)MEM_mallocN(sizeof(RTBuilder::Object) * size, "RTBuilder.objects");
-
-
- rtbuild_init(builder);
-
- builder->primitives.begin = builder->primitives.end = memblock;
- builder->primitives.maxsize = size;
-
- for (int i = 0; i < 3; i++) {
- builder->sorted_begin[i] = (RTBuilder::Object **)MEM_mallocN(sizeof(RTBuilder::Object *) * size, "RTBuilder.sorted_objects");
- builder->sorted_end[i] = builder->sorted_begin[i];
- }
-
-
- return builder;
-}
-
-void rtbuild_free(RTBuilder *b)
-{
- if (b->primitives.begin) MEM_freeN(b->primitives.begin);
-
- for (int i = 0; i < 3; i++)
- if (b->sorted_begin[i])
- MEM_freeN(b->sorted_begin[i]);
-
- MEM_freeN(b);
-}
-
-void rtbuild_add(RTBuilder *b, RayObject *o)
-{
- float bb[6];
-
- assert(b->primitives.begin + b->primitives.maxsize != b->primitives.end);
-
- INIT_MINMAX(bb, bb + 3);
- RE_rayobject_merge_bb(o, bb, bb + 3);
-
- /* skip objects with invalid bounding boxes, nan causes DO_MINMAX
- * to do nothing, so we get these invalid values. this shouldn't
- * happen usually, but bugs earlier in the pipeline can cause it. */
- if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
- return;
- /* skip objects with inf bounding boxes */
- if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2]))
- return;
- if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5]))
- return;
- /* skip objects with zero bounding box, they are of no use, and
- * will give problems in rtbuild_heuristic_object_split later */
- if (bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5])
- return;
-
- copy_v3_v3(b->primitives.end->bb, bb);
- copy_v3_v3(b->primitives.end->bb + 3, bb + 3);
- b->primitives.end->obj = o;
- b->primitives.end->cost = RE_rayobject_cost(o);
-
- for (int i = 0; i < 3; i++) {
- *(b->sorted_end[i]) = b->primitives.end;
- b->sorted_end[i]++;
- }
- b->primitives.end++;
-}
-
-int rtbuild_size(RTBuilder *b)
-{
- return b->sorted_end[0] - b->sorted_begin[0];
-}
-
-
-template<class Obj, int Axis>
-static bool obj_bb_compare(const Obj &a, const Obj &b)
-{
- if (a->bb[Axis] != b->bb[Axis])
- return a->bb[Axis] < b->bb[Axis];
- return a->obj < b->obj;
-}
-
-template<class Item>
-static void object_sort(Item *begin, Item *end, int axis)
-{
- if (axis == 0) return std::sort(begin, end, obj_bb_compare<Item, 0> );
- if (axis == 1) return std::sort(begin, end, obj_bb_compare<Item, 1> );
- if (axis == 2) return std::sort(begin, end, obj_bb_compare<Item, 2> );
- assert(false);
-}
-
-void rtbuild_done(RTBuilder *b, RayObjectControl *ctrl)
-{
- for (int i = 0; i < 3; i++) {
- if (b->sorted_begin[i]) {
- if (RE_rayobjectcontrol_test_break(ctrl)) break;
- object_sort(b->sorted_begin[i], b->sorted_end[i], i);
- }
- }
-}
-
-RayObject *rtbuild_get_primitive(RTBuilder *b, int index)
-{
- return b->sorted_begin[0][index]->obj;
-}
-
-RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp)
-{
- rtbuild_init(tmp);
-
- tmp->depth = b->depth + 1;
-
- for (int i = 0; i < 3; i++)
- if (b->sorted_begin[i]) {
- tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child];
- tmp->sorted_end[i] = b->sorted_begin[i] + b->child_offset[child + 1];
- }
- else {
- tmp->sorted_begin[i] = NULL;
- tmp->sorted_end[i] = NULL;
- }
-
- return tmp;
-}
-
-static void rtbuild_calc_bb(RTBuilder *b)
-{
- if (b->bb[0] == 1.0e30f) {
- for (RTBuilder::Object **index = b->sorted_begin[0]; index != b->sorted_end[0]; index++)
- RE_rayobject_merge_bb( (*index)->obj, b->bb, b->bb + 3);
- }
-}
-
-void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3])
-{
- rtbuild_calc_bb(b);
- DO_MIN(b->bb, min);
- DO_MAX(b->bb + 3, max);
-}
-
-#if 0
-int rtbuild_get_largest_axis(RTBuilder *b)
-{
- rtbuild_calc_bb(b);
- return bb_largest_axis(b->bb, b->bb + 3);
-}
-
-//Left balanced tree
-int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis)
-{
- int i;
- int mleafs_per_child, Mleafs_per_child;
- int tot_leafs = rtbuild_size(b);
- int missing_leafs;
-
- long long s;
-
- assert(nchilds <= RTBUILD_MAX_CHILDS);
-
- //TODO optimize calc of leafs_per_child
- for (s = nchilds; s < tot_leafs; s *= nchilds) ;
- Mleafs_per_child = s / nchilds;
- mleafs_per_child = Mleafs_per_child / nchilds;
-
- //split min leafs per child
- b->child_offset[0] = 0;
- for (i = 1; i <= nchilds; i++)
- b->child_offset[i] = mleafs_per_child;
-
- //split remaining leafs
- missing_leafs = tot_leafs - mleafs_per_child * nchilds;
- for (i = 1; i <= nchilds; i++)
- {
- if (missing_leafs > Mleafs_per_child - mleafs_per_child)
- {
- b->child_offset[i] += Mleafs_per_child - mleafs_per_child;
- missing_leafs -= Mleafs_per_child - mleafs_per_child;
- }
- else {
- b->child_offset[i] += missing_leafs;
- missing_leafs = 0;
- break;
- }
- }
-
- //adjust for accumulative offsets
- for (i = 1; i <= nchilds; i++)
- b->child_offset[i] += b->child_offset[i - 1];
-
- //Count created childs
- for (i = nchilds; b->child_offset[i] == b->child_offset[i - 1]; i--) ;
- split_leafs(b, b->child_offset, i, axis);
-
- assert(b->child_offset[0] == 0 && b->child_offset[i] == tot_leafs);
- return i;
-}
-
-
-int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds)
-{
- int axis = rtbuild_get_largest_axis(b);
- return rtbuild_mean_split(b, nchilds, axis);
-}
-#endif
-
-/*
- * "separators" is an array of dim NCHILDS-1
- * and indicates where to cut the childs
- */
-#if 0
-int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis)
-{
- int size = rtbuild_size(b);
-
- assert(nchilds <= RTBUILD_MAX_CHILDS);
- if (size <= nchilds)
- {
- return rtbuild_mean_split(b, nchilds, axis);
- }
- else {
- int i;
-
- b->split_axis = axis;
-
- //Calculate child offsets
- b->child_offset[0] = 0;
- for (i = 0; i < nchilds - 1; i++)
- b->child_offset[i + 1] = split_leafs_by_plane(b, b->child_offset[i], size, separators[i]);
- b->child_offset[nchilds] = size;
-
- for (i = 0; i < nchilds; i++)
- if (b->child_offset[i + 1] - b->child_offset[i] == size)
- return rtbuild_mean_split(b, nchilds, axis);
-
- return nchilds;
- }
-}
-
-int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds)
-{
- int la, i;
- float separators[RTBUILD_MAX_CHILDS];
-
- rtbuild_calc_bb(b);
-
- la = bb_largest_axis(b->bb, b->bb + 3);
- for (i = 1; i < nchilds; i++)
- separators[i - 1] = (b->bb[la + 3] - b->bb[la]) * i / nchilds;
-
- return rtbuild_median_split(b, separators, nchilds, la);
-}
-#endif
-
-//Heuristics Object Splitter
-
-
-struct SweepCost {
- float bb[6];
- float cost;
-};
-
-/* Object Surface Area Heuristic splitter */
-int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
-{
- int size = rtbuild_size(b);
- assert(nchilds == 2);
- assert(size > 1);
- int baxis = -1, boffset = 0;
-
- if (size > nchilds) {
- if (b->depth > RTBUILD_MAX_SAH_DEPTH) {
- // for degenerate cases we avoid running out of stack space
- // by simply splitting the children in the middle
- b->child_offset[0] = 0;
- b->child_offset[1] = (size+1)/2;
- b->child_offset[2] = size;
- return 2;
- }
-
- float bcost = FLT_MAX;
- baxis = -1;
- boffset = size / 2;
-
- SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep");
-
- for (int axis = 0; axis < 3; axis++) {
- SweepCost sweep_left;
-
- RTBuilder::Object **obj = b->sorted_begin[axis];
-
-// float right_cost = 0;
- for (int i = size - 1; i >= 0; i--) {
- if (i == size - 1) {
- copy_v3_v3(sweep[i].bb, obj[i]->bb);
- copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3);
- sweep[i].cost = obj[i]->cost;
- }
- else {
- sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]);
- sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]);
- sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]);
- sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]);
- sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]);
- sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]);
- sweep[i].cost = obj[i]->cost + sweep[i + 1].cost;
- }
-// right_cost += obj[i]->cost;
- }
-
- sweep_left.bb[0] = obj[0]->bb[0];
- sweep_left.bb[1] = obj[0]->bb[1];
- sweep_left.bb[2] = obj[0]->bb[2];
- sweep_left.bb[3] = obj[0]->bb[3];
- sweep_left.bb[4] = obj[0]->bb[4];
- sweep_left.bb[5] = obj[0]->bb[5];
- sweep_left.cost = obj[0]->cost;
-
-// right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0;
-
- for (int i = 1; i < size; i++) {
- //Worst case heuristic (cost of each child is linear)
- float hcost, left_side, right_side;
-
- // not using log seems to have no impact on raytracing perf, but
- // makes tree construction quicker, left out for now to test (brecht)
- // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i));
- // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i));
- left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost);
- right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost);
- hcost = left_side + right_side;
-
- assert(left_side >= 0);
- assert(right_side >= 0);
-
- if (left_side > bcost) break; //No way we can find a better heuristic in this axis
-
- assert(hcost >= 0);
- // this makes sure the tree built is the same whatever is the order of the sorting axis
- if (hcost < bcost || (hcost == bcost && axis < baxis)) {
- bcost = hcost;
- baxis = axis;
- boffset = i;
- }
- DO_MIN(obj[i]->bb, sweep_left.bb);
- DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3);
-
- sweep_left.cost += obj[i]->cost;
-// right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0;
- }
-
- //assert(baxis >= 0 && baxis < 3);
- if (!(baxis >= 0 && baxis < 3))
- baxis = 0;
- }
-
-
- MEM_freeN(sweep);
- }
- else if (size == 2) {
- baxis = 0;
- boffset = 1;
- }
- else if (size == 1) {
- b->child_offset[0] = 0;
- b->child_offset[1] = 1;
- return 1;
- }
-
- b->child_offset[0] = 0;
- b->child_offset[1] = boffset;
- b->child_offset[2] = size;
-
-
- /* Adjust sorted arrays for childs */
- for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true;
- for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false;
- for (int i = 0; i < 3; i++)
- std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node);
-
- return nchilds;
-}
-
-/*
- * Helper code
- * PARTITION code / used on mean-split
- * basically this a std::nth_element (like on C++ STL algorithm)
- */
-#if 0
-static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis)
-{
- int i;
- b->split_axis = split_axis;
-
- for (i = 0; i < partitions - 1; i++)
- {
- assert(nth[i] < nth[i + 1] && nth[i + 1] < nth[partitions]);
-
- if (split_axis == 0) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 0>);
- if (split_axis == 1) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 1>);
- if (split_axis == 2) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 2>);
- }
-}
-#endif
-
-/*
- * Bounding Box utils
- */
-float bb_volume(const float min[3], const float max[3])
-{
- return (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]);
-}
-
-float bb_area(const float min[3], const float max[3])
-{
- float sub[3], a;
- sub[0] = max[0] - min[0];
- sub[1] = max[1] - min[1];
- sub[2] = max[2] - min[2];
-
- a = (sub[0] * sub[1] + sub[0] * sub[2] + sub[1] * sub[2]) * 2.0f;
- /* used to have an assert() here on negative results
- * however, in this case its likely some overflow or ffast math error.
- * so just return 0.0f instead. */
- return a < 0.0f ? 0.0f : a;
-}
-
-int bb_largest_axis(const float min[3], const float max[3])
-{
- float sub[3];
-
- sub[0] = max[0] - min[0];
- sub[1] = max[1] - min[1];
- sub[2] = max[2] - min[2];
- if (sub[0] > sub[1]) {
- if (sub[0] > sub[2])
- return 0;
- else
- return 2;
- }
- else {
- if (sub[1] > sub[2])
- return 1;
- else
- return 2;
- }
-}
-
-/* only returns 0 if merging inner and outerbox would create a box larger than outer box */
-int bb_fits_inside(const float outer_min[3], const float outer_max[3],
- const float inner_min[3], const float inner_max[3])
-{
- int i;
- for (i = 0; i < 3; i++)
- if (outer_min[i] > inner_min[i]) return 0;
-
- for (i = 0; i < 3; i++)
- if (outer_max[i] < inner_max[i]) return 0;
-
- return 1;
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
deleted file mode 100644
index 061d76e3a3e..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_rtbuild.h
- * \ingroup render
- */
-
-#ifndef __RAYOBJECT_RTBUILD_H__
-#define __RAYOBJECT_RTBUILD_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "rayobject.h"
-
-
-/*
- * Ray Tree Builder
- * this structs helps building any type of tree
- * it contains several methods to organize/split nodes
- * allowing to create a given tree on the fly.
- *
- * Idea is that other trees BVH, BIH can use this code to
- * generate with simple calls, and then convert to the theirs
- * specific structure on the fly.
- */
-#define RTBUILD_MAX_CHILDS 32
-#define RTBUILD_MAX_SAH_DEPTH 256
-
-
-typedef struct RTBuilder {
- struct Object {
- RayObject *obj;
- float cost;
- float bb[6];
- int selected;
- };
-
- /* list to all primitives added in this tree */
- struct {
- Object *begin, *end;
- int maxsize;
- } primitives;
-
- /* sorted list of rayobjects */
- struct Object **sorted_begin[3], **sorted_end[3];
-
- /* axis used (if any) on the split method */
- int split_axis;
-
- /* child partitions calculated during splitting */
- int child_offset[RTBUILD_MAX_CHILDS + 1];
-
-// int child_sorted_axis; /* -1 if not sorted */
-
- float bb[6];
-
- /* current depth */
- int depth;
-} RTBuilder;
-
-/* used during creation */
-RTBuilder *rtbuild_create(int size);
-void rtbuild_free(RTBuilder *b);
-void rtbuild_add(RTBuilder *b, RayObject *o);
-void rtbuild_done(RTBuilder *b, RayObjectControl *c);
-void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]);
-int rtbuild_size(RTBuilder *b);
-
-RayObject *rtbuild_get_primitive(RTBuilder *b, int offset);
-
-/* used during tree reorganization */
-RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp);
-
-/* Calculates child partitions and returns number of efectively needed partitions */
-int rtbuild_get_largest_axis(RTBuilder *b);
-
-//Object partition
-int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis);
-int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds);
-
-int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds);
-
-//Space partition
-int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis);
-int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds);
-
-
-/* bb utils */
-float bb_area(const float min[3], const float max[3]);
-float bb_volume(const float min[3], const float max[3]);
-int bb_largest_axis(const float min[3], const float max[3]);
-int bb_fits_inside(const float outer_min[3], const float outer_max[3],
- const float inner_min[3], const float inner_max[3]);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYOBJECT_RTBUILD_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
deleted file mode 100644
index eb7dddac06e..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_svbvh.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "vbvh.h"
-#include "svbvh.h"
-#include "reorganize.h"
-
-#ifdef __SSE__
-
-#define DFS_STACK_SIZE 256
-
-struct SVBVHTree {
- RayObject rayobj;
-
- SVBVHNode *root;
- MemArena *node_arena;
-
- float cost;
- RTBuilder *builder;
-};
-
-/*
- * Cost to test N childs
- */
-struct PackCost {
- float operator()(int n)
- {
- return (n / 4) + ((n % 4) > 2 ? 1 : n % 4);
- }
-};
-
-
-template<>
-void bvh_done<SVBVHTree>(SVBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2");
- BLI_memarena_use_malloc(arena2);
- BLI_memarena_use_align(arena2, 16);
-
- //Build and optimize the tree
- if (0) {
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- reorganize(root);
- remove_useless(root, &root);
- bvh_refit(root);
-
- pushup(root);
- pushdown(root);
- pushup_simd<VBVHNode, 4>(root);
-
- obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
- }
- else {
- //Finds the optimal packing of this tree using a given cost model
- //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
- OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- if (root) {
- VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
- obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
- }
- else
- obj->root = NULL;
- }
-
- //Free data
- BLI_memarena_free(arena1);
-
- obj->node_arena = arena2;
- obj->cost = 1.0;
-
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-}
-
-template<int StackSize>
-static int intersect(SVBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
- else
- return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *) obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-static RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return NULL;
-}
-
-RayObject *RE_rayobject_svbvh_create(int size)
-{
- return bvh_create_tree<SVBVHTree, DFS_STACK_SIZE>(size);
-}
-
-#else
-
-RayObject *RE_rayobject_svbvh_create(int UNUSED(size))
-{
- puts("WARNING: SSE disabled at compile time\n");
- return NULL;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
deleted file mode 100644
index dfa5a69b335..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_vbvh.cpp
- * \ingroup render
- */
-
-
-int tot_pushup = 0;
-int tot_pushdown = 0;
-int tot_hints = 0;
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_memarena.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_global.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rayobject_rtbuild.h"
-
-#include "reorganize.h"
-#include "bvh.h"
-#include "vbvh.h"
-
-#include <queue>
-#include <algorithm>
-
-#define DFS_STACK_SIZE 256
-
-struct VBVHTree {
- RayObject rayobj;
- VBVHNode *root;
- MemArena *node_arena;
- float cost;
- RTBuilder *builder;
-};
-
-/*
- * Cost to test N childs
- */
-struct PackCost {
- float operator()(int n)
- {
- return n;
- }
-};
-
-template<>
-void bvh_done<VBVHTree>(VBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- //Build and optimize the tree
- if (1) {
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- return;
- }
-
- if (root) {
- reorganize(root);
- remove_useless(root, &root);
- bvh_refit(root);
-
- pushup(root);
- pushdown(root);
- obj->root = root;
- }
- else
- obj->root = NULL;
- }
- else {
- /* TODO */
-#if 0
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena2");
- BLI_memarena_use_malloc(arena2);
-
- //Finds the optimal packing of this tree using a given cost model
- //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
- OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena2).transform(obj->builder);
- VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
- obj->root = Reorganize_VBVH<OVBVHNode>(arena1).transform(root);
-
- BLI_memarena_free(arena2);
-#endif
- }
-
- //Cleanup
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-
- obj->node_arena = arena1;
- obj->cost = 1.0;
-}
-
-template<int StackSize>
-static int intersect(VBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return bvh_node_stack_raycast<VBVHNode, StackSize, false, true>(obj->root, isec);
- else
- return bvh_node_stack_raycast<VBVHNode, StackSize, false, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *) obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-
-#if 0 /* UNUSED */
-static void bfree(VBVHTree *tree)
-{
- if (tot_pushup + tot_pushdown + tot_hints + tot_moves) {
- if (G.debug & G_DEBUG) {
- printf("tot pushups: %d\n", tot_pushup);
- printf("tot pushdowns: %d\n", tot_pushdown);
- printf("tot moves: %d\n", tot_moves);
- printf("tot hints created: %d\n", tot_hints);
- }
-
- tot_pushup = 0;
- tot_pushdown = 0;
- tot_hints = 0;
- tot_moves = 0;
- }
- bvh_free(tree);
-}
-#endif
-
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return 0;
-}
-
-RayObject *RE_rayobject_vbvh_create(int size)
-{
- return bvh_create_tree<VBVHTree, DFS_STACK_SIZE>(size);
-}
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
deleted file mode 100644
index 84d04a8851f..00000000000
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/reorganize.h
- * \ingroup render
- */
-
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <queue>
-#include <vector>
-
-#include "BKE_global.h"
-
-#ifdef _WIN32
-# ifdef INFINITY
-# undef INFINITY
-# endif
-# define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though.
-#endif
-
-extern int tot_pushup;
-extern int tot_pushdown;
-
-#if !defined(INFINITY) && defined(HUGE_VAL)
-#define INFINITY HUGE_VAL
-#endif
-
-template<class Node>
-static bool node_fits_inside(Node *a, Node *b)
-{
- return bb_fits_inside(b->bb, b->bb + 3, a->bb, a->bb + 3);
-}
-
-template<class Node>
-static void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Node *> &cost)
-{
- std::queue<Node *> q;
- q.push(tree);
-
- while (!q.empty()) {
- Node *parent = q.front();
- q.pop();
-
- if (parent == node) continue;
- if (node_fits_inside(node, parent) && RE_rayobject_isAligned(parent->child) ) {
- float pcost = bb_area(parent->bb, parent->bb + 3);
- cost = std::min(cost, std::make_pair(pcost, parent) );
- for (Node *child = parent->child; child; child = child->sibling)
- q.push(child);
- }
- }
-}
-
-template<class Node>
-static void reorganize(Node *root)
-{
- std::queue<Node *> q;
-
- q.push(root);
- while (!q.empty()) {
- Node *node = q.front();
- q.pop();
-
- if (RE_rayobject_isAligned(node->child)) {
- for (Node **prev = &node->child; *prev; ) {
- assert(RE_rayobject_isAligned(*prev));
- q.push(*prev);
-
- std::pair<float, Node *> best(FLT_MAX, root);
- reorganize_find_fittest_parent(root, *prev, best);
-
- if (best.second == node) {
- //Already inside the fitnest BB
- prev = &(*prev)->sibling;
- }
- else {
- Node *tmp = *prev;
- *prev = (*prev)->sibling;
-
- tmp->sibling = best.second->child;
- best.second->child = tmp;
- }
-
-
- }
- }
- if (node != root) {
- }
- }
-}
-
-/*
- * Prunes useless nodes from trees:
- * erases nodes with total amount of primitives = 0
- * prunes nodes with only one child (except if that child is a primitive)
- */
-template<class Node>
-static void remove_useless(Node *node, Node **new_node)
-{
- if (RE_rayobject_isAligned(node->child) ) {
-
- for (Node **prev = &node->child; *prev; ) {
- Node *next = (*prev)->sibling;
- remove_useless(*prev, prev);
- if (*prev == NULL)
- *prev = next;
- else {
- (*prev)->sibling = next;
- prev = &((*prev)->sibling);
- }
- }
- }
- if (node->child) {
- if (RE_rayobject_isAligned(node->child) && node->child->sibling == 0)
- *new_node = node->child;
- }
- else if (node->child == NULL) {
- *new_node = NULL;
- }
-}
-
-/*
- * Minimizes expected number of BBtest by colapsing nodes
- * it uses surface area heuristic for determining whether a node should be colapsed
- */
-template<class Node>
-static void pushup(Node *parent)
-{
- if (is_leaf(parent)) return;
-
- float p_area = bb_area(parent->bb, parent->bb + 3);
- Node **prev = &parent->child;
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
- const float c_area = bb_area(child->bb, child->bb + 3);
- const int nchilds = count_childs(child);
- float original_cost = ((p_area != 0.0f) ? (c_area / p_area) * nchilds : 1.0f) + 1;
- float flatten_cost = nchilds;
- if (flatten_cost < original_cost && nchilds >= 2) {
- append_sibling(child, child->child);
- child = child->sibling;
- *prev = child;
-
-// *prev = child->child;
-// append_sibling( *prev, child->sibling );
-// child = *prev;
- tot_pushup++;
- }
- else {
- *prev = child;
- prev = &(*prev)->sibling;
- child = *prev;
- }
- }
-
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
- pushup(child);
-}
-
-/*
- * try to optimize number of childs to be a multiple of SSize
- */
-template<class Node, int SSize>
-static void pushup_simd(Node *parent)
-{
- if (is_leaf(parent)) return;
-
- int n = count_childs(parent);
-
- Node **prev = &parent->child;
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
- int cn = count_childs(child);
- if (cn - 1 <= (SSize - (n % SSize) ) % SSize && RE_rayobject_isAligned(child->child) ) {
- n += (cn - 1);
- append_sibling(child, child->child);
- child = child->sibling;
- *prev = child;
- }
- else {
- *prev = child;
- prev = &(*prev)->sibling;
- child = *prev;
- }
- }
-
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
- pushup_simd<Node, SSize>(child);
-}
-
-
-/*
- * Pushdown
- * makes sure no child fits inside any of its sibling
- */
-template<class Node>
-static void pushdown(Node *parent)
-{
- Node **s_child = &parent->child;
- Node *child = parent->child;
-
- while (child && RE_rayobject_isAligned(child)) {
- Node *next = child->sibling;
- Node **next_s_child = &child->sibling;
-
- //assert(bb_fits_inside(parent->bb, parent->bb+3, child->bb, child->bb+3));
-
- for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling)
- if (child != i && bb_fits_inside(i->bb, i->bb + 3, child->bb, child->bb + 3) && RE_rayobject_isAligned(i->child)) {
-// todo optimize (should the one with the smallest area?)
-// float ia = bb_area(i->bb, i->bb+3)
-// if (child->i)
- *s_child = child->sibling;
- child->sibling = i->child;
- i->child = child;
- next_s_child = s_child;
-
- tot_pushdown++;
- break;
- }
- child = next;
- s_child = next_s_child;
- }
-
- for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling) {
- pushdown(i);
- }
-}
-
-
-/*
- * BVH refit
- * readjust nodes BB (useful if nodes childs where modified)
- */
-template<class Node>
-static float bvh_refit(Node *node)
-{
- if (is_leaf(node)) return 0;
- if (is_leaf(node->child)) return 0;
-
- float total = 0;
-
- for (Node *child = node->child; child; child = child->sibling)
- total += bvh_refit(child);
-
- float old_area = bb_area(node->bb, node->bb + 3);
- INIT_MINMAX(node->bb, node->bb + 3);
- for (Node *child = node->child; child; child = child->sibling) {
- DO_MIN(child->bb, node->bb);
- DO_MAX(child->bb + 3, node->bb + 3);
- }
- total += old_area - bb_area(node->bb, node->bb + 3);
- return total;
-}
-
-
-/*
- * this finds the best way to packing a tree according to a given test cost function
- * with the purpose to reduce the expected cost (eg.: number of BB tests).
- */
-#include <vector>
-#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */
-#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE
-
-#define CUT_SIZE_IS_VALID(cut_size) ((cut_size) < MAX_CUT_SIZE && (cut_size) >= 0)
-#define CUT_SIZE_INVALID -1
-
-
-struct OVBVHNode {
- float bb[6];
-
- OVBVHNode *child;
- OVBVHNode *sibling;
-
- /*
- * Returns min cost to represent the subtree starting at the given node,
- * allowing it to have a given cutsize
- */
- float cut_cost[MAX_CUT_SIZE];
- float get_cost(int cutsize)
- {
- assert(CUT_SIZE_IS_VALID(cutsize - 1));
- return cut_cost[cutsize - 1];
- }
-
- /*
- * This saves the cut size of this child, when parent is reaching
- * its minimum cut with the given cut size
- */
- int cut_size[MAX_CUT_SIZE];
- int get_cut_size(int parent_cut_size)
- {
- assert(CUT_SIZE_IS_VALID(parent_cut_size - 1));
- return cut_size[parent_cut_size - 1];
- }
-
- /*
- * Reorganize the node based on calculated cut costs
- */
- int best_cutsize;
- void set_cut(int cutsize, OVBVHNode ***cut)
- {
- if (cutsize == 1) {
- **cut = this;
- *cut = &(**cut)->sibling;
- }
- else {
- if (cutsize > MAX_CUT_SIZE) {
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- child->set_cut(1, cut);
- cutsize--;
- }
- assert(cutsize == 0);
- }
- else {
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- child->set_cut(child->get_cut_size(cutsize), cut);
- }
- }
- }
- }
-
- void optimize()
- {
- if (RE_rayobject_isAligned(this->child)) {
- //Calc new childs
- if (this->best_cutsize != CUT_SIZE_INVALID) {
- OVBVHNode **cut = &(this->child);
- set_cut(this->best_cutsize, &cut);
- *cut = NULL;
- }
-
- //Optimize new childs
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling)
- child->optimize();
- }
- }
-};
-
-/*
- * Calculates an optimal SIMD packing
- *
- */
-template<class Node, class TestCost>
-struct VBVH_optimalPackSIMD {
- TestCost testcost;
-
- VBVH_optimalPackSIMD(TestCost testcost)
- {
- this->testcost = testcost;
- }
-
- /*
- * calc best cut on a node
- */
- struct calc_best {
- Node *child[MAX_OPTIMIZE_CHILDS];
- float child_hit_prob[MAX_OPTIMIZE_CHILDS];
-
- calc_best(Node *node)
- {
- int nchilds = 0;
- //Fetch childs and needed data
- {
- float parent_area = bb_area(node->bb, node->bb + 3);
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- this->child[nchilds] = child;
- this->child_hit_prob[nchilds] = (parent_area != 0.0f) ? bb_area(child->bb, child->bb + 3) / parent_area : 1.0f;
- nchilds++;
- }
-
- assert(nchilds >= 2 && nchilds <= MAX_OPTIMIZE_CHILDS);
- }
-
-
- //Build DP table to find minimum cost to represent this node with a given cutsize
- int bt[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //backtrace table
- float cost[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //cost table (can be reduced to float[2][MAX_CUT_COST])
-
- for (int i = 0; i <= nchilds; i++) {
- for (int j = 0; j <= MAX_CUT_SIZE; j++) {
- cost[i][j] = INFINITY;
- }
- }
-
- cost[0][0] = 0;
-
- for (int i = 1; i <= nchilds; i++) {
- for (int size = i - 1; size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; size++) {
- for (int cut = 1; cut + size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; cut++) {
- float new_cost = cost[i - 1][size] + child_hit_prob[i - 1] * child[i - 1]->get_cost(cut);
- if (new_cost < cost[i][size + cut]) {
- cost[i][size + cut] = new_cost;
- bt[i][size + cut] = cut;
- }
- }
- }
- }
-
- /* Save the ways to archive the minimum cost with a given cutsize */
- for (int i = nchilds; i <= MAX_CUT_SIZE; i++) {
- node->cut_cost[i - 1] = cost[nchilds][i];
- if (cost[nchilds][i] < INFINITY) {
- int current_size = i;
- for (int j = nchilds; j > 0; j--) {
- child[j - 1]->cut_size[i - 1] = bt[j][current_size];
- current_size -= bt[j][current_size];
- }
- }
- }
- }
- };
-
- void calc_costs(Node *node)
- {
-
- if (RE_rayobject_isAligned(node->child) ) {
- int nchilds = 0;
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- calc_costs(child);
- nchilds++;
- }
-
- for (int i = 0; i < MAX_CUT_SIZE; i++)
- node->cut_cost[i] = INFINITY;
-
- //We are not allowed to look on nodes with with so many childs
- if (nchilds > MAX_CUT_SIZE) {
- float cost = 0;
-
- float parent_area = bb_area(node->bb, node->bb + 3);
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- cost += ((parent_area != 0.0f) ? (bb_area(child->bb, child->bb + 3) / parent_area) : 1.0f) * child->get_cost(1);
- }
-
- cost += testcost(nchilds);
- node->cut_cost[0] = cost;
- node->best_cutsize = nchilds;
- }
- else {
- calc_best calc(node);
-
- //calc expected cost if we optimaly pack this node
- for (int cutsize = nchilds; cutsize <= MAX_CUT_SIZE; cutsize++) {
- float m = node->get_cost(cutsize) + testcost(cutsize);
- if (m < node->cut_cost[0]) {
- node->cut_cost[0] = m;
- node->best_cutsize = cutsize;
- }
- }
- }
-
- if (node->cut_cost[0] == INFINITY) {
- node->best_cutsize = CUT_SIZE_INVALID;
- }
- }
- else {
- node->cut_cost[0] = 1.0f;
- for (int i = 1; i < MAX_CUT_SIZE; i++)
- node->cut_cost[i] = INFINITY;
-
- /* node->best_cutsize can remain unset here */
- }
- }
-
- Node *transform(Node *node)
- {
- if (RE_rayobject_isAligned(node->child)) {
-#ifdef DEBUG
- static int num = 0;
- bool first = false;
- if (num == 0) { num++; first = true; }
-#endif
-
- calc_costs(node);
-
-#ifdef DEBUG
- if (first && G.debug) {
- printf("expected cost = %f (%d)\n", node->cut_cost[0], node->best_cutsize);
- }
-#endif
- node->optimize();
- }
- return node;
- }
-};
diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h
deleted file mode 100644
index 292b93c445f..00000000000
--- a/source/blender/render/intern/raytrace/svbvh.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/svbvh.h
- * \ingroup render
- */
-
-#ifndef __SVBVH_H__
-#define __SVBVH_H__
-
-#ifdef __SSE__
-
-#include "bvh.h"
-#include "BLI_memarena.h"
-#include <algorithm>
-
-struct SVBVHNode {
- float child_bb[24];
- SVBVHNode *child[4];
- int nchilds;
-};
-
-static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group)
-{
- const __m128 tmin0 = _mm_setzero_ps();
- const __m128 tmax0 = _mm_set_ps1(isec->dist);
-
- const __m128 start0 = _mm_set_ps1(isec->start[0]);
- const __m128 start1 = _mm_set_ps1(isec->start[1]);
- const __m128 start2 = _mm_set_ps1(isec->start[2]);
- const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0);
- const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0);
- const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1);
- const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1);
- const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2);
- const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2);
- const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]);
- const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]);
- const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]);
- const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0);
- const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0);
- const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1);
- const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1);
- const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2);
- const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2);
- const __m128 tmin1 = _mm_max_ps(tmin0, mul0);
- const __m128 tmax1 = _mm_min_ps(tmax0, mul1);
- const __m128 tmin2 = _mm_max_ps(tmin1, mul2);
- const __m128 tmax2 = _mm_min_ps(tmax1, mul3);
- const __m128 tmin3 = _mm_max_ps(tmin2, mul4);
- const __m128 tmax3 = _mm_min_ps(tmax2, mul5);
-
- return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
-}
-
-static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb)
-{
- const float *bb = _bb;
-
- float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
- float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
- float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
- float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
- float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
- float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
-
- RE_RC_COUNT(isec->raycounter->bb.test);
-
- if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
- if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
- if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
-
- RE_RC_COUNT(isec->raycounter->bb.hit);
-
- return 1;
-}
-
-static bool svbvh_node_is_leaf(const SVBVHNode *node)
-{
- return !RE_rayobject_isAligned(node);
-}
-
-template<int MAX_STACK_SIZE, bool SHADOW>
-static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec)
-{
- SVBVHNode *stack[MAX_STACK_SIZE], *node;
- int hit = 0, stack_pos = 0;
-
- stack[stack_pos++] = root;
-
- while (stack_pos) {
- node = stack[--stack_pos];
-
- if (!svbvh_node_is_leaf(node)) {
- int nchilds = node->nchilds;
-
- if (nchilds == 4) {
- float *child_bb = node->child_bb;
- int res = svbvh_bb_intersect_test_simd4(isec, ((__m128 *) (child_bb)));
- SVBVHNode **child = node->child;
-
- RE_RC_COUNT(isec->raycounter->simd_bb.test);
-
- if (res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- }
- else {
- float *child_bb = node->child_bb;
- SVBVHNode **child = node->child;
- int i;
-
- for (i = 0; i < nchilds; i++) {
- if (svbvh_bb_intersect_test(isec, (float *)child_bb + 6 * i)) {
- stack[stack_pos++] = child[i];
- }
- }
- }
- }
- else {
- hit |= RE_rayobject_intersect((RayObject *)node, isec);
- if (SHADOW && hit) break;
- }
- }
-
- return hit;
-}
-
-
-template<>
-inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float min[3], float max[3])
-{
- if (is_leaf(node)) {
- RE_rayobject_merge_bb((RayObject *)node, min, max);
- }
- else {
- int i;
- for (i = 0; i + 4 <= node->nchilds; i += 4) {
- float *res = node->child_bb + 6 * i;
- for (int j = 0; j < 3; j++) {
- min[j] = min_ff(min[j],
- min_ffff(res[4 * j + 0],
- res[4 * j + 1],
- res[4 * j + 2],
- res[4 * j + 3]));
- }
- for (int j = 0; j < 3; j++) {
- max[j] = max_ff(max[j],
- max_ffff(res[4 * (j + 3) + 0],
- res[4 * (j + 3) + 1],
- res[4 * (j + 3) + 2],
- res[4 * (j + 3) + 3]));
- }
- }
-
- for (; i < node->nchilds; i++) {
- DO_MIN(node->child_bb + 6 * i, min);
- DO_MAX(node->child_bb + 3 + 6 * i, max);
- }
- }
-}
-
-
-
-/*
- * Builds a SVBVH tree form a VBVHTree
- */
-template<class OldNode>
-struct Reorganize_SVBVH {
- MemArena *arena;
-
- float childs_per_node;
- int nodes_with_childs[16];
- int useless_bb;
- int nodes;
-
- Reorganize_SVBVH(MemArena *a)
- {
- arena = a;
- nodes = 0;
- childs_per_node = 0;
- useless_bb = 0;
-
- for (int i = 0; i < 16; i++) {
- nodes_with_childs[i] = 0;
- }
- }
-
- ~Reorganize_SVBVH()
- {
-#if 0
- {
- printf("%f childs per node\n", childs_per_node / nodes);
- printf("%d childs BB are useless\n", useless_bb);
- for (int i = 0; i < 16; i++) {
- printf("%i childs per node: %d/%d = %f\n", i, nodes_with_childs[i], nodes, nodes_with_childs[i] / float(nodes));
- }
- }
-#endif
- }
-
- SVBVHNode *create_node(int nchilds)
- {
- SVBVHNode *node = (SVBVHNode *)BLI_memarena_alloc(arena, sizeof(SVBVHNode));
- node->nchilds = nchilds;
-
- return node;
- }
-
- void copy_bb(float bb[6], const float old_bb[6])
- {
- std::copy(old_bb, old_bb + 6, bb);
- }
-
- void prepare_for_simd(SVBVHNode *node)
- {
- int i = 0;
- while (i + 4 <= node->nchilds) {
- float vec_tmp[4 * 6];
- float *res = node->child_bb + 6 * i;
- std::copy(res, res + 6 * 4, vec_tmp);
-
- for (int j = 0; j < 6; j++) {
- res[4 * j + 0] = vec_tmp[6 * 0 + j];
- res[4 * j + 1] = vec_tmp[6 * 1 + j];
- res[4 * j + 2] = vec_tmp[6 * 2 + j];
- res[4 * j + 3] = vec_tmp[6 * 3 + j];
- }
-
- i += 4;
- }
- }
-
- /* amt must be power of two */
- inline int padup(int num, int amt)
- {
- return ((num + (amt - 1)) & ~(amt - 1));
- }
-
- SVBVHNode *transform(OldNode *old)
- {
- if (is_leaf(old))
- return (SVBVHNode *)old;
- if (is_leaf(old->child))
- return (SVBVHNode *)old->child;
-
- int nchilds = count_childs(old);
- int alloc_childs = nchilds;
- if (nchilds % 4 > 2)
- alloc_childs = padup(nchilds, 4);
-
- SVBVHNode *node = create_node(alloc_childs);
-
- childs_per_node += nchilds;
- nodes++;
- if (nchilds < 16)
- nodes_with_childs[nchilds]++;
-
- useless_bb += alloc_childs - nchilds;
- while (alloc_childs > nchilds) {
- const static float def_bb[6] = {FLT_MAX, FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
- alloc_childs--;
- node->child[alloc_childs] = NULL;
- copy_bb(node->child_bb + alloc_childs * 6, def_bb);
- }
-
- int i = nchilds;
- for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling) {
- i--;
- node->child[i] = transform(o_child);
- if (is_leaf(o_child)) {
- float bb[6];
- INIT_MINMAX(bb, bb + 3);
- RE_rayobject_merge_bb((RayObject *)o_child, bb, bb + 3);
- copy_bb(node->child_bb + i * 6, bb);
- break;
- }
- else {
- copy_bb(node->child_bb + i * 6, o_child->bb);
- }
- }
- assert(i == 0);
-
- prepare_for_simd(node);
-
- return node;
- }
-};
-
-#endif /* __SSE__ */
-
-#endif /* __SVBVH_H__ */
diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h
deleted file mode 100644
index abccab5fc13..00000000000
--- a/source/blender/render/intern/raytrace/vbvh.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/vbvh.h
- * \ingroup render
- */
-
-
-#include <assert.h>
-#include <algorithm>
-
-#include "BLI_memarena.h"
-
-#include "rayobject_rtbuild.h"
-
-/*
- * VBVHNode represents a BVHNode with support for a variable number of childrens
- */
-struct VBVHNode {
- float bb[6];
-
- VBVHNode *child;
- VBVHNode *sibling;
-};
-
-
-/*
- * Push nodes (used on dfs)
- */
-template<class Node>
-inline static void bvh_node_push_childs(Node *node, Isect *UNUSED(isec), Node **stack, int &stack_pos)
-{
- Node *child = node->child;
-
- if (is_leaf(child)) {
- stack[stack_pos++] = child;
- }
- else {
- while (child) {
- /* Skips BB tests on primitives */
-#if 0
- if (is_leaf(child->child)) {
- stack[stack_pos++] = child->child;
- }
- else
-#endif
- {
- stack[stack_pos++] = child;
- }
-
- child = child->sibling;
- }
- }
-}
-
-
-template<class Node>
-static int count_childs(Node *parent)
-{
- int n = 0;
- for (Node *i = parent->child; i; i = i->sibling) {
- n++;
- if (is_leaf(i))
- break;
- }
-
- return n;
-}
-
-
-template<class Node>
-static void append_sibling(Node *node, Node *sibling)
-{
- while (node->sibling)
- node = node->sibling;
-
- node->sibling = sibling;
-}
-
-
-/*
- * Builds a binary VBVH from a rtbuild
- */
-template<class Node>
-struct BuildBinaryVBVH {
- MemArena *arena;
- RayObjectControl *control;
-
- void test_break()
- {
- if (RE_rayobjectcontrol_test_break(control))
- throw "Stop";
- }
-
- BuildBinaryVBVH(MemArena *a, RayObjectControl *c)
- {
- arena = a;
- control = c;
- }
-
- Node *create_node()
- {
- Node *node = (Node *)BLI_memarena_alloc(arena, sizeof(Node) );
- assert(RE_rayobject_isAligned(node));
-
- node->sibling = NULL;
- node->child = NULL;
-
- return node;
- }
-
- int rtbuild_split(RTBuilder *builder)
- {
- return ::rtbuild_heuristic_object_split(builder, 2);
- }
-
- Node *transform(RTBuilder *builder)
- {
- try
- {
- return _transform(builder);
-
- } catch (...)
- {
- }
- return NULL;
- }
-
- Node *_transform(RTBuilder *builder)
- {
- int size = rtbuild_size(builder);
-
- if (size == 0) {
- return NULL;
- }
- else if (size == 1) {
- Node *node = create_node();
- INIT_MINMAX(node->bb, node->bb + 3);
- rtbuild_merge_bb(builder, node->bb, node->bb + 3);
- node->child = (Node *) rtbuild_get_primitive(builder, 0);
- return node;
- }
- else {
- test_break();
-
- Node *node = create_node();
-
- Node **child = &node->child;
-
- int nc = rtbuild_split(builder);
- INIT_MINMAX(node->bb, node->bb + 3);
-
- assert(nc == 2);
- for (int i = 0; i < nc; i++) {
- RTBuilder tmp;
- rtbuild_get_child(builder, i, &tmp);
-
- *child = _transform(&tmp);
- DO_MIN((*child)->bb, node->bb);
- DO_MAX((*child)->bb + 3, node->bb + 3);
- child = &((*child)->sibling);
- }
-
- *child = NULL;
- return node;
- }
- }
-};
-
-#if 0
-template<class Tree, class OldNode>
-struct Reorganize_VBVH {
- Tree *tree;
-
- Reorganize_VBVH(Tree *t)
- {
- tree = t;
- }
-
- VBVHNode *create_node()
- {
- VBVHNode *node = (VBVHNode *)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode));
- return node;
- }
-
- void copy_bb(VBVHNode *node, OldNode *old)
- {
- std::copy(old->bb, old->bb + 6, node->bb);
- }
-
- VBVHNode *transform(OldNode *old)
- {
- if (is_leaf(old))
- return (VBVHNode *)old;
-
- VBVHNode *node = create_node();
- VBVHNode **child_ptr = &node->child;
- node->sibling = 0;
-
- copy_bb(node, old);
-
- for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling)
- {
- VBVHNode *n_child = transform(o_child);
- *child_ptr = n_child;
- if (is_leaf(n_child)) return node;
- child_ptr = &n_child->sibling;
- }
- *child_ptr = 0;
-
- return node;
- }
-};
-#endif
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
deleted file mode 100644
index 48f5f494e58..00000000000
--- a/source/blender/render/intern/source/bake.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- * Contributors: Vertex color baking, Copyright 2011 AutoCRC
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/bake.c
- * \ingroup render
- */
-
-
-/* system includes */
-#include <stdio.h>
-#include <string.h>
-
-/* External modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_image_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_node.h"
-#include "BKE_scene.h"
-#include "BKE_library.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-#include "IMB_colormanagement.h"
-
-/* local include */
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "zbuf.h"
-
-#include "PIL_time.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ************************* bake ************************ */
-
-
-typedef struct BakeShade {
- int thread;
-
- ShadeSample ssamp;
- ObjectInstanceRen *obi;
- VlakRen *vlr;
-
- ZSpan *zspan;
- Image *ima;
- ImBuf *ibuf;
-
- int rectx, recty, quad, type, vdone;
- bool ready;
-
- float dir[3];
- Object *actob;
-
- /* Output: vertex color or image data. If vcol is not NULL, rect and
- * rect_float should be NULL. */
- MPoly *mpoly;
- MLoop *mloop;
- MLoopCol *vcol;
-
- unsigned int *rect;
- float *rect_float;
-
- /* displacement buffer used for normalization with unknown maximal distance */
- bool use_displacement_buffer;
- float *displacement_buffer;
- float displacement_min, displacement_max;
-
- bool use_mask;
- char *rect_mask; /* bake pixel mask */
-
- float dxco[3], dyco[3];
-
- short *do_update;
-
- struct ColorSpace *rect_colorspace;
-} BakeShade;
-
-static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v)
-{
- if (quad)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* cache for shadow */
- shi->samplenr = R.shadowsamplenr[shi->thread]++;
-
- shi->mask = 0xFFFF; /* all samples */
-
- shi->u = -u;
- shi->v = -v;
- shi->xs = x;
- shi->ys = y;
-
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
-
- /* no normal flip */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- /* set up view vector to look right at the surface (note that the normal
- * is negated in the renderer so it does not need to be done here) */
- shi->view[0] = shi->vn[0];
- shi->view[1] = shi->vn[1];
- shi->view[2] = shi->vn[2];
-}
-
-static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang)
-{
- BakeShade *bs = handle;
- ShadeSample *ssamp = &bs->ssamp;
- ShadeResult shr;
- VlakRen *vlr = shi->vlr;
-
- shade_input_init_material(shi);
-
- if (bs->type == RE_BAKE_AO) {
- ambient_occlusion(shi);
-
- if (R.r.bake_flag & R_BAKE_NORMALIZE) {
- copy_v3_v3(shr.combined, shi->ao);
- }
- else {
- zero_v3(shr.combined);
- environment_lighting_apply(shi, &shr);
- }
- }
- else {
- if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */
- shi->r = shi->g = shi->b = 1.0f;
-
- shade_input_set_shade_texco(shi);
-
- /* only do AO for a full bake (and obviously AO bakes)
- * AO for light bakes is a leftover and might not be needed */
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT))
- shade_samples_do_AO(ssamp);
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
- shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
- }
- else
- shade_material_loop(shi, &shr);
-
- if (bs->type == RE_BAKE_NORMALS) {
- float nor[3];
-
- copy_v3_v3(nor, shi->vn);
-
- if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) {
- /* pass */
- }
- else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
- float mat[3][3], imat[3][3];
-
- /* bitangent */
- if (tvn && ttang) {
- copy_v3_v3(mat[0], ttang);
- cross_v3_v3v3(mat[1], tvn, ttang);
- mul_v3_fl(mat[1], ttang[3]);
- copy_v3_v3(mat[2], tvn);
- }
- else {
- copy_v3_v3(mat[0], shi->nmaptang);
- cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang);
- mul_v3_fl(mat[1], shi->nmaptang[3]);
- copy_v3_v3(mat[2], shi->nmapnorm);
- }
-
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, nor);
- }
- else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT)
- mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */
- else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD)
- mul_mat3_m4_v3(R.viewinv, nor);
-
- normalize_v3(nor); /* in case object has scaling */
-
- /* The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed.
- *
- * there is also a small 1e-5f bias for precision issues. otherwise
- * we randomly get 127 or 128 for neutral colors. we choose 128
- * because it is the convention flat color. * */
- shr.combined[0] = (-nor[0]) / 2.0f + 0.5f + 1e-5f;
- shr.combined[1] = nor[1] / 2.0f + 0.5f + 1e-5f;
- shr.combined[2] = nor[2] / 2.0f + 0.5f + 1e-5f;
- }
- else if (bs->type == RE_BAKE_TEXTURE) {
- copy_v3_v3(shr.combined, &shi->r);
- shr.alpha = shi->alpha;
- }
- else if (bs->type == RE_BAKE_SHADOW) {
- copy_v3_v3(shr.combined, shr.shad);
- shr.alpha = shi->alpha;
- }
- else if (bs->type == RE_BAKE_SPEC_COLOR) {
- copy_v3_v3(shr.combined, &shi->specr);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_SPEC_INTENSITY) {
- copy_v3_fl(shr.combined, shi->spec);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_MIRROR_COLOR) {
- copy_v3_v3(shr.combined, &shi->mirr);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_MIRROR_INTENSITY) {
- copy_v3_fl(shr.combined, shi->ray_mirror);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_ALPHA) {
- copy_v3_fl(shr.combined, shi->alpha);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_EMIT) {
- copy_v3_fl(shr.combined, shi->emit);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_VERTEX_COLORS) {
- copy_v3_v3(shr.combined, shi->vcol);
- shr.alpha = shi->vcol[3];
- }
- }
-
- if (bs->rect_float && !bs->vcol) {
- float *col = bs->rect_float + 4 * (bs->rectx * y + x);
- copy_v3_v3(col, shr.combined);
- if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) {
- col[3] = shr.alpha;
- }
- else {
- col[3] = 1.0;
- }
- }
- else {
- /* Target is char (LDR). */
- unsigned char col[4];
-
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
- float rgb[3];
-
- copy_v3_v3(rgb, shr.combined);
- if (R.scene_color_manage) {
- /* Vertex colors have no way to specify color space, so they
- * default to sRGB. */
- if (!bs->vcol)
- IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace);
- else
- linearrgb_to_srgb_v3_v3(rgb, rgb);
- }
- rgb_float_to_uchar(col, rgb);
- }
- else {
- rgb_float_to_uchar(col, shr.combined);
- }
-
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) {
- col[3] = FTOCHAR(shr.alpha);
- }
- else {
- col[3] = 255;
- }
-
- if (bs->vcol) {
- /* Vertex color baking. Vcol has no useful alpha channel (it exists
- * but is used only for vertex painting). */
- bs->vcol->r = col[0];
- bs->vcol->g = col[1];
- bs->vcol->b = col[2];
- }
- else {
- unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_uchar(imcol, col);
- }
-
- }
-
- if (bs->rect_mask) {
- bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
- }
-
- if (bs->do_update) {
- *bs->do_update = true;
- }
-}
-
-static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y)
-{
- BakeShade *bs = handle;
- float disp;
-
- if (R.r.bake_flag & R_BAKE_NORMALIZE) {
- if (R.r.bake_maxdist)
- disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/
- else
- disp = dist;
- }
- else {
- disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/
- }
-
- if (bs->displacement_buffer) {
- float *displacement = bs->displacement_buffer + (bs->rectx * y + x);
- *displacement = disp;
- bs->displacement_min = min_ff(bs->displacement_min, disp);
- bs->displacement_max = max_ff(bs->displacement_max, disp);
- }
-
- if (bs->rect_float && !bs->vcol) {
- float *col = bs->rect_float + 4 * (bs->rectx * y + x);
- col[0] = col[1] = col[2] = disp;
- col[3] = 1.0f;
- }
- else {
- /* Target is char (LDR). */
- unsigned char col[4];
- col[0] = col[1] = col[2] = FTOCHAR(disp);
- col[3] = 255;
-
- if (bs->vcol) {
- /* Vertex color baking. Vcol has no useful alpha channel (it exists
- * but is used only for vertex painting). */
- bs->vcol->r = col[0];
- bs->vcol->g = col[1];
- bs->vcol->b = col[2];
- }
- else {
- unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_uchar(imcol, col);
- }
- }
- if (bs->rect_mask) {
- bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
- }
-}
-
-static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist)
-{
- float maxdist;
- int hit;
-
- /* might be useful to make a user setting for maxsize*/
- if (R.r.bake_maxdist > 0.0f)
- maxdist = R.r.bake_maxdist;
- else
- maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist;
-
- /* 'dir' is always normalized */
- madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist);
-
- mul_v3_v3fl(isect->dir, dir, sign);
-
- isect->dist = maxdist;
-
- hit = RE_rayobject_raycast(raytree, isect);
- if (hit) {
- madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist);
-
- *dist = isect->dist;
- }
-
- return hit;
-}
-
-static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
-{
- VlakRen *vlr = bs->vlr;
- float A, d1, d2, d3, *v1, *v2, *v3;
-
- if (bs->quad) {
- v1 = vlr->v1->co;
- v2 = vlr->v3->co;
- v3 = vlr->v4->co;
- }
- else {
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
- }
-
- /* formula derived from barycentric coordinates:
- * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea
- * then taking u and v partial derivatives to get dxco and dyco */
- A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]);
-
- if (fabsf(A) > FLT_EPSILON) {
- A = 0.5f / A;
-
- d1 = uv2[1] - uv3[1];
- d2 = uv3[1] - uv1[1];
- d3 = uv1[1] - uv2[1];
- bs->dxco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
- bs->dxco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
- bs->dxco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
-
- d1 = uv3[0] - uv2[0];
- d2 = uv1[0] - uv3[0];
- d3 = uv2[0] - uv1[0];
- bs->dyco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
- bs->dyco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
- bs->dyco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
- }
- else {
- bs->dxco[0] = bs->dxco[1] = bs->dxco[2] = 0.0f;
- bs->dyco[0] = bs->dyco[1] = bs->dyco[2] = 0.0f;
- }
-
- if (bs->obi->flag & R_TRANSFORMED) {
- mul_m3_v3(bs->obi->nmat, bs->dxco);
- mul_m3_v3(bs->obi->nmat, bs->dyco);
- }
-}
-
-static void do_bake_shade(void *handle, int x, int y, float u, float v)
-{
- BakeShade *bs = handle;
- VlakRen *vlr = bs->vlr;
- ObjectInstanceRen *obi = bs->obi;
- Object *ob = obi->obr->ob;
- float l, *v1, *v2, *v3, tvn[3], ttang[4];
- int quad;
- ShadeSample *ssamp = &bs->ssamp;
- ShadeInput *shi = ssamp->shi;
-
- /* fast threadsafe break test */
- if (R.test_break(R.tbh))
- return;
-
- /* setup render coordinates */
- if (bs->quad) {
- v1 = vlr->v1->co;
- v2 = vlr->v3->co;
- v3 = vlr->v4->co;
- }
- else {
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
- }
-
- l = 1.0f - u - v;
-
- /* shrink barycentric coordinates inwards slightly to avoid some issues
- * where baking selected to active might just miss the other face at the
- * near the edge of a face */
- if (bs->actob) {
- const float eps = 1.0f - 1e-4f;
- float invsum;
-
- u = (u - 0.5f) * eps + 0.5f;
- v = (v - 0.5f) * eps + 0.5f;
- l = (l - 0.5f) * eps + 0.5f;
-
- invsum = 1.0f / (u + v + l);
-
- u *= invsum;
- v *= invsum;
- l *= invsum;
- }
-
- /* renderco */
- shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
- shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
- shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
-
- /* avoid self shadow with vertex bake from adjacent faces [#33729] */
- if ((bs->vcol != NULL) && (bs->actob == NULL)) {
- madd_v3_v3fl(shi->co, vlr->n, 0.0001f);
- }
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, shi->co);
-
- copy_v3_v3(shi->dxco, bs->dxco);
- copy_v3_v3(shi->dyco, bs->dyco);
-
- quad = bs->quad;
- bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v);
-
- if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
- shade_input_set_shade_texco(shi);
- copy_v3_v3(tvn, shi->nmapnorm);
- copy_v4_v4(ttang, shi->nmaptang);
- }
-
- /* if we are doing selected to active baking, find point on other face */
- if (bs->actob) {
- Isect isec, minisec;
- float co[3], minco[3], dist, mindist = 0.0f;
- int hit, sign, dir = 1;
-
- /* intersect with ray going forward and backward*/
- hit = 0;
- memset(&minisec, 0, sizeof(minisec));
- minco[0] = minco[1] = minco[2] = 0.0f;
-
- copy_v3_v3(bs->dir, shi->vn);
-
- for (sign = -1; sign <= 1; sign += 2) {
- memset(&isec, 0, sizeof(isec));
- isec.mode = RE_RAY_MIRROR;
-
- isec.orig.ob = obi;
- isec.orig.face = vlr;
- isec.userdata = bs->actob;
- isec.check = RE_CHECK_VLR_BAKE;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
-
- if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
- if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) {
- minisec = isec;
- mindist = dist;
- copy_v3_v3(minco, co);
- hit = 1;
- dir = sign;
- }
- }
- }
-
- if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
- if (hit)
- bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y);
- else
- bake_displacement(handle, shi, 0.0f, x, y);
- return;
- }
-
- /* if hit, we shade from the new point, otherwise from point one starting face */
- if (hit) {
- obi = (ObjectInstanceRen *)minisec.hit.ob;
- vlr = (VlakRen *)minisec.hit.face;
- quad = (minisec.isect == 2);
- copy_v3_v3(shi->co, minco);
-
- u = -minisec.u;
- v = -minisec.v;
- bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
- }
- }
-
- if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
- bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang);
- else
- bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, NULL);
-}
-
-static int get_next_bake_face(BakeShade *bs)
-{
- ObjectRen *obr;
- VlakRen *vlr;
- MTFace *tface;
- static int v = 0, vdone = false;
- static ObjectInstanceRen *obi = NULL;
-
- if (bs == NULL) {
- vlr = NULL;
- v = vdone = false;
- obi = R.instancetable.first;
- return 0;
- }
-
- BLI_thread_lock(LOCK_CUSTOM1);
-
- for (; obi; obi = obi->next, v = 0) {
- obr = obi->obr;
-
- /* only allow non instances here */
- if (obr->flag & R_INSTANCEABLE)
- continue;
-
- for (; v < obr->totvlak; v++) {
- vlr = RE_findOrAddVlak(obr, v);
-
- if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
- if (R.r.bake_flag & R_BAKE_VCOL) {
- /* Gather face data for vertex color bake */
- Mesh *me;
- int *origindex, vcollayer;
- CustomDataLayer *cdl;
-
- if (obr->ob->type != OB_MESH)
- continue;
- me = obr->ob->data;
-
- origindex = RE_vlakren_get_origindex(obr, vlr, 0);
- if (origindex == NULL)
- continue;
- if (*origindex >= me->totpoly) {
- /* Small hack for Array modifier, which gives false
- * original indices - z0r */
- continue;
- }
-#if 0
- /* Only shade selected faces. */
- if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0)
- continue;
-#endif
-
- vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
- if (vcollayer == -1)
- continue;
-
- cdl = &me->ldata.layers[vcollayer];
- bs->mpoly = me->mpoly + *origindex;
- bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart;
- bs->mloop = me->mloop + bs->mpoly->loopstart;
-
- /* Tag mesh for reevaluation. */
- me->id.tag |= LIB_TAG_DOIT;
- }
- else {
- Image *ima = NULL;
- ImBuf *ibuf = NULL;
- const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
- const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
- const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
- const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
-
- tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
- /* should use 'BKE_object_material_edit_image_get' but in this case simpler not to */
- ima = vlr->mat ? vlr->mat->edit_image : NULL;
-
- if (!tface || !ima)
- continue;
-
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ibuf == NULL)
- continue;
-
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->flag & IMA_USED_FOR_RENDER) {
- ima->id.tag &= ~LIB_TAG_DOIT;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- /* find the image for the first time? */
- if (ima->id.tag & LIB_TAG_DOIT) {
- ima->id.tag &= ~LIB_TAG_DOIT;
-
- /* we either fill in float or char, this ensures things go fine */
- if (ibuf->rect_float)
- imb_freerectImBuf(ibuf);
- /* clear image */
- if (R.r.bake_flag & R_BAKE_CLEAR) {
- if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
- else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE))
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
- else
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
- }
- /* might be read by UI to set active image for display */
- R.bakebuf = ima;
- }
-
- /* Tag image for redraw. */
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- bs->obi = obi;
- bs->vlr = vlr;
- bs->vdone++; /* only for error message if nothing was rendered */
- v++;
- BLI_thread_unlock(LOCK_CUSTOM1);
- return 1;
- }
- }
- }
-
- BLI_thread_unlock(LOCK_CUSTOM1);
- return 0;
-}
-
-static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
-{
- int *origindex, i;
- MLoopCol *basevcol;
- MLoop *mloop;
-
- /* per vertex fixed seed */
- BLI_thread_srandom(bs->thread, vert->index);
-
- origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
- if (!origindex || *origindex == ORIGINDEX_NONE)
- return;
-
- /* Search for matching vertex index and apply shading. */
- for (i = 0; i < bs->mpoly->totloop; i++) {
- mloop = bs->mloop + i;
- if (mloop->v != *origindex)
- continue;
- basevcol = bs->vcol;
- bs->vcol = basevcol + i;
- do_bake_shade(bs, 0, 0, u, v);
- bs->vcol = basevcol;
- break;
- }
-}
-
-/* Bake all vertices of a face. Actually, this still works on a face-by-face
- * basis, and each vertex on each face is shaded. Vertex colors are a property
- * of loops, not vertices. */
-static void shade_verts(BakeShade *bs)
-{
- VlakRen *vlr = bs->vlr;
-
- /* Disable baking to image; write to vcol instead. vcol pointer is set in
- * bake_single_vertex. */
- bs->ima = NULL;
- bs->rect = NULL;
- bs->rect_float = NULL;
- bs->displacement_buffer = NULL;
- bs->displacement_min = FLT_MAX;
- bs->displacement_max = -FLT_MAX;
-
- bs->quad = 0;
-
- /* No anti-aliasing for vertices. */
- zero_v3(bs->dxco);
- zero_v3(bs->dyco);
-
- /* Shade each vertex of the face. u and v are barycentric coordinates; since
- * we're only interested in vertices, these will be 0 or 1. */
- if ((vlr->flag & R_FACE_SPLIT) == 0) {
- /* Processing triangle face, whole quad, or first half of split quad. */
-
- bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f);
- bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
- bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
-
- if (vlr->v4) {
- bs->quad = 1;
- bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f);
- }
- }
- else {
- /* Processing second half of split quad. Only one vertex to go. */
- if (vlr->flag & R_DIVIDE_24) {
- bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
- }
- else {
- bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
- }
- }
-}
-
-/* already have tested for tface and ima and zspan */
-static void shade_tface(BakeShade *bs)
-{
- VlakRen *vlr = bs->vlr;
- ObjectInstanceRen *obi = bs->obi;
- ObjectRen *obr = obi->obr;
- MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
- Image *ima = vlr->mat->edit_image;
- float vec[4][2];
- int a, i1, i2, i3;
-
- /* per face fixed seed */
- BLI_thread_srandom(bs->thread, vlr->index);
-
- /* check valid zspan */
- if (ima != bs->ima) {
- BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
-
- bs->ima = ima;
- bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- /* note, these calls only free/fill contents of zspan struct, not zspan itself */
- zbuf_free_span(bs->zspan);
- zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop);
- }
-
- bs->rectx = bs->ibuf->x;
- bs->recty = bs->ibuf->y;
- bs->rect = bs->ibuf->rect;
- bs->rect_colorspace = bs->ibuf->rect_colorspace;
- bs->rect_float = bs->ibuf->rect_float;
- bs->vcol = NULL;
- bs->quad = 0;
- bs->rect_mask = NULL;
- bs->displacement_buffer = NULL;
-
- if (bs->use_mask || bs->use_displacement_buffer) {
- BakeImBufuserData *userdata = bs->ibuf->userdata;
- if (userdata == NULL) {
- BLI_thread_lock(LOCK_CUSTOM1);
- userdata = bs->ibuf->userdata;
- if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */
- userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData");
-
- if (bs->use_mask) {
- if (userdata->mask_buffer == NULL) {
- userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask");
- }
- }
-
- if (bs->use_displacement_buffer) {
- if (userdata->displacement_buffer == NULL) {
- userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp");
- }
- }
-
- bs->ibuf->userdata = userdata;
-
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-
- bs->rect_mask = userdata->mask_buffer;
- bs->displacement_buffer = userdata->displacement_buffer;
- }
-
- /* get pixel level vertex coordinates */
- for (a = 0; a < 4; a++) {
- /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
- * where a pixel gets in between 2 faces or the middle of a quad,
- * camera aligned quads also have this problem but they are less common.
- * Add a small offset to the UVs, fixes bug #18685 - Campbell */
- vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f);
- vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f);
- }
-
- /* UV indices have to be corrected for possible quad->tria splits */
- i1 = 0; i2 = 1; i3 = 2;
- vlr_set_uv_indices(vlr, &i1, &i2, &i3);
- bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]);
- zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
-
- if (vlr->v4) {
- bs->quad = 1;
- bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]);
- zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
- }
-}
-
-static void *do_bake_thread(void *bs_v)
-{
- BakeShade *bs = bs_v;
-
- while (get_next_bake_face(bs)) {
- if (R.r.bake_flag & R_BAKE_VCOL) {
- shade_verts(bs);
- }
- else {
- shade_tface(bs);
- }
-
- /* fast threadsafe break test */
- if (R.test_break(R.tbh))
- break;
-
- /* access is not threadsafe but since its just true/false probably ok
- * only used for interactive baking */
- if (bs->do_update) {
- *bs->do_update = true;
- }
- }
- bs->ready = true;
-
- BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
-
- return NULL;
-}
-
-void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
-{
- /* must check before filtering */
- const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
-
- /* Margin */
- if (filter) {
- IMB_filter_extend(ibuf, mask, filter);
- }
-
- /* if the bake results in new alpha then change the image setting */
- if (is_new_alpha) {
- ibuf->planes = R_IMF_PLANES_RGBA;
- }
- else {
- if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
- /* clear alpha added by filtering */
- IMB_rectfill_alpha(ibuf, 1.0f);
- }
- }
-}
-
-void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
-{
- int i;
- const float *current_displacement = displacement;
- const char *current_mask = mask;
- float max_distance;
-
- max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
-
- for (i = 0; i < ibuf->x * ibuf->y; i++) {
- if (*current_mask == FILTER_MASK_USED) {
- float normalized_displacement;
-
- if (max_distance > 1e-5f)
- normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
- else
- normalized_displacement = 0.5f;
-
- if (ibuf->rect_float) {
- /* currently baking happens to RGBA only */
- float *fp = ibuf->rect_float + i * 4;
- fp[0] = fp[1] = fp[2] = normalized_displacement;
- fp[3] = 1.0f;
- }
-
- if (ibuf->rect) {
- unsigned char *cp = (unsigned char *) (ibuf->rect + i);
- cp[0] = cp[1] = cp[2] = FTOCHAR(normalized_displacement);
- cp[3] = 255;
- }
- }
-
- current_displacement++;
- current_mask++;
- }
-}
-
-/* using object selection tags, the faces with UV maps get baked */
-/* render should have been setup */
-/* returns 0 if nothing was handled */
-int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
-{
- BakeShade *handles;
- ListBase threads;
- Image *ima;
- int a, vdone = false, result = BAKE_RESULT_OK;
- bool use_mask = false;
- bool use_displacement_buffer = false;
- bool do_manage = false;
-
- if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
- do_manage = BKE_scene_check_color_management_enabled(re->scene);
- }
-
- re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
-
- /* initialize render global */
- R = *re;
- R.bakebuf = NULL;
-
- /* initialize static vars */
- get_next_bake_face(NULL);
-
- /* do we need a mask? */
- if (re->r.bake_filter)
- use_mask = true;
-
- /* do we need buffer to store displacements */
- if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
- if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) ||
- (type == RE_BAKE_DERIVATIVE))
- {
- use_displacement_buffer = true;
- use_mask = true;
- }
- }
-
- /* baker uses this flag to detect if image was initialized */
- if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- ima->id.tag |= LIB_TAG_DOIT;
- ima->flag &= ~IMA_USED_FOR_RENDER;
- if (ibuf) {
- ibuf->userdata = NULL; /* use for masking if needed */
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
- }
-
- if (R.r.bake_flag & R_BAKE_VCOL) {
- /* untag all meshes */
- BKE_main_id_tag_listbase(&G.main->mesh, LIB_TAG_DOIT, false);
- }
-
- BLI_threadpool_init(&threads, do_bake_thread, re->r.threads);
-
- handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade");
-
- /* get the threads running */
- for (a = 0; a < re->r.threads; a++) {
- handles[a].thread = a;
-
- /* set defaults in handles */
- handles[a].ssamp.shi[0].lay = re->lay;
-
- if (type == RE_BAKE_SHADOW) {
- handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW;
- }
- else {
- handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED;
- }
- handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
- handles[a].ssamp.shi[0].thread = a;
- handles[a].ssamp.shi[0].do_manage = do_manage;
- handles[a].ssamp.tot = 1;
-
- handles[a].type = type;
- handles[a].actob = actob;
- if (R.r.bake_flag & R_BAKE_VCOL)
- handles[a].zspan = NULL;
- else
- handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
-
- handles[a].use_mask = use_mask;
- handles[a].use_displacement_buffer = use_displacement_buffer;
-
- handles[a].do_update = do_update; /* use to tell the view to update */
-
- handles[a].displacement_min = FLT_MAX;
- handles[a].displacement_max = -FLT_MAX;
-
- BLI_threadpool_insert(&threads, &handles[a]);
- }
-
- /* wait for everything to be done */
- a = 0;
- while (a != re->r.threads) {
- PIL_sleep_ms(50);
-
- /* calculate progress */
- for (vdone = false, a = 0; a < re->r.threads; a++)
- vdone += handles[a].vdone;
- if (progress)
- *progress = (float)(vdone / (float)re->totvlak);
-
- for (a = 0; a < re->r.threads; a++) {
- if (handles[a].ready == false) {
- break;
- }
- }
- }
-
- /* filter and refresh images */
- if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
- float displacement_min = FLT_MAX, displacement_max = -FLT_MAX;
-
- if (use_displacement_buffer) {
- for (a = 0; a < re->r.threads; a++) {
- displacement_min = min_ff(displacement_min, handles[a].displacement_min);
- displacement_max = max_ff(displacement_max, handles[a].displacement_max);
- }
- }
-
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- BakeImBufuserData *userdata;
-
- if (ima->flag & IMA_USED_FOR_RENDER)
- result = BAKE_RESULT_FEEDBACK_LOOP;
-
- if (!ibuf)
- continue;
-
- userdata = (BakeImBufuserData *)ibuf->userdata;
- if (userdata) {
- if (use_displacement_buffer) {
- if (type == RE_BAKE_DERIVATIVE) {
- float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f;
- RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- displacement_min, displacement_max, user_scale);
- }
- else {
- RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- displacement_min, displacement_max);
- }
- }
-
- RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter);
- }
-
- ibuf->userflags |= IB_BITMAPDIRTY;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
- }
-
- /* calculate return value */
- for (a = 0; a < re->r.threads; a++) {
- zbuf_free_span(handles[a].zspan);
- MEM_freeN(handles[a].zspan);
- }
- }
-
- MEM_freeN(handles);
-
- BLI_threadpool_end(&threads);
-
- if (vdone == 0) {
- result = BAKE_RESULT_NO_OBJECTS;
- }
-
- return result;
-}
-
-struct Image *RE_bake_shade_get_image(void)
-{
- return R.bakebuf;
-}
-
-/* **************** Derivative Maps Baker **************** */
-
-static void add_single_heights_margin(const ImBuf *ibuf, const char *mask, float *heights_buffer)
-{
- int x, y;
-
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- int index = ibuf->x * y + x;
-
- /* If unassigned pixel, look for neighbors. */
- if (mask[index] != FILTER_MASK_USED) {
- float height_acc = 0;
- int denom = 0;
- int i, j;
-
- for (j = -1; j <= 1; j++)
- for (i = -1; i <= 1; i++) {
- int w = (i == 0 ? 1 : 0) + (j == 0 ? 1 : 0) + 1;
-
- if (i != 0 || j != 0) {
- int index2 = 0;
- int x0 = x + i;
- int y0 = y + j;
-
- CLAMP(x0, 0, ibuf->x - 1);
- CLAMP(y0, 0, ibuf->y - 1);
-
- index2 = ibuf->x * y0 + x0;
-
- if (mask[index2] == FILTER_MASK_USED) {
- height_acc += w * heights_buffer[index2];
- denom += w;
- }
- }
- }
-
- /* Insert final value. */
- if (denom > 0) {
- heights_buffer[index] = height_acc / denom;
- }
- }
- }
- }
-}
-
-/* returns user-scale */
-float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask,
- const float height_min, const float height_max,
- const float fmult)
-{
- const float delta_height = height_max - height_min;
- const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f;
- bool auto_range_fit = fmult <= 0.0f;
- float max_num_deriv = -1.0f;
- int x, y, index;
-
- /* Need a single margin to calculate good derivatives. */
- add_single_heights_margin(ibuf, mask, heights_buffer);
-
- if (auto_range_fit) {
- /* If automatic range fitting is enabled. */
- for (y = 0; y < ibuf->y; y++) {
- const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
- const int Yc = y;
- const int Yd = y == 0 ? 0 : (y - 1);
-
- for (x = 0; x < ibuf->x; x++) {
- const int Xl = x == 0 ? 0 : (x - 1);
- const int Xc = x;
- const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
-
- const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
- const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
- const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
-
- const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
- const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
- const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
-
- /* This corresponds to using the sobel kernel on the heights buffer
- * to obtain the derivative multiplied by 8.
- */
- const float deriv_x = Hu + 2 * Hcy + Hd;
- const float deriv_y = Hr + 2 * Hcx + Hl;
-
- /* early out */
- index = ibuf->x * y + x;
- if (mask[index] != FILTER_MASK_USED) {
- continue;
- }
-
- /* Widen bound. */
- if (fabsf(deriv_x) > max_num_deriv) {
- max_num_deriv = fabsf(deriv_x);
- }
-
- if (fabsf(deriv_y) > max_num_deriv) {
- max_num_deriv = fabsf(deriv_y);
- }
- }
- }
- }
-
- /* Output derivatives. */
- auto_range_fit &= (max_num_deriv > 0);
- for (y = 0; y < ibuf->y; y++) {
- const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
- const int Yc = y;
- const int Yd = y == 0 ? 0 : (y - 1);
-
- for (x = 0; x < ibuf->x; x++) {
- const int Xl = x == 0 ? 0 : (x - 1);
- const int Xc = x;
- const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
-
- const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
- const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
- const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
-
- const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
- const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
- const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
-
- /* This corresponds to using the sobel kernel on the heights buffer
- * to obtain the derivative multiplied by 8.
- */
- float deriv_x = Hu + 2 * Hcy + Hd;
- float deriv_y = Hr + 2 * Hcx + Hl;
-
- /* Early out. */
- index = ibuf->x * y + x;
- if (mask[index] != FILTER_MASK_USED) {
- continue;
- }
-
- if (auto_range_fit) {
- deriv_x /= max_num_deriv;
- deriv_y /= max_num_deriv;
- }
- else {
- deriv_x *= (fmult / denom);
- deriv_y *= (fmult / denom);
- }
-
- deriv_x = deriv_x * 0.5f + 0.5f;
- deriv_y = deriv_y * 0.5f + 0.5f;
-
- /* Clamp. */
- CLAMP(deriv_x, 0.0f, 1.0f);
- CLAMP(deriv_y, 0.0f, 1.0f);
-
- /* Write out derivatives. */
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + index * 4;
-
- rrgbf[0] = deriv_x;
- rrgbf[1] = deriv_y;
- rrgbf[2] = 0.0f;
- rrgbf[3] = 1.0f;
- }
- else {
- char *rrgb = (char *)ibuf->rect + index * 4;
-
- rrgb[0] = FTOCHAR(deriv_x);
- rrgb[1] = FTOCHAR(deriv_y);
- rrgb[2] = 0;
- rrgb[3] = 255;
- }
- }
- }
-
- /* Eeturn user-scale (for rendering). */
- return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f);
-}
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 505af3c2fa8..bd3e01c83a8 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -84,19 +84,11 @@
/* local include */
#include "render_types.h"
-#include "shading.h"
#include "zbuf.h"
/* Remove when Cycles moves from MFace to MLoopTri */
#define USE_MFACE_WORKAROUND
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
typedef struct BakeDataZSpan {
BakePixel *pixel_array;
int primitive_id;
@@ -263,6 +255,36 @@ static void calc_point_from_barycentric_extrusion(
copy_v3_v3(r_dir, dir);
}
+static void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
+{
+ /* find most stable axis to project */
+ int axis1, axis2;
+ axis_dominant_v3(&axis1, &axis2, facenor);
+
+ /* compute u,v and derivatives */
+ float t00 = v3[axis1] - v1[axis1];
+ float t01 = v3[axis2] - v1[axis2];
+ float t10 = v3[axis1] - v2[axis1];
+ float t11 = v3[axis2] - v2[axis2];
+
+ float detsh = (t00 * t11 - t10 * t01);
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ t00 *= detsh; t01 *= detsh;
+ t10 *= detsh; t11 *= detsh;
+
+ *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
+ *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
+ if (differentials) {
+ *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
+ *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
+ *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
+ *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
+ }
+}
+
/**
* This function populates pixel_array and returns TRUE if things are correct
*/
@@ -665,7 +687,7 @@ void RE_bake_pixels_populate(
}
for (i = 0; i < bake_images->size; i++) {
- zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
+ zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height);
}
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
@@ -958,36 +980,6 @@ void RE_bake_ibuf_clear(Image *image, const bool is_tangent)
/* ************************************************************* */
-/**
- * not the real UV, but the internal per-face UV instead
- * I'm using it to test if everything is correct */
-static bool bake_uv(const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[])
-{
- size_t i;
-
- for (i=0; i < num_pixels; i++) {
- size_t offset = i * depth;
- copy_v2_v2(&result[offset], pixel_array[i].uv);
- }
-
- return true;
-}
-
-bool RE_bake_internal(
- Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[],
- const size_t num_pixels, const int depth, const eScenePassType pass_type, float result[])
-{
- switch (pass_type) {
- case SCE_PASS_UV:
- {
- return bake_uv(pixel_array, num_pixels, depth, result);
- }
- default:
- break;
- }
- return false;
-}
-
int RE_pass_depth(const eScenePassType pass_type)
{
/* IMB_buffer_byte_from_float assumes 4 channels
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
deleted file mode 100644
index 71e44887a8e..00000000000
--- a/source/blender/render/intern/source/convertblender.c
+++ /dev/null
@@ -1,5974 +0,0 @@
-/*
- * ***** 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/convertblender.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_rand.h"
-#include "BLI_memarena.h"
-#ifdef WITH_FREESTYLE
-# include "BLI_edgehash.h"
-#endif
-
-#include "BLT_translation.h"
-
-#include "DNA_material_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_image_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_curve.h"
-#include "BKE_customdata.h"
-#include "BKE_colortools.h"
-#include "BKE_displist.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_group.h"
-#include "BKE_key.h"
-#include "BKE_image.h"
-#include "BKE_lattice.h"
-#include "BKE_layer.h"
-#include "BKE_material.h"
-#include "BKE_main.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_scene.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
-#include "PIL_time.h"
-
-#include "envmap.h"
-#include "occlusion.h"
-#include "pointdensity.h"
-#include "voxeldata.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "renderpipeline.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "strand.h"
-#include "texture.h"
-#include "volume_precache.h"
-#include "sss.h"
-#include "zbuf.h"
-#include "sunsky.h"
-
-/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */
-/* or for checking vertex normal flips */
-#define FLT_EPSILON10 1.19209290e-06F
-
-/* could enable at some point but for now there are far too many conversions */
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
-#endif
-
-/* ------------------------------------------------------------------------- */
-/* tool functions/defines for ad hoc simplification and possible future
- * cleanup */
-/* ------------------------------------------------------------------------- */
-
-#define UVTOINDEX(u, v) (startvlak + (u) * sizev + (v))
-/*
- *
- * NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !!
- *
- * ^ ()----p4----p3----()
- * | | | | |
- * u | | F1 | F2 |
- * | | | |
- * ()----p1----p2----()
- * v ->
- */
-
-/* ------------------------------------------------------------------------- */
-
-#define CD_MASK_RENDER_INTERNAL \
- (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL)
-
-static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv)
-{
- int vLen = vsize-1+(!!cyclv);
- int v;
-
- for (v=0; v<vLen; v++) {
- VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v);
- VlakRen *vlr_other;
- VertRen *vert = RE_vertren_copy(obr, vlr->v2);
-
- if (cyclv) {
- vlr->v2 = vert;
-
- if (v == vLen - 1) {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
- vlr_other->v1 = vert;
- }
- else {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr_other->v1 = vert;
- }
- }
- else {
- vlr->v2 = vert;
-
- if (v < vLen - 1) {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr_other->v1 = vert;
- }
-
- if (v == 0) {
- vlr->v1 = RE_vertren_copy(obr, vlr->v1);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Stress, tangents and normals */
-/* ------------------------------------------------------------------------- */
-
-static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2)
-{
- float len= len_v3v3(v1->co, v2->co)/len_v3v3(v1->orco, v2->orco);
- float *acc;
-
- acc= accum + 2*v1->index;
- acc[0]+= len;
- acc[1]+= 1.0f;
-
- acc= accum + 2*v2->index;
- acc[0]+= len;
- acc[1]+= 1.0f;
-}
-
-static void calc_edge_stress(Render *UNUSED(re), ObjectRen *obr, Mesh *me)
-{
- float loc[3], size[3], *accum, *acc, *accumoffs, *stress;
- int a;
-
- if (obr->totvert==0) return;
-
- BKE_mesh_texspace_get(me, loc, NULL, size);
-
- accum= MEM_callocN(2*sizeof(float)*obr->totvert, "temp accum for stress");
-
- /* de-normalize orco */
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- if (ver->orco) {
- ver->orco[0]= ver->orco[0]*size[0] +loc[0];
- ver->orco[1]= ver->orco[1]*size[1] +loc[1];
- ver->orco[2]= ver->orco[2]*size[2] +loc[2];
- }
- }
-
- /* add stress values */
- accumoffs= accum; /* so we can use vertex index */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
-
- if (vlr->v1->orco && vlr->v4) {
- calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2);
- calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3);
- calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1);
- if (vlr->v4) {
- calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4);
- calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1);
- calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4);
- }
- }
- }
-
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- if (ver->orco) {
- /* find stress value */
- acc= accumoffs + 2*ver->index;
- if (acc[1]!=0.0f)
- acc[0]/= acc[1];
- stress= RE_vertren_get_stress(obr, ver, 1);
- *stress= *acc;
-
- /* restore orcos */
- ver->orco[0] = (ver->orco[0]-loc[0])/size[0];
- ver->orco[1] = (ver->orco[1]-loc[1])/size[1];
- ver->orco[2] = (ver->orco[2]-loc[2])/size[2];
- }
- }
-
- MEM_freeN(accum);
-}
-
-/* gets tangent from tface or orco */
-static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
-{
- MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
- VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4;
- float tang[3], *tav;
- float *uv1, *uv2, *uv3, *uv4;
- float uv[4][2];
-
- if (tface) {
- uv1= tface->uv[0];
- uv2= tface->uv[1];
- uv3= tface->uv[2];
- uv4= tface->uv[3];
- }
- else if (v1->orco) {
- uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
- map_to_sphere(&uv[0][0], &uv[0][1], v1->orco[0], v1->orco[1], v1->orco[2]);
- map_to_sphere(&uv[1][0], &uv[1][1], v2->orco[0], v2->orco[1], v2->orco[2]);
- map_to_sphere(&uv[2][0], &uv[2][1], v3->orco[0], v3->orco[1], v3->orco[2]);
- if (v4)
- map_to_sphere(&uv[3][0], &uv[3][1], v4->orco[0], v4->orco[1], v4->orco[2]);
- }
- else return;
-
- tangent_from_uv_v3(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
-
- if (do_tangent) {
- tav= RE_vertren_get_tangent(obr, v1, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v2, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
- add_v3_v3(tav, tang);
- }
-
- if (v4) {
- tangent_from_uv_v3(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
-
- if (do_tangent) {
- tav= RE_vertren_get_tangent(obr, v1, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v4, 1);
- add_v3_v3(tav, tang);
- }
- }
-}
-
-
-
-/****************************************************************
- ************ tangent space generation interface ****************
- ****************************************************************/
-
-typedef struct {
- ObjectRen *obr;
- int mtface_index;
-} SRenderMeshToTangent;
-
-/* interface */
-#include "mikktspace.h"
-
-static int GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- return pMesh->obr->totvlak;
-}
-
-static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- return vlr->v4!=NULL ? 4 : 3;
-}
-
-static void GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- const float *co = (&vlr->v1)[vert_index]->co;
- copy_v3_v3(r_co, co);
-}
-
-static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
- const float *coord;
-
- if (tface != NULL) {
- coord= tface->uv[vert_index];
- copy_v2_v2(r_uv, coord);
- }
- else if ((coord = (&vlr->v1)[vert_index]->orco)) {
- map_to_sphere(&r_uv[0], &r_uv[1], coord[0], coord[1], coord[2]);
- }
- else { /* else we get un-initialized value, 0.0 ok default? */
- zero_v2(r_uv);
- }
-}
-
-static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
-
- if (vlr->flag & ME_SMOOTH) {
- const float *n = (&vlr->v1)[vert_index]->n;
- copy_v3_v3(r_no, n);
- }
- else {
- negate_v3_v3(r_no, vlr->n);
- }
-}
-static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int iVert)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
- float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
- if (ftang!=NULL) {
- copy_v3_v3(&ftang[iVert*4+0], fvTangent);
- ftang[iVert*4+3]=fSign;
- }
-}
-
-static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent)
-{
- int a;
-
- /* clear all vertex normals */
- if (do_vertex_normal) {
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
- }
- }
-
- /* calculate cos of angles and point-masses, use as weight factor to
- * add face normal to vertex */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
- if (do_vertex_normal && vlr->flag & ME_SMOOTH) {
- float *n4= (vlr->v4)? vlr->v4->n: NULL;
- const float *c4= (vlr->v4)? vlr->v4->co: NULL;
-
- accumulate_vertex_normals_v3(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
- vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4);
- }
- if (do_tangent) {
- /* tangents still need to be calculated for flat faces too */
- /* weighting removed, they are not vertexnormals */
- calc_tangent_vector(obr, vlr, do_tangent);
- }
- }
-
- /* do solid faces */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
-
- if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) {
- if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n);
- if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n);
- if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n);
- if (vlr->v4 && is_zero_v3(vlr->v4->n)) copy_v3_v3(vlr->v4->n, vlr->n);
- }
- }
-
- /* normalize vertex normals */
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- if (do_tangent) {
- float *tav= RE_vertren_get_tangent(obr, ver, 0);
- if (tav) {
- /* orthonorm. */
- const float tdn = dot_v3v3(tav, ver->n);
- tav[0] -= ver->n[0]*tdn;
- tav[1] -= ver->n[1]*tdn;
- tav[2] -= ver->n[2]*tdn;
- normalize_v3(tav);
- }
- }
- }
-
- /* normal mapping tangent with mikktspace */
- if (do_nmap_tangent != false) {
- SRenderMeshToTangent mesh2tangent;
- SMikkTSpaceContext sContext;
- SMikkTSpaceInterface sInterface;
- memset(&mesh2tangent, 0, sizeof(SRenderMeshToTangent));
- memset(&sContext, 0, sizeof(SMikkTSpaceContext));
- memset(&sInterface, 0, sizeof(SMikkTSpaceInterface));
-
- mesh2tangent.obr = obr;
-
- sContext.m_pUserData = &mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = GetNumFaces;
- sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace;
- sInterface.m_getPosition = GetPosition;
- sInterface.m_getTexCoord = GetTextureCoordinate;
- sInterface.m_getNormal = GetNormal;
- sInterface.m_setTSpaceBasic = SetTSpace;
-
- for (a = 0; a < MAX_MTFACE; a++) {
- if (obr->tangent_mask & 1 << a) {
- mesh2tangent.mtface_index = a;
- genTangSpaceDefault(&sContext);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Autosmoothing: */
-/* ------------------------------------------------------------------------- */
-
-typedef struct ASvert {
- int totface;
- ListBase faces;
-} ASvert;
-
-typedef struct ASface {
- struct ASface *next, *prev;
- VlakRen *vlr[4];
- VertRen *nver[4];
-} ASface;
-
-static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
-{
- ASface *asf;
- int a = -1;
-
- if (v1 == NULL)
- return a;
-
- asf = asv->faces.last;
- if (asf) {
- for (a = 0; a < 4 && asf->vlr[a]; a++) {
- }
- }
- else {
- a = 4;
- }
-
- /* new face struct */
- if (a == 4) {
- a = 0;
- asf = MEM_callocN(sizeof(ASface), "asface");
- BLI_addtail(&asv->faces, asf);
- }
-
- asf->vlr[a] = vlr;
- asv->totface++;
-
- return a;
-}
-
-static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3])
-{
- /* return when new vertex already was made, or existing one is OK */
- ASface *asf;
- int a;
-
- /* First face, we can use existing vert and assign it current lnor! */
- if (asv->totface == 1) {
- copy_v3_v3(ver->n, lnor);
- return ver;
- }
-
- /* In case existing ver has same normal as current lnor, we can simply use it! */
- if (equals_v3v3(lnor, ver->n)) {
- return ver;
- }
-
- asf = asv->faces.first;
- while (asf) {
- for (a = 0; a < 4; a++) {
- if (asf->vlr[a] && asf->vlr[a] != vlr) {
- /* this face already made a copy for this vertex! */
- if (asf->nver[a]) {
- if (equals_v3v3(lnor, asf->nver[a]->n)) {
- return asf->nver[a];
- }
- }
- }
- }
- asf = asf->next;
- }
-
- return NULL;
-}
-
-static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3])
-{
- VertRen *v1;
- ASface *asf;
- int asf_idx;
- float lnor[3];
-
- normal_short_to_float_v3(lnor, _lnor);
-
- asf_idx = as_addvert(asv, ver, vlr);
- if (asf_idx < 0) {
- return;
- }
- asf = asv->faces.last;
-
- /* already made a new vertex within threshold? */
- v1 = as_findvertex_lnor(vlr, ver, asv, lnor);
- if (v1 == NULL) {
- /* make a new vertex */
- v1 = RE_vertren_copy(obr, ver);
- copy_v3_v3(v1->n, lnor);
- }
- if (v1 != ver) {
- asf->nver[asf_idx] = v1;
- if (vlr->v1 == ver) vlr->v1 = v1;
- if (vlr->v2 == ver) vlr->v2 = v1;
- if (vlr->v3 == ver) vlr->v3 = v1;
- if (vlr->v4 == ver) vlr->v4 = v1;
- }
-}
-
-/* note; autosmooth happens in object space still, after applying autosmooth we rotate */
-/* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
-static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3])
-{
- ASvert *asverts;
- VertRen *ver;
- VlakRen *vlr;
- int a, totvert;
-
- float rot[3][3];
-
- /* Note: For normals, we only want rotation, not scaling component.
- * Negative scales (aka mirroring) give wrong results, see T44102. */
- if (lnors) {
- float mat3[3][3], size[3];
-
- copy_m3_m4(mat3, mat);
- mat3_to_rot_size(rot, size, mat3);
- }
-
- if (obr->totvert == 0)
- return;
-
- totvert = obr->totvert;
- asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts");
-
- if (lnors) {
- /* We construct listbase of all vertices and pointers to faces, and add new verts when needed
- * (i.e. when existing ones do not share the same (loop)normal).
- */
- for (a = 0; a < obr->totvlak; a++, lnors++) {
- vlr = RE_findOrAddVlak(obr, a);
- /* skip wire faces */
- if (vlr->v2 != vlr->v3) {
- as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]);
- as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]);
- as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]);
- if (vlr->v4)
- as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]);
- }
- }
- }
-
- /* free */
- for (a = 0; a < totvert; a++) {
- BLI_freelistN(&asverts[a].faces);
- }
- MEM_freeN(asverts);
-
- /* rotate vertices and calculate normal of faces */
- for (a = 0; a < obr->totvert; a++) {
- ver = RE_findOrAddVert(obr, a);
- mul_m4_v3(mat, ver->co);
- if (lnors) {
- mul_m3_v3(rot, ver->n);
- negate_v3(ver->n);
- }
- }
- for (a = 0; a < obr->totvlak; a++) {
- vlr = RE_findOrAddVlak(obr, a);
-
- /* skip wire faces */
- if (vlr->v2 != vlr->v3) {
- if (vlr->v4)
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Orco hash and Materials */
-/* ------------------------------------------------------------------------- */
-
-static float *get_object_orco(Render *re, void *ob)
-{
- if (!re->orco_hash) {
- return NULL;
- }
-
- return BLI_ghash_lookup(re->orco_hash, ob);
-}
-
-static void set_object_orco(Render *re, void *ob, float *orco)
-{
- if (!re->orco_hash)
- re->orco_hash = BLI_ghash_ptr_new("set_object_orco gh");
-
- BLI_ghash_insert(re->orco_hash, ob, orco);
-}
-
-static void free_mesh_orco_hash(Render *re)
-{
- if (re->orco_hash) {
- BLI_ghash_free(re->orco_hash, NULL, MEM_freeN);
- re->orco_hash = NULL;
- }
-}
-
-static void check_material_mapto(Material *ma)
-{
- int a;
- ma->mapto_textured = 0;
-
- /* cache which inputs are actually textured.
- * this can avoid a bit of time spent iterating through all the texture slots, map inputs and map tos
- * every time a property which may or may not be textured is accessed */
-
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- /* currently used only in volume render, so we'll check for those flags */
- if (ma->mtex[a]->mapto & MAP_DENSITY) ma->mapto_textured |= MAP_DENSITY;
- if (ma->mtex[a]->mapto & MAP_EMISSION) ma->mapto_textured |= MAP_EMISSION;
- if (ma->mtex[a]->mapto & MAP_EMISSION_COL) ma->mapto_textured |= MAP_EMISSION_COL;
- if (ma->mtex[a]->mapto & MAP_SCATTERING) ma->mapto_textured |= MAP_SCATTERING;
- if (ma->mtex[a]->mapto & MAP_TRANSMISSION_COL) ma->mapto_textured |= MAP_TRANSMISSION_COL;
- if (ma->mtex[a]->mapto & MAP_REFLECTION) ma->mapto_textured |= MAP_REFLECTION;
- if (ma->mtex[a]->mapto & MAP_REFLECTION_COL) ma->mapto_textured |= MAP_REFLECTION_COL;
- }
- }
-}
-static void flag_render_node_material(Render *re, bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name)==ID_MA) {
- Material *ma= (Material *)node->id;
-
- if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
- re->flag |= R_ZTRA;
-
- ma->flag |= MA_IS_USED;
- }
- else if (node->type==NODE_GROUP)
- flag_render_node_material(re, (bNodeTree *)node->id);
- }
- }
-}
-
-static Material *give_render_material(Render *re, Object *ob, short nr)
-{
- extern Material defmaterial; /* material.c */
- Material *ma;
-
- ma= give_current_material(ob, nr);
- if (ma==NULL)
- ma= &defmaterial;
-
- if (re->r.mode & R_SPEED) ma->texco |= NEED_UV;
-
- if (ma->material_type == MA_TYPE_VOLUME) {
- ma->mode |= MA_TRANSP;
- ma->mode &= ~MA_SHADBUF;
- }
- if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
- re->flag |= R_ZTRA;
-
- /* for light groups and SSS */
- ma->flag |= MA_IS_USED;
-
- if (ma->nodetree && ma->use_nodes)
- flag_render_node_material(re, ma->nodetree);
-
- check_material_mapto(ma);
-
- return ma;
-}
-
-/* ------------------------------------------------------------------------- */
-/* Particles */
-/* ------------------------------------------------------------------------- */
-typedef struct ParticleStrandData {
- struct MCol *mcol;
- float *orco, *uvco, *surfnor;
- float time, adapt_angle, adapt_pix, size;
- int totuv, totcol;
- int first, line, adapt, override_uv;
-}
-ParticleStrandData;
-/* future thread problem... */
-static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, ParticleStrandData *sd, const float vec[3], const float vec1[3])
-{
- static VertRen *v1= NULL, *v2= NULL;
- VlakRen *vlr= NULL;
- float nor[3], cross[3], crosslen, w, dx, dy, width;
- static float anor[3], avec[3];
- int flag, i;
- static int second=0;
-
- sub_v3_v3v3(nor, vec, vec1);
- normalize_v3(nor); /* nor needed as tangent */
- cross_v3_v3v3(cross, vec, nor);
-
- /* turn cross in pixelsize */
- w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
- dx= re->winx*cross[0]*re->winmat[0][0];
- dy= re->winy*cross[1]*re->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- if (w!=0.0f) {
- float fac;
- if (ma->strand_ease!=0.0f) {
- if (ma->strand_ease<0.0f)
- fac= pow(sd->time, 1.0f+ma->strand_ease);
- else
- fac= pow(sd->time, 1.0f/(1.0f-ma->strand_ease));
- }
- else fac= sd->time;
-
- width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
-
- /* use actual Blender units for strand width and fall back to minimum width */
- if (ma->mode & MA_STR_B_UNITS) {
- crosslen= len_v3(cross);
- w= 2.0f*crosslen*ma->strand_min/w;
-
- if (width < w)
- width= w;
-
- /*cross is the radius of the strand so we want it to be half of full width */
- mul_v3_fl(cross, 0.5f/crosslen);
- }
- else
- width/=w;
-
- mul_v3_fl(cross, width);
- }
-
- if (ma->mode & MA_TANGENT_STR)
- flag= R_SMOOTH|R_TANGENT;
- else
- flag= R_SMOOTH;
-
- /* only 1 pixel wide strands filled in as quads now, otherwise zbuf errors */
- if (ma->strand_sta==1.0f)
- flag |= R_STRAND;
-
- /* single face line */
- if (sd->line) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(vlr->v1->co, vec);
- add_v3_v3(vlr->v1->co, cross);
- copy_v3_v3(vlr->v1->n, nor);
- vlr->v1->orco= sd->orco;
- vlr->v1->accum = -1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v2->co, vec);
- sub_v3_v3v3(vlr->v2->co, vlr->v2->co, cross);
- copy_v3_v3(vlr->v2->n, nor);
- vlr->v2->orco= sd->orco;
- vlr->v2->accum= vlr->v1->accum;
-
- copy_v3_v3(vlr->v4->co, vec1);
- add_v3_v3(vlr->v4->co, cross);
- copy_v3_v3(vlr->v4->n, nor);
- vlr->v4->orco= sd->orco;
- vlr->v4->accum = 1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v3->co, vec1);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
- copy_v3_v3(vlr->v3->n, nor);
- vlr->v3->orco= sd->orco;
- vlr->v3->accum= vlr->v4->accum;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (sd->surfnor) {
- float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
- copy_v3_v3(snor, sd->surfnor);
- }
-
- if (sd->uvco) {
- for (i=0; i<sd->totuv; i++) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
- mtf->uv[0][0]=mtf->uv[1][0]=
- mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
- mtf->uv[0][1]=mtf->uv[1][1]=
- mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
- }
- if (sd->override_uv>=0) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
-
- mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
- mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
-
- mtf->uv[0][1]=mtf->uv[1][1]=0.0f;
- mtf->uv[2][1]=mtf->uv[3][1]=1.0f;
- }
- }
- if (sd->mcol) {
- for (i=0; i<sd->totcol; i++) {
- MCol *mc;
- mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- }
- }
- }
- /* first two vertices of a strand */
- else if (sd->first) {
- if (sd->adapt) {
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- second=1;
- }
-
- v1= RE_findOrAddVert(obr, obr->totvert++);
- v2= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(v1->co, vec);
- add_v3_v3(v1->co, cross);
- copy_v3_v3(v1->n, nor);
- v1->orco= sd->orco;
- v1->accum = -1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(v2->co, vec);
- sub_v3_v3v3(v2->co, v2->co, cross);
- copy_v3_v3(v2->n, nor);
- v2->orco= sd->orco;
- v2->accum= v1->accum;
- }
- /* more vertices & faces to strand */
- else {
- if (sd->adapt==0 || second) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= v1;
- vlr->v2= v2;
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- v1= vlr->v4; /* cycle */
- v2= vlr->v3; /* cycle */
-
-
- if (sd->adapt) {
- second=0;
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- }
-
- }
- else if (sd->adapt) {
- float dvec[3], pvec[3];
- sub_v3_v3v3(dvec, avec, vec);
- project_v3_v3v3(pvec, dvec, vec);
- sub_v3_v3v3(dvec, dvec, pvec);
-
- w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
- dx= re->winx*dvec[0]*re->winmat[0][0]/w;
- dy= re->winy*dvec[1]*re->winmat[1][1]/w;
- w = sqrtf(dx * dx + dy * dy);
- if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= v1;
- vlr->v2= v2;
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- v1= vlr->v4; /* cycle */
- v2= vlr->v3; /* cycle */
-
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- }
- else {
- vlr= RE_findOrAddVlak(obr, obr->totvlak-1);
- }
- }
-
- copy_v3_v3(vlr->v4->co, vec);
- add_v3_v3(vlr->v4->co, cross);
- copy_v3_v3(vlr->v4->n, nor);
- vlr->v4->orco= sd->orco;
- vlr->v4->accum= -1.0f + 2.0f * sd->time; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v3->co, vec);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
- copy_v3_v3(vlr->v3->n, nor);
- vlr->v3->orco= sd->orco;
- vlr->v3->accum= vlr->v4->accum;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (sd->surfnor) {
- float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
- copy_v3_v3(snor, sd->surfnor);
- }
-
- if (sd->uvco) {
- for (i=0; i<sd->totuv; i++) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
- mtf->uv[0][0]=mtf->uv[1][0]=
- mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
- mtf->uv[0][1]=mtf->uv[1][1]=
- mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
- }
- if (sd->override_uv>=0) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
-
- mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
- mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
-
- mtf->uv[0][1]=mtf->uv[1][1]=(vlr->v1->accum+1.0f)/2.0f;
- mtf->uv[2][1]=mtf->uv[3][1]=(vlr->v3->accum+1.0f)/2.0f;
- }
- }
- if (sd->mcol) {
- for (i=0; i<sd->totcol; i++) {
- MCol *mc;
- mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- }
- }
- }
-}
-
-static void static_particle_wire(ObjectRen *obr, Material *ma, const float vec[3], const float vec1[3], int first, int line)
-{
- VlakRen *vlr;
- static VertRen *v1;
-
- if (line) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- copy_v3_v3(vlr->v1->co, vec);
- copy_v3_v3(vlr->v2->co, vec1);
-
- sub_v3_v3v3(vlr->n, vec, vec1);
- normalize_v3(vlr->n);
- copy_v3_v3(vlr->v1->n, vlr->n);
- copy_v3_v3(vlr->v2->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V1V2;
-
- }
- else if (first) {
- v1= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(v1->co, vec);
- }
- else {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= v1;
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- v1= vlr->v2; /* cycle */
- copy_v3_v3(v1->co, vec);
-
- sub_v3_v3v3(vlr->n, vec, vec1);
- normalize_v3(vlr->n);
- copy_v3_v3(v1->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V1V2;
- }
-
-}
-
-static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd,
- const float loc[3], const float loc1[3], int seed, float *pa_co)
-{
- HaloRen *har = NULL;
-
- if (ma->material_type == MA_TYPE_WIRE)
- static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line);
- else if (ma->material_type == MA_TYPE_HALO) {
- har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed, pa_co);
- if (har) har->lay= obr->ob->lay;
- }
- else
- static_particle_strand(re, obr, ma, sd, loc, loc1);
-}
-static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb)
-{
- VlakRen *vlr;
- MTFace *mtf;
- float xvec[3], yvec[3], zvec[3], bb_center[3];
- /* Number of tiles */
- int totsplit = bb->uv_split * bb->uv_split;
- int tile, x, y;
- /* Tile offsets */
- float uvx = 0.0f, uvy = 0.0f, uvdx = 1.0f, uvdy = 1.0f, time = 0.0f;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
-
- add_v3_v3v3(vlr->v1->co, bb_center, xvec);
- add_v3_v3(vlr->v1->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v1->co);
-
- sub_v3_v3v3(vlr->v2->co, bb_center, xvec);
- add_v3_v3(vlr->v2->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v2->co);
-
- sub_v3_v3v3(vlr->v3->co, bb_center, xvec);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v3->co);
-
- add_v3_v3v3(vlr->v4->co, bb_center, xvec);
- sub_v3_v3(vlr->v4->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v4->co);
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- copy_v3_v3(vlr->v1->n, vlr->n);
- copy_v3_v3(vlr->v2->n, vlr->n);
- copy_v3_v3(vlr->v3->n, vlr->n);
- copy_v3_v3(vlr->v4->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (bb->uv_split > 1) {
- uvdx = uvdy = 1.0f / (float)bb->uv_split;
-
- if (ELEM(bb->anim, PART_BB_ANIM_AGE, PART_BB_ANIM_FRAME)) {
- if (bb->anim == PART_BB_ANIM_FRAME)
- time = ((int)(bb->time * bb->lifetime) % totsplit)/(float)totsplit;
- else
- time = bb->time;
- }
- else if (bb->anim == PART_BB_ANIM_ANGLE) {
- if (bb->align == PART_BB_VIEW) {
- time = (float)fmod((bb->tilt + 1.0f) / 2.0f, 1.0);
- }
- else {
- float axis1[3] = {0.0f, 0.0f, 0.0f};
- float axis2[3] = {0.0f, 0.0f, 0.0f};
-
- axis1[(bb->align + 1) % 3] = 1.0f;
- axis2[(bb->align + 2) % 3] = 1.0f;
-
- if (bb->lock == 0) {
- zvec[bb->align] = 0.0f;
- normalize_v3(zvec);
- }
-
- time = saacos(dot_v3v3(zvec, axis1)) / (float)M_PI;
-
- if (dot_v3v3(zvec, axis2) < 0.0f)
- time = 1.0f - time / 2.0f;
- else
- time /= 2.0f;
- }
- }
-
- if (bb->split_offset == PART_BB_OFF_LINEAR)
- time = (float)fmod(time + (float)bb->num / (float)totsplit, 1.0f);
- else if (bb->split_offset==PART_BB_OFF_RANDOM)
- time = (float)fmod(time + bb->random, 1.0f);
-
- /* Find the coordinates in tile space (integer), then convert to UV
- * space (float). Note that Y is flipped. */
- tile = (int)((time + FLT_EPSILON10) * totsplit);
- x = tile % bb->uv_split;
- y = tile / bb->uv_split;
- y = (bb->uv_split - 1) - y;
- uvx = uvdx * x;
- uvy = uvdy * y;
- }
-
- /* normal UVs */
- if (bb->uv[0] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[0], NULL, 1);
- mtf->uv[0][0] = 1.0f;
- mtf->uv[0][1] = 1.0f;
- mtf->uv[1][0] = 0.0f;
- mtf->uv[1][1] = 1.0f;
- mtf->uv[2][0] = 0.0f;
- mtf->uv[2][1] = 0.0f;
- mtf->uv[3][0] = 1.0f;
- mtf->uv[3][1] = 0.0f;
- }
-
- /* time-index UVs */
- if (bb->uv[1] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[1], NULL, 1);
- mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = bb->time;
- mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = (float)bb->num/(float)bb->totnum;
- }
-
- /* split UVs */
- if (bb->uv_split > 1 && bb->uv[2] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[2], NULL, 1);
- mtf->uv[0][0] = uvx + uvdx;
- mtf->uv[0][1] = uvy + uvdy;
- mtf->uv[1][0] = uvx;
- mtf->uv[1][1] = uvy + uvdy;
- mtf->uv[2][0] = uvx;
- mtf->uv[2][1] = uvy;
- mtf->uv[3][0] = uvx + uvdx;
- mtf->uv[3][1] = uvy;
- }
-}
-static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize, float *pa_co)
-{
- float loc[3], loc0[3], loc1[3], vel[3];
-
- copy_v3_v3(loc, state->co);
-
- if (ren_as != PART_DRAW_BB)
- mul_m4_v3(re->viewmat, loc);
-
- switch (ren_as) {
- case PART_DRAW_LINE:
- sd->line = 1;
- sd->time = 0.0f;
- sd->size = hasize;
-
- mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
- normalize_v3(vel);
-
- if (part->draw & PART_DRAW_VEL_LENGTH)
- mul_v3_fl(vel, len_v3(state->vel));
-
- madd_v3_v3v3fl(loc0, loc, vel, -part->draw_line[0]);
- madd_v3_v3v3fl(loc1, loc, vel, part->draw_line[1]);
-
- particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed, pa_co);
-
- break;
-
- case PART_DRAW_BB:
-
- copy_v3_v3(bb->vec, loc);
- copy_v3_v3(bb->vel, state->vel);
-
- particle_billboard(re, obr, ma, bb);
-
- break;
-
- default:
- {
- HaloRen *har = NULL;
-
- har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed, pa_co);
-
- if (har) har->lay= obr->ob->lay;
-
- break;
- }
- }
-}
-static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd)
-{
- int i;
-
- /* get uvco */
- if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- for (i=0; i<sd->totuv; i++) {
- if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i);
- mtface += num;
-
- psys_interpolate_uvs(mtface, mface->v4, fuv, sd->uvco + 2 * i);
- }
- else {
- sd->uvco[2*i] = 0.0f;
- sd->uvco[2*i + 1] = 0.0f;
- }
- }
- }
-
- /* get mcol */
- if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- for (i=0; i<sd->totcol; i++) {
- if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
- MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
- mc += num * 4;
-
- psys_interpolate_mcol(mc, mface->v4, fuv, sd->mcol + i);
- }
- else
- memset(&sd->mcol[i], 0, sizeof(MCol));
- }
- }
-}
-static int render_new_particle_system(Depsgraph *depsgraph, Render *re,
- ObjectRen *obr, ParticleSystem *psys, int timeoffset)
-{
- Object *ob= obr->ob;
-// Object *tob=0;
- Material *ma = NULL;
- ParticleSystemModifierData *psmd;
- ParticleSystem *tpsys = NULL;
- ParticleSettings *part, *tpart = NULL;
- ParticleData *pars, *pa = NULL, *tpa = NULL;
- ParticleKey *states = NULL;
- ParticleKey state;
- ParticleCacheKey *cache = NULL;
- ParticleBillboardData bb;
- ParticleSimulationData sim = {NULL};
- ParticleStrandData sd;
- StrandBuffer *strandbuf = NULL;
- StrandVert *svert = NULL;
- StrandBound *sbound = NULL;
- StrandRen *strand = NULL;
- RNG *rng = NULL;
- float loc[3], loc1[3], loc0[3], mat[4][4], nmat[3][3], co[3], nor[3], duplimat[4][4];
- float strandlen=0.0f, curlen=0.0f;
- float hasize, pa_size, r_tilt, r_length;
- float pa_time, pa_birthtime, pa_dietime;
- float random, pa_co[3];
- const float cfra= BKE_scene_frame_get(re->scene);
- int i, a, k, max_k=0, totpart;
- bool do_surfacecache = false, use_duplimat = false;
- int totchild=0, step_nbr;
- int seed, path_nbr=0, orco1=0, num;
- int totface;
-
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
-
-/* 1. check that everything is ok & updated */
- if (psys==NULL)
- return 0;
-
- part=psys->part;
- pars=psys->particles;
-
- if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering))
- return 0;
-
- if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
- return 1;
-
- if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT))
- return 0;
-
- if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL)
- return 0;
-
-/* 2. start initializing things */
-
- /* last possibility to bail out! */
- psmd = psys_get_modifier(ob, psys);
- if (!(psmd->modifier.mode & eModifierMode_Render))
- return 0;
-
- sim.depsgraph = depsgraph;
- sim.scene = re->scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = psmd;
-
- if (part->phystype==PART_PHYS_KEYED)
- psys_count_keyed_targets(&sim);
-
- totchild=psys->totchild;
-
- /* can happen for disconnected/global hair */
- if (part->type==PART_HAIR && !psys->childcache)
- totchild= 0;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */
- totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- step_nbr = 1 << part->draw_step;
- }
- else {
- step_nbr = 1 << part->ren_step;
- }
- if (ELEM(part->kink, PART_KINK_SPIRAL))
- step_nbr += part->kink_extra_steps;
-
- psys->flag |= PSYS_DRAWING;
-
- rng= BLI_rng_new(psys->seed);
-
- totpart=psys->totpart;
-
- memset(&sd, 0, sizeof(ParticleStrandData));
- sd.override_uv = -1;
-
-/* 2.1 setup material stff */
- ma= give_render_material(re, ob, part->omat);
-
-#if 0 /* XXX old animation system */
- if (ma->ipo) {
- calc_ipo(ma->ipo, cfra);
- execute_ipo((ID *)ma, ma->ipo);
- }
-#endif /* XXX old animation system */
-
- hasize = ma->hasize;
- seed = ma->seed1;
-
- re->flag |= R_HALO;
-
- RE_set_customdata_names(obr, &psmd->dm_final->faceData);
- sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE);
- sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL);
-
- if (ma->texco & TEXCO_UV && sd.totuv) {
- sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs");
-
- if (ma->strand_uvname[0]) {
- sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname);
- sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
- }
- }
- else
- sd.uvco = NULL;
-
- if (sd.totcol)
- sd.mcol = MEM_callocN(sd.totcol * sizeof(MCol), "particle_mcols");
-
-/* 2.2 setup billboards */
- if (part->ren_as == PART_DRAW_BB) {
- int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
-
- bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]);
- if (bb.uv[0] < 0)
- bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
-
- bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]);
-
- bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]);
-
- if (first_uv >= 0) {
- bb.uv[0] -= first_uv;
- bb.uv[1] -= first_uv;
- bb.uv[2] -= first_uv;
- }
-
- bb.align = part->bb_align;
- bb.anim = part->bb_anim;
- bb.lock = part->draw & PART_DRAW_BB_LOCK;
- bb.ob = (part->bb_ob ? part->bb_ob : RE_GetCamera(re));
- bb.split_offset = part->bb_split_offset;
- bb.totnum = totpart+totchild;
- bb.uv_split = part->bb_uv_split;
- }
-
-/* 2.5 setup matrices */
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat); /* need to be that way, for imat texture */
- transpose_m3_m4(nmat, ob->imat);
-
- if (psys->flag & PSYS_USE_IMAT) {
- /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */
- mul_m4_m4m4(duplimat, ob->obmat, psys->imat);
- use_duplimat = true;
- }
-
-/* 2.6 setup strand rendering */
- if (part->ren_as == PART_DRAW_PATH && psys->pathcache) {
- path_nbr = step_nbr;
-
- if (path_nbr) {
- if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) {
- sd.orco = get_object_orco(re, psys);
- if (!sd.orco) {
- sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
- set_object_orco(re, psys, sd.orco);
- }
- }
- }
-
- if (part->draw & PART_DRAW_REN_ADAPT) {
- sd.adapt = 1;
- sd.adapt_pix = (float)part->adapt_pix;
- sd.adapt_angle = cosf(DEG2RADF((float)part->adapt_angle));
- }
-
- if (part->draw & PART_DRAW_REN_STRAND) {
- strandbuf= RE_addStrandBuffer(obr, (totpart+totchild)*(path_nbr+1));
- strandbuf->ma= ma;
- strandbuf->lay= ob->lay;
- copy_m4_m4(strandbuf->winmat, re->winmat);
- strandbuf->winx= re->winx;
- strandbuf->winy= re->winy;
- strandbuf->maxdepth= 2;
- strandbuf->adaptcos= cosf(DEG2RADF((float)part->adapt_angle));
- strandbuf->overrideuv= sd.override_uv;
- strandbuf->minwidth= ma->strand_min;
-
- if (ma->strand_widthfade == 0.0f)
- strandbuf->widthfade= -1.0f;
- else if (ma->strand_widthfade >= 1.0f)
- strandbuf->widthfade= 2.0f - ma->strand_widthfade;
- else
- strandbuf->widthfade= 1.0f/MAX2(ma->strand_widthfade, 1e-5f);
-
- if (part->flag & PART_HAIR_BSPLINE)
- strandbuf->flag |= R_STRAND_BSPLINE;
- if (ma->mode & MA_STR_B_UNITS)
- strandbuf->flag |= R_STRAND_B_UNITS;
-
- svert= strandbuf->vert;
-
- if (re->r.mode & R_SPEED)
- do_surfacecache = true;
- else if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
- if (ma->amb != 0.0f)
- do_surfacecache = true;
-
- totface= psmd->dm_final->getNumTessFaces(psmd->dm_final);
- index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX);
- index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
- for (a=0; a<totface; a++)
- strandbuf->totbound = max_ii(strandbuf->totbound, (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a): a);
-
- strandbuf->totbound++;
- strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
- sbound= strandbuf->bound;
- sbound->start= sbound->end= 0;
- }
- }
-
- if (sd.orco == NULL) {
- sd.orco = MEM_mallocN(3 * sizeof(float), "particle orco");
- orco1 = 1;
- }
-
- if (path_nbr == 0)
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
-/* 3. start creating renderable things */
- for (a=0, pa=pars; a<totpart+totchild; a++, pa++, seed++) {
- random = BLI_rng_get_float(rng);
- /* setup per particle individual stuff */
- if (a<totpart) {
- if (pa->flag & PARS_UNEXIST) continue;
-
- pa_time=(cfra-pa->time)/pa->lifetime;
- pa_birthtime = pa->time;
- pa_dietime = pa->dietime;
-
- hasize = ma->hasize;
-
- /* XXX 'tpsys' is alwyas NULL, this code won't run! */
- /* get orco */
- if (tpsys && part->phystype == PART_PHYS_NO) {
- tpa = tpsys->particles + pa->num;
- psys_particle_on_emitter(
- psmd,
- tpart->from, tpa->num, pa->num_dmcache, tpa->fuv,
- tpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
- else {
- psys_particle_on_emitter(
- psmd,
- part->from, pa->num, pa->num_dmcache,
- pa->fuv, pa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
-
- /* get uvco & mcol */
- num= pa->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
- num= pa->num;
-
- get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd);
-
- pa_size = pa->size;
-
- r_tilt = 2.0f*(psys_frand(psys, a) - 0.5f);
- r_length = psys_frand(psys, a+1);
-
- if (path_nbr) {
- cache = psys->pathcache[a];
- max_k = (int)cache->segments;
- }
-
- if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
- }
- else {
- ChildParticle *cpa= psys->child+a-totpart;
-
- if (path_nbr) {
- cache = psys->childcache[a-totpart];
-
- if (cache->segments < 0)
- continue;
-
- max_k = (int)cache->segments;
- }
-
- pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
- pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);
-
- r_tilt = 2.0f*(psys_frand(psys, a + 21) - 0.5f);
- r_length = psys_frand(psys, a + 22);
-
- num = cpa->num;
-
- /* get orco */
- if (part->childtype == PART_CHILD_FACES) {
- psys_particle_on_emitter(
- psmd,
- PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD,
- cpa->fuv, cpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
- else {
- ParticleData *par = psys->particles + cpa->parent;
- psys_particle_on_emitter(
- psmd,
- part->from, par->num, DMCACHE_ISCHILD, par->fuv,
- par->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
-
- /* get uvco & mcol */
- if (part->childtype==PART_CHILD_FACES) {
- get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd);
- }
- else {
- ParticleData *parent = psys->particles + cpa->parent;
- num = parent->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
- num = parent->num;
-
- get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd);
- }
-
- if (strandbuf) {
- int orignum = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, cpa->num) : cpa->num;
-
- if ((orignum > sbound - strandbuf->bound) &&
- (orignum < strandbuf->totbound))
- {
- sbound = &strandbuf->bound[orignum];
- sbound->start = sbound->end = obr->totstrand;
- }
- }
- }
-
- /* TEXCO_PARTICLE */
- pa_co[0] = pa_time;
- pa_co[1] = 0.f;
- pa_co[2] = 0.f;
-
- /* surface normal shading setup */
- if (ma->mode_l & MA_STR_SURFDIFF) {
- mul_m3_v3(nmat, nor);
- sd.surfnor= nor;
- }
- else
- sd.surfnor= NULL;
-
- /* strand render setup */
- if (strandbuf) {
- strand= RE_findOrAddStrand(obr, obr->totstrand++);
- strand->buffer= strandbuf;
- strand->vert= svert;
- copy_v3_v3(strand->orco, sd.orco);
-
- if (sd.surfnor) {
- float *snor= RE_strandren_get_surfnor(obr, strand, 1);
- copy_v3_v3(snor, sd.surfnor);
- }
-
- if (do_surfacecache && num >= 0) {
- int *facenum= RE_strandren_get_face(obr, strand, 1);
- *facenum= num;
- }
-
- if (sd.uvco) {
- for (i=0; i<sd.totuv; i++) {
- if (i != sd.override_uv) {
- float *uv= RE_strandren_get_uv(obr, strand, i, NULL, 1);
-
- uv[0]= sd.uvco[2*i];
- uv[1]= sd.uvco[2*i+1];
- }
- }
- }
- if (sd.mcol) {
- for (i=0; i<sd.totcol; i++) {
- MCol *mc= RE_strandren_get_mcol(obr, strand, i, NULL, 1);
- *mc = sd.mcol[i];
- }
- }
-
- sbound->end++;
- }
-
- /* strandco computation setup */
- if (path_nbr) {
- strandlen= 0.0f;
- curlen= 0.0f;
- for (k=1; k<=path_nbr; k++)
- if (k<=max_k)
- strandlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
- }
-
- if (path_nbr) {
- /* render strands */
- for (k=0; k<=path_nbr; k++) {
- float time;
-
- if (k<=max_k) {
- copy_v3_v3(state.co, (cache+k)->co);
- copy_v3_v3(state.vel, (cache+k)->vel);
- }
- else
- continue;
-
- if (k > 0)
- curlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
- time= curlen/strandlen;
-
- copy_v3_v3(loc, state.co);
- mul_m4_v3(re->viewmat, loc);
-
- if (strandbuf) {
- copy_v3_v3(svert->co, loc);
- svert->strandco= -1.0f + 2.0f*time;
- svert++;
- strand->totvert++;
- }
- else {
- sd.size = hasize;
-
- if (k==1) {
- sd.first = 1;
- sd.time = 0.0f;
- sub_v3_v3v3(loc0, loc1, loc);
- add_v3_v3v3(loc0, loc1, loc0);
-
- particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co);
- }
-
- sd.first = 0;
- sd.time = time;
-
- if (k)
- particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co);
-
- copy_v3_v3(loc1, loc);
- }
- }
-
- }
- else {
- /* render normal particles */
- if (part->trail_count > 1) {
- float length = part->path_end * (1.0f - part->randlength * r_length);
- int trail_count = part->trail_count * (1.0f - part->randlength * r_length);
- float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time;
- float dt = length / (trail_count ? (float)trail_count : 1.0f);
-
- /* make sure we have pointcache in memory before getting particle on path */
- psys_make_temp_pointcache(ob, psys);
-
- for (i=0; i < trail_count; i++, ct -= dt) {
- if (part->draw & PART_ABS_PATH_TIME) {
- if (ct < pa_birthtime || ct > pa_dietime)
- continue;
- }
- else if (ct < 0.0f || ct > 1.0f)
- continue;
-
- state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
- psys_get_particle_on_path(&sim, a, &state, 1);
-
- if (psys->parent)
- mul_m4_v3(psys->parent->obmat, state.co);
-
- if (use_duplimat)
- mul_m4_v4(duplimat, state.co);
-
- if (part->ren_as == PART_DRAW_BB) {
- bb.random = random;
- bb.offset[0] = part->bb_offset[0];
- bb.offset[1] = part->bb_offset[1];
- bb.size[0] = part->bb_size[0] * pa_size;
- if (part->bb_align==PART_BB_VEL) {
- float pa_vel = len_v3(state.vel);
- float head = part->bb_vel_head*pa_vel;
- float tail = part->bb_vel_tail*pa_vel;
- bb.size[1] = part->bb_size[1]*pa_size + head + tail;
- /* use offset to adjust the particle center. this is relative to size, so need to divide! */
- if (bb.size[1] > 0.0f)
- bb.offset[1] += (head-tail) / bb.size[1];
- }
- else
- bb.size[1] = part->bb_size[1] * pa_size;
- bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
- bb.time = ct;
- bb.num = a;
- }
-
- pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct;
- pa_co[1] = (float)i/(float)(trail_count-1);
-
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
- }
- }
- else {
- state.time=cfra;
- if (psys_get_particle_state(&sim, a, &state, 0)==0)
- continue;
-
- if (psys->parent)
- mul_m4_v3(psys->parent->obmat, state.co);
-
- if (use_duplimat)
- mul_m4_v3(duplimat, state.co);
-
- if (part->ren_as == PART_DRAW_BB) {
- bb.random = random;
- bb.offset[0] = part->bb_offset[0];
- bb.offset[1] = part->bb_offset[1];
- bb.size[0] = part->bb_size[0] * pa_size;
- if (part->bb_align==PART_BB_VEL) {
- float pa_vel = len_v3(state.vel);
- float head = part->bb_vel_head*pa_vel;
- float tail = part->bb_vel_tail*pa_vel;
- bb.size[1] = part->bb_size[1]*pa_size + head + tail;
- /* use offset to adjust the particle center. this is relative to size, so need to divide! */
- if (bb.size[1] > 0.0f)
- bb.offset[1] += (head-tail) / bb.size[1];
- }
- else
- bb.size[1] = part->bb_size[1] * pa_size;
- bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
- bb.time = pa_time;
- bb.num = a;
- bb.lifetime = pa_dietime-pa_birthtime;
- }
-
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
- }
- }
-
- if (orco1==0)
- sd.orco+=3;
-
- if (re->test_break(re->tbh))
- break;
- }
-
- if (do_surfacecache)
- strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset);
-
-/* 4. clean up */
-#if 0 /* XXX old animation system */
- if (ma) do_mat_ipo(re->scene, ma);
-#endif /* XXX old animation system */
-
- if (orco1)
- MEM_freeN(sd.orco);
-
- if (sd.uvco)
- MEM_freeN(sd.uvco);
-
- if (sd.mcol)
- MEM_freeN(sd.mcol);
-
- if (states)
- MEM_freeN(states);
-
- BLI_rng_free(rng);
-
- psys->flag &= ~PSYS_DRAWING;
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
- if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0)
- calc_vertexnormals(re, obr, 1, 0, 0);
-
- return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-/* Halo's */
-/* ------------------------------------------------------------------------- */
-
-static void make_render_halos(Render *re, ObjectRen *obr, Mesh *UNUSED(me), int totvert, MVert *mvert, Material *ma, float *orco)
-{
- Object *ob= obr->ob;
- HaloRen *har;
- float xn, yn, zn, nor[3], view[3];
- float vec[3], hasize, mat[4][4], imat[3][3];
- int a, ok, seed= ma->seed1;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- copy_m3_m4(imat, ob->imat);
-
- re->flag |= R_HALO;
-
- for (a=0; a<totvert; a++, mvert++) {
- ok= 1;
-
- if (ok) {
- hasize= ma->hasize;
-
- copy_v3_v3(vec, mvert->co);
- mul_m4_v3(mat, vec);
-
- if (ma->mode & MA_HALOPUNO) {
- xn= mvert->no[0];
- yn= mvert->no[1];
- zn= mvert->no[2];
-
- /* transpose ! */
- nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(nor);
-
- copy_v3_v3(view, vec);
- normalize_v3(view);
-
- zn = dot_v3v3(nor, view);
- if (zn>=0.0f) hasize= 0.0f;
- else hasize*= zn*zn*zn*zn;
- }
-
- if (orco) har= RE_inithalo(re, obr, ma, vec, NULL, orco, hasize, 0.0, seed);
- else har= RE_inithalo(re, obr, ma, vec, NULL, mvert->co, hasize, 0.0, seed);
- if (har) har->lay= ob->lay;
- }
- if (orco) orco+= 3;
- seed++;
- }
-}
-
-static int verghalo(const void *a1, const void *a2)
-{
- const HaloRen *har1= *(const HaloRen**)a1;
- const HaloRen *har2= *(const HaloRen**)a2;
-
- if (har1->zs < har2->zs) return 1;
- else if (har1->zs > har2->zs) return -1;
- return 0;
-}
-
-static void sort_halos(Render *re, int totsort)
-{
- ObjectRen *obr;
- HaloRen *har= NULL, **haso;
- int a;
-
- if (re->tothalo==0) return;
-
- re->sortedhalos= MEM_callocN(sizeof(HaloRen*)*re->tothalo, "sorthalos");
- haso= re->sortedhalos;
-
- 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++;
-
- *(haso++)= har;
- }
- }
-
- qsort(re->sortedhalos, totsort, sizeof(HaloRen*), verghalo);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Displacement Mapping */
-/* ------------------------------------------------------------------------- */
-
-static short test_for_displace(Render *re, Object *ob)
-{
- /* return 1 when this object uses displacement textures. */
- Material *ma;
- int i;
-
- for (i=1; i<=ob->totcol; i++) {
- ma=give_render_material(re, ob, i);
- /* ma->mapto is ORed total of all mapto channels */
- if (ma && (ma->mapto & MAP_DISPLACE)) return 1;
- }
- return 0;
-}
-
-static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
-{
- MTFace *tface;
- short texco= shi->mat->texco;
- float sample=0, displace[3];
- char *name;
- int i;
-
- /* shi->co is current render coord, just make sure at least some vector is here */
- copy_v3_v3(shi->co, vr->co);
- /* vertex normal is used for textures type 'col' and 'var' */
- copy_v3_v3(shi->vn, vr->n);
-
- if (texco & TEXCO_UV) {
- shi->totuv= 0;
- shi->actuv= obr->actmtface;
-
- for (i=0; (tface=RE_vlakren_get_tface(obr, shi->vlr, i, &name, 0)); i++) {
- ShadeInputUV *suv= &shi->uv[i];
-
- /* shi.uv needs scale correction from tface uv */
- suv->uv[0]= 2*tface->uv[vindex][0]-1.0f;
- suv->uv[1]= 2*tface->uv[vindex][1]-1.0f;
- suv->uv[2]= 0.0f;
- suv->name= name;
- shi->totuv++;
- }
- }
-
- /* set all rendercoords, 'texco' is an ORed value for all textures needed */
- if ((texco & TEXCO_ORCO) && (vr->orco)) {
- copy_v3_v3(shi->lo, vr->orco);
- }
- if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(re->viewinv, shi->gl);
- }
- if (texco & TEXCO_NORM) {
- copy_v3_v3(shi->orn, shi->vn);
- }
- if (texco & TEXCO_REFL) {
- /* not (yet?) */
- }
- if (texco & TEXCO_STRESS) {
- const float *s= RE_vertren_get_stress(obr, vr, 0);
-
- if (s) {
- shi->stress= *s;
- if (shi->stress<1.0f) shi->stress-= 1.0f;
- else shi->stress= (shi->stress-1.0f)/shi->stress;
- }
- else
- shi->stress= 0.0f;
- }
-
- shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
-
- do_material_tex(shi, re);
-
- //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2],
- //vr->co[0], vr->co[1], vr->co[2]);
-
- displace[0]= shi->displace[0] * scale[0];
- displace[1]= shi->displace[1] * scale[1];
- displace[2]= shi->displace[2] * scale[2];
-
- /* 0.5 could become button once? */
- vr->co[0] += displace[0];
- vr->co[1] += displace[1];
- vr->co[2] += displace[2];
-
- //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]);
-
- /* we just don't do this vertex again, bad luck for other face using same vertex with
- * different material... */
- vr->flag |= 1;
-
- /* Pass sample back so displace_face can decide which way to split the quad */
- sample = shi->displace[0]*shi->displace[0];
- sample += shi->displace[1]*shi->displace[1];
- sample += shi->displace[2]*shi->displace[2];
-
- vr->accum=sample;
- /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */
- return;
-}
-
-static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale)
-{
- ShadeInput shi;
-
- /* Warning, This is not that nice, and possibly a bit slow,
- * however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
- memset(&shi, 0, sizeof(ShadeInput));
- /* end warning! - Campbell */
-
- /* set up shadeinput struct for multitex() */
-
- /* memset above means we don't need this */
- /*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */
-
- shi.obr= obr;
- shi.vlr= vlr; /* current render face */
- shi.mat= vlr->mat; /* current input material */
- shi.thread= 0;
-
- /* TODO, assign these, displacement with new bumpmap is skipped without - campbell */
-#if 0
- /* order is not known ? */
- shi.v1= vlr->v1;
- shi.v2= vlr->v2;
- shi.v3= vlr->v3;
-#endif
-
- /* Displace the verts, flag is set when done */
- if (!vlr->v1->flag)
- displace_render_vert(re, obr, &shi, vlr->v1, 0, scale);
-
- if (!vlr->v2->flag)
- displace_render_vert(re, obr, &shi, vlr->v2, 1, scale);
-
- if (!vlr->v3->flag)
- displace_render_vert(re, obr, &shi, vlr->v3, 2, scale);
-
- if (vlr->v4) {
- if (!vlr->v4->flag)
- displace_render_vert(re, obr, &shi, vlr->v4, 3, scale);
-
- /* closest in displace value. This will help smooth edges. */
- if (fabsf(vlr->v1->accum - vlr->v3->accum) > fabsf(vlr->v2->accum - vlr->v4->accum)) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
- }
-
- /* Recalculate the face normal - if flipped before, flip now */
- if (vlr->v4) {
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
- else {
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
-}
-
-static void displace(Render *re, ObjectRen *obr)
-{
- VertRen *vr;
- VlakRen *vlr;
-// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30};
- float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn
- int i; //, texflag=0;
- Object *obt;
-
- /* Object Size with parenting */
- obt=obr->ob;
- while (obt) {
- mul_v3_v3v3(temp, obt->size, obt->dscale);
- scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2];
- obt=obt->parent;
- }
-
- /* Clear all flags */
- for (i=0; i<obr->totvert; i++) {
- vr= RE_findOrAddVert(obr, i);
- vr->flag= 0;
- }
-
- for (i=0; i<obr->totvlak; i++) {
- vlr=RE_findOrAddVlak(obr, i);
- displace_render_face(re, obr, vlr, scale);
- }
-
- /* Recalc vertex normals */
- calc_vertexnormals(re, obr, 1, 0, 0);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Metaball */
-/* ------------------------------------------------------------------------- */
-
-static void init_render_mball(Depsgraph *depsgraph, Render *re, ObjectRen *obr)
-{
- Object *ob= obr->ob;
- DispList *dl;
- VertRen *ver;
- VlakRen *vlr, *vlr1;
- Material *ma;
- float *data, *nors, *orco=NULL, mat[4][4], imat[3][3], xn, yn, zn;
- int a, need_orco, vlakindex, *index, negative_scale;
- ListBase dispbase= {NULL, NULL};
-
- if (ob!=BKE_mball_basis_find(re->scene, ob))
- return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- copy_m3_m4(imat, ob->imat);
- negative_scale = is_negative_m4(mat);
-
- ma= give_render_material(re, ob, 1);
-
- need_orco= 0;
- if (ma->texco & TEXCO_ORCO) {
- need_orco= 1;
- }
-
- BKE_displist_make_mball_forRender(depsgraph, re->scene, ob, &dispbase);
- dl= dispbase.first;
- if (dl == NULL) return;
-
- data= dl->verts;
- nors= dl->nors;
- if (need_orco) {
- orco= get_object_orco(re, ob);
-
- if (!orco) {
- /* orco hasn't been found in cache - create new one and add to cache */
- orco= BKE_mball_make_orco(ob, &dispbase);
- set_object_orco(re, ob, orco);
- }
- }
-
- for (a=0; a<dl->nr; a++, data+=3, nors+=3) {
-
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data);
- mul_m4_v3(mat, ver->co);
-
- /* render normals are inverted */
- xn= -nors[0];
- yn= -nors[1];
- zn= -nors[2];
-
- /* transpose ! */
- ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(ver->n);
- //if (ob->transflag & OB_NEG_SCALE) negate_v3(ver->n);
-
- if (need_orco) {
- ver->orco= orco;
- orco+=3;
- }
- }
-
- index= dl->index;
- for (a=0; a<dl->parts; a++, index+=4) {
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, index[0]);
- vlr->v2= RE_findOrAddVert(obr, index[1]);
- vlr->v3= RE_findOrAddVert(obr, index[2]);
- vlr->v4 = NULL;
-
- if (negative_scale)
- normal_tri_v3(vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co);
- else
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->flag= ME_SMOOTH;
- vlr->ec= 0;
-
- /* mball -too bad- always has triangles, because quads can be non-planar */
- if (index[3] && index[3]!=index[2]) {
- vlr1= RE_findOrAddVlak(obr, obr->totvlak++);
- vlakindex= vlr1->index;
- *vlr1= *vlr;
- vlr1->index= vlakindex;
- vlr1->v2= vlr1->v3;
- vlr1->v3= RE_findOrAddVert(obr, index[3]);
- if (negative_scale)
- normal_tri_v3(vlr1->n, vlr1->v1->co, vlr1->v2->co, vlr1->v3->co);
- else
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
- }
- }
-
- /* enforce display lists remade */
- BKE_displist_free(&dispbase);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Surfaces and Curves */
-/* ------------------------------------------------------------------------- */
-
-/* returns amount of vertices added for orco */
-static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar, float *orco, float mat[4][4])
-{
- VertRen *v1, *v2, *v3, *v4, *ver;
- VlakRen *vlr, *vlr1, *vlr2, *vlr3;
- float *data, n1[3];
- int u, v, orcoret= 0;
- int p1, p2, p3, p4, a;
- int sizeu, nsizeu, sizev, nsizev;
- int startvert, startvlak;
-
- startvert= obr->totvert;
- nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr;
-
- data= dl->verts;
- for (u = 0; u < sizeu; u++) {
- v1 = RE_findOrAddVert(obr, obr->totvert++); /* save this for possible V wrapping */
- copy_v3_v3(v1->co, data); data += 3;
- if (orco) {
- v1->orco= orco; orco+= 3; orcoret++;
- }
- mul_m4_v3(mat, v1->co);
-
- for (v = 1; v < sizev; v++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data); data += 3;
- if (orco) {
- ver->orco= orco; orco+= 3; orcoret++;
- }
- mul_m4_v3(mat, ver->co);
- }
- /* if V-cyclic, add extra vertices at end of the row */
- if (dl->flag & DL_CYCL_U) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, v1->co);
- if (orco) {
- ver->orco= orco; orco+=3; orcoret++; //orcobase + 3*(u*sizev + 0);
- }
- }
- }
-
- /* Done before next loop to get corner vert */
- if (dl->flag & DL_CYCL_U) nsizev++;
- if (dl->flag & DL_CYCL_V) nsizeu++;
-
- /* if U cyclic, add extra row at end of column */
- if (dl->flag & DL_CYCL_V) {
- for (v = 0; v < nsizev; v++) {
- v1= RE_findOrAddVert(obr, startvert + v);
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, v1->co);
- if (orco) {
- ver->orco= orco; orco+=3; orcoret++; //ver->orco= orcobase + 3*(0*sizev + v);
- }
- }
- }
-
- sizeu = nsizeu;
- sizev = nsizev;
-
- startvlak= obr->totvlak;
-
- for (u = 0; u < sizeu - 1; u++) {
- p1 = startvert + u * sizev; /* walk through face list */
- p2 = p1 + 1;
- p3 = p2 + sizev;
- p4 = p3 - 1;
-
- for (v = 0; v < sizev - 1; v++) {
- v1= RE_findOrAddVert(obr, p1);
- v2= RE_findOrAddVert(obr, p2);
- v3= RE_findOrAddVert(obr, p3);
- v4= RE_findOrAddVert(obr, p4);
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
-
- normal_quad_v3(n1, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- copy_v3_v3(vlr->n, n1);
-
- vlr->mat= matar[ dl->col];
- vlr->ec= ME_V1V2+ME_V2V3;
- vlr->flag= dl->rt;
-
- add_v3_v3(v1->n, n1);
- add_v3_v3(v2->n, n1);
- add_v3_v3(v3->n, n1);
- add_v3_v3(v4->n, n1);
-
- p1++; p2++; p3++; p4++;
- }
- }
- /* fix normals for U resp. V cyclic faces */
- sizeu--; sizev--; /* dec size for face array */
- if (dl->flag & DL_CYCL_V) {
-
- for (v = 0; v < sizev; v++) {
- /* optimize! :*/
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, v));
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, v));
- add_v3_v3(vlr1->v1->n, vlr->n);
- add_v3_v3(vlr1->v2->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr1->n);
- add_v3_v3(vlr->v4->n, vlr1->n);
- }
- }
- if (dl->flag & DL_CYCL_U) {
-
- for (u = 0; u < sizeu; u++) {
- /* optimize! :*/
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(u, 0));
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(u, sizev-1));
- add_v3_v3(vlr1->v2->n, vlr->n);
- add_v3_v3(vlr1->v3->n, vlr->n);
- add_v3_v3(vlr->v1->n, vlr1->n);
- add_v3_v3(vlr->v4->n, vlr1->n);
- }
- }
-
- /* last vertex is an extra case:
- *
- * ^ ()----()----()----()
- * | | | || |
- * u | |(0,n)||(0,0)|
- * | | || |
- * ()====()====[]====()
- * | | || |
- * | |(m,n)||(m,0)|
- * | | || |
- * ()----()----()----()
- * v ->
- *
- * vertex [] is no longer shared, therefore distribute
- * normals of the surrounding faces to all of the duplicates of []
- */
-
- if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)) {
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m, n) */
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, 0)); /* (0, 0) */
- add_v3_v3v3(n1, vlr->n, vlr1->n);
- vlr2= RE_findOrAddVlak(obr, UVTOINDEX(0, sizev-1)); /* (0, n) */
- add_v3_v3(n1, vlr2->n);
- vlr3= RE_findOrAddVlak(obr, UVTOINDEX(sizeu-1, 0)); /* (m, 0) */
- add_v3_v3(n1, vlr3->n);
- copy_v3_v3(vlr->v3->n, n1);
- copy_v3_v3(vlr1->v1->n, n1);
- copy_v3_v3(vlr2->v2->n, n1);
- copy_v3_v3(vlr3->v4->n, n1);
- }
- for (a = startvert; a < obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
-
-
- return orcoret;
-}
-
-static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
- int timeoffset, float *orco, float mat[4][4])
-{
- Object *ob= obr->ob;
- int a, end, totvert, vertofs;
- short mat_iter;
- VertRen *ver;
- VlakRen *vlr;
- MVert *mvert = NULL;
- MFace *mface;
- Material *ma;
-#ifdef WITH_FREESTYLE
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
- FreestyleFace *ffa = NULL;
-#endif
- /* Curve *cu= ELEM(ob->type, OB_FONT, OB_CURVE) ? ob->data : NULL; */
-
- mvert= dm->getVertArray(dm);
- totvert= dm->getNumVerts(dm);
-
- for (a=0; a<totvert; a++, mvert++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, mvert->co);
- mul_m4_v3(mat, ver->co);
-
- if (orco) {
- ver->orco= orco;
- orco+=3;
- }
- }
-
- if (!timeoffset) {
- /* store customdata names, because DerivedMesh is freed */
- RE_set_customdata_names(obr, &dm->faceData);
-
- /* still to do for keys: the correct local texture coordinate */
-
- /* faces in order of color blocks */
- vertofs= obr->totvert - totvert;
- for (mat_iter= 0; (mat_iter < ob->totcol || (mat_iter==0 && ob->totcol==0)); mat_iter++) {
-
- ma= give_render_material(re, ob, mat_iter+1);
- end= dm->getNumTessFaces(dm);
- mface= dm->getTessFaceArray(dm);
-
-#ifdef WITH_FREESTYLE
- if (ob->type == OB_MESH) {
- Mesh *me= ob->data;
- index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
- ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
- }
-#endif
-
- for (a=0; a<end; a++, mface++) {
- int v1, v2, v3, v4, flag;
-
- if (mface->mat_nr == mat_iter) {
- float len;
-
- v1= mface->v1;
- v2= mface->v2;
- v3= mface->v3;
- v4= mface->v4;
- flag= mface->flag & ME_SMOOTH;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
- vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
- if (v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4);
- else vlr->v4 = NULL;
-
- /* render normals are inverted in render */
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->flag= flag;
- vlr->ec= 0; /* mesh edges rendered separately */
-#ifdef WITH_FREESTYLE
- if (ffa) {
- int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
- vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
- }
- else {
- vlr->freestyle_face_mark= 0;
- }
-#endif
-
- if (len==0) obr->totvlak--;
- else {
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn= 0, mcn= 0;
- char *name;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
- mtface= (MTFace*)layer->data;
- *mtf= mtface[a];
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
- mcol= (MCol*)layer->data;
- memcpy(mc, &mcol[a*4], sizeof(MCol)*4);
- }
- }
- }
- }
- }
- }
-
- /* Normals */
- calc_vertexnormals(re, obr, 1, 0, 0);
- }
-
-}
-
-static void init_render_surf(Depsgraph *depsgraph, Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Nurb *nu = NULL;
- Curve *cu;
- ListBase displist= {NULL, NULL};
- DispList *dl;
- Material **matar;
- float *orco=NULL, mat[4][4];
- int a, totmat;
- bool need_orco = false;
- DerivedMesh *dm= NULL;
-
- cu= ob->data;
- nu= cu->nurb.first;
- if (nu == NULL) return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
-
- /* material array */
- totmat= ob->totcol+1;
- matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
-
- for (a=0; a<totmat; a++) {
- matar[a]= give_render_material(re, ob, a+1);
-
- if (matar[a] && matar[a]->texco & TEXCO_ORCO)
- need_orco= 1;
- }
-
- if (ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1;
-
- BKE_displist_make_surf(depsgraph, re->scene, ob, &displist, &dm, 1, 0, 1);
-
- if (dm) {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco= BKE_displist_make_orco(depsgraph, re->scene, ob, dm, true, true);
- if (orco) {
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- init_render_dm(dm, re, obr, timeoffset, orco, mat);
- dm->release(dm);
- }
- else {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_curve_surf_make_orco(ob);
- set_object_orco(re, ob, orco);
- }
- }
-
- /* walk along displaylist and create rendervertices/-faces */
- for (dl=displist.first; dl; dl=dl->next) {
- /* watch out: u ^= y, v ^= x !! */
- if (dl->type==DL_SURF)
- orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
- }
- }
-
- BKE_displist_free(&displist);
-
- MEM_freeN(matar);
-}
-
-static void init_render_curve(Depsgraph *depsgraph, Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Curve *cu;
- VertRen *ver;
- VlakRen *vlr;
- DispList *dl;
- DerivedMesh *dm = NULL;
- ListBase disp={NULL, NULL};
- Material **matar;
- float *data, *fp, *orco=NULL;
- float n[3], mat[4][4], nmat[4][4];
- int nr, startvert, a, b, negative_scale;
- bool need_orco = false;
- int totmat;
-
- cu= ob->data;
- if (ob->type==OB_FONT && cu->str==NULL) return;
- else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return;
-
- BKE_displist_make_curveTypes_forRender(depsgraph, re->scene, ob, &disp, &dm, false, true);
- dl= disp.first;
- if (dl==NULL) return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- negative_scale = is_negative_m4(mat);
-
- /* local object -> world space transform for normals */
- transpose_m4_m4(nmat, mat);
- invert_m4(nmat);
-
- /* material array */
- totmat= ob->totcol+1;
- matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
-
- for (a=0; a<totmat; a++) {
- matar[a]= give_render_material(re, ob, a+1);
-
- if (matar[a] && matar[a]->texco & TEXCO_ORCO)
- need_orco= 1;
- }
-
- if (dm) {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_displist_make_orco(depsgraph, re->scene, ob, dm, true, true);
- if (orco) {
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- init_render_dm(dm, re, obr, timeoffset, orco, mat);
- dm->release(dm);
- }
- else {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_curve_make_orco(depsgraph, re->scene, ob, NULL);
- set_object_orco(re, ob, orco);
- }
- }
-
- while (dl) {
- if (dl->col > ob->totcol) {
- /* pass */
- }
- else if (dl->type==DL_INDEX3) {
- const int *index;
-
- startvert= obr->totvert;
- data= dl->verts;
-
- for (a=0; a<dl->nr; a++, data+=3) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data);
-
- mul_m4_v3(mat, ver->co);
-
- if (orco) {
- ver->orco = orco;
- orco += 3;
- }
- }
-
- if (timeoffset==0) {
- float tmp[3];
- const int startvlak= obr->totvlak;
-
- zero_v3(n);
- index= dl->index;
- for (a=0; a<dl->parts; a++, index+=3) {
- int v1 = index[0], v2 = index[2], v3 = index[1];
- float *co1 = &dl->verts[v1 * 3],
- *co2 = &dl->verts[v2 * 3],
- *co3 = &dl->verts[v3 * 3];
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, startvert + v1);
- vlr->v2= RE_findOrAddVert(obr, startvert + v2);
- vlr->v3= RE_findOrAddVert(obr, startvert + v3);
- vlr->v4= NULL;
-
- /* to prevent float accuracy issues, we calculate normal in local object space (not world) */
- if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) {
- if (negative_scale == false) {
- add_v3_v3(n, tmp);
- }
- else {
- sub_v3_v3(n, tmp);
- }
- }
-
- vlr->mat= matar[ dl->col ];
- vlr->flag= 0;
- vlr->ec= 0;
- }
-
- /* transform normal to world space */
- mul_m4_v3(nmat, n);
- normalize_v3(n);
-
- /* vertex normals */
- for (a= startvlak; a<obr->totvlak; a++) {
- vlr= RE_findOrAddVlak(obr, a);
-
- copy_v3_v3(vlr->n, n);
- add_v3_v3(vlr->v1->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr->n);
- add_v3_v3(vlr->v2->n, vlr->n);
- }
- for (a=startvert; a<obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
- }
- }
- else if (dl->type==DL_SURF) {
-
- /* cyclic U means an extruded full circular curve, we skip bevel splitting then */
- if (dl->flag & DL_CYCL_U) {
- orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
- }
- else {
- int p1, p2, p3, p4;
-
- fp= dl->verts;
- startvert= obr->totvert;
- nr= dl->nr*dl->parts;
-
- while (nr--) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(ver->co, fp);
- mul_m4_v3(mat, ver->co);
- fp+= 3;
-
- if (orco) {
- ver->orco = orco;
- orco += 3;
- }
- }
-
- if (dl->flag & DL_CYCL_V && orco) {
- fp = dl->verts;
- nr = dl->nr;
- while (nr--) {
- ver = RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, fp);
- mul_m4_v3(mat, ver->co);
- ver->orco = orco;
- fp += 3;
- orco += 3;
- }
- }
-
- if (dl->bevel_split || timeoffset == 0) {
- const int startvlak= obr->totvlak;
-
- for (a=0; a<dl->parts; a++) {
-
- if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4)==0)
- break;
-
- p1+= startvert;
- p2+= startvert;
- p3+= startvert;
- p4+= startvert;
-
- if (dl->flag & DL_CYCL_V && orco && a == dl->parts - 1) {
- p3 = p1 + dl->nr;
- p4 = p2 + dl->nr;
- }
-
- for (; b<dl->nr; b++) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- /* important 1 offset in order is kept [#24913] */
- vlr->v1= RE_findOrAddVert(obr, p2);
- vlr->v2= RE_findOrAddVert(obr, p1);
- vlr->v3= RE_findOrAddVert(obr, p3);
- vlr->v4= RE_findOrAddVert(obr, p4);
- vlr->ec= ME_V2V3+ME_V3V4;
- if (a==0) vlr->ec+= ME_V1V2;
-
- vlr->flag= dl->rt;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- vlr->mat= matar[ dl->col ];
-
- p4= p3;
- p3++;
- p2= p1;
- p1++;
- }
- }
-
- if (dl->bevel_split) {
- for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
- if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
- split_v_renderfaces(
- obr, startvlak, startvert, dl->parts, dl->nr, a,
- /* intentionally swap (v, u) --> (u, v) */
- dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
- }
- }
- }
-
- /* vertex normals */
- for (a= startvlak; a<obr->totvlak; a++) {
- vlr= RE_findOrAddVlak(obr, a);
-
- add_v3_v3(vlr->v1->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr->n);
- add_v3_v3(vlr->v2->n, vlr->n);
- add_v3_v3(vlr->v4->n, vlr->n);
- }
- for (a=startvert; a<obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
- }
- }
- }
-
- dl= dl->next;
- }
- }
-
- BKE_displist_free(&disp);
-
- MEM_freeN(matar);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Mesh */
-/* ------------------------------------------------------------------------- */
-
-struct edgesort {
- unsigned int v1, v2;
- int f;
- unsigned int i1, i2;
-};
-
-/* edges have to be added with lowest index first for sorting */
-static void to_edgesort(struct edgesort *ed,
- unsigned int i1, unsigned int i2,
- unsigned int v1, unsigned int v2, int f)
-{
- if (v1 > v2) {
- SWAP(unsigned int, v1, v2);
- SWAP(unsigned int, i1, i2);
- }
-
- ed->v1= v1;
- ed->v2= v2;
- ed->i1= i1;
- ed->i2= i2;
- ed->f = f;
-}
-
-static int vergedgesort(const void *v1, const void *v2)
-{
- const struct edgesort *x1=v1, *x2=v2;
-
- if ( x1->v1 > x2->v1) return 1;
- else if ( x1->v1 < x2->v1) return -1;
- else if ( x1->v2 > x2->v2) return 1;
- else if ( x1->v2 < x2->v2) return -1;
-
- return 0;
-}
-
-static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
-{
- MFace *mf, *mface;
- MTFace *tface=NULL;
- struct edgesort *edsort, *ed;
- unsigned int *mcol=NULL;
- int a, totedge=0, totface;
-
- mface= dm->getTessFaceArray(dm);
- totface= dm->getNumTessFaces(dm);
- tface= dm->getTessFaceDataArray(dm, CD_MTFACE);
- mcol= dm->getTessFaceDataArray(dm, CD_MCOL);
-
- if (mcol==NULL && tface==NULL) return NULL;
-
- /* make sorted table with edges and face indices in it */
- for (a= totface, mf= mface; a>0; a--, mf++) {
- totedge += mf->v4 ? 4 : 3;
- }
-
- if (totedge==0)
- return NULL;
-
- ed= edsort= MEM_callocN(totedge*sizeof(struct edgesort), "edgesort");
-
- for (a=0, mf=mface; a<totface; a++, mf++) {
- to_edgesort(ed++, 0, 1, mf->v1, mf->v2, a);
- to_edgesort(ed++, 1, 2, mf->v2, mf->v3, a);
- if (mf->v4) {
- to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
- to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
- }
- else {
- to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
- }
- }
-
- qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
-
- *totedgesort= totedge;
-
- return edsort;
-}
-
-static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge)
-{
- struct edgesort ed, *edp;
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn, mcn;
- char *name;
-
- if (medge->v1 < medge->v2) {
- ed.v1= medge->v1;
- ed.v2= medge->v2;
- }
- else {
- ed.v1= medge->v2;
- ed.v2= medge->v1;
- }
-
- edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort);
-
- /* since edges have different index ordering, we have to duplicate mcol and tface */
- if (edp) {
- mtfn= mcn= 0;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- mtface= &((MTFace*)layer->data)[edp->f];
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
-
- *mtf= *mtface;
-
- memcpy(mtf->uv[0], mtface->uv[edp->i1], sizeof(float)*2);
- memcpy(mtf->uv[1], mtface->uv[edp->i2], sizeof(float)*2);
- memcpy(mtf->uv[2], mtface->uv[1], sizeof(float)*2);
- memcpy(mtf->uv[3], mtface->uv[1], sizeof(float)*2);
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mcol= &((MCol*)layer->data)[edp->f*4];
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
-
- mc[0]= mcol[edp->i1];
- mc[1]= mc[2]= mc[3]= mcol[edp->i2];
- }
- }
- }
-}
-
-static void free_camera_inside_volumes(Render *re)
-{
- BLI_freelistN(&re->render_volumes_inside);
-}
-
-static void init_camera_inside_volumes(Render *re)
-{
- ObjectInstanceRen *obi;
- VolumeOb *vo;
- /* coordinates are all in camera space, so camera coordinate is zero. we also
- * add an offset for the clip start, however note that with clip start it's
- * actually impossible to do a single 'inside' test, since there will not be
- * a single point where all camera rays start from, though for small clip start
- * they will be close together. */
- float co[3] = {0.f, 0.f, -re->clipsta};
-
- for (vo= re->volumes.first; vo; vo= vo->next) {
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->obr == vo->obr) {
- if (point_inside_volume_objectinstance(re, obi, co)) {
- MatInside *mi;
-
- mi = MEM_mallocN(sizeof(MatInside), "camera inside material");
- mi->ma = vo->ma;
- mi->obi = obi;
-
- BLI_addtail(&(re->render_volumes_inside), mi);
- }
- }
- }
- }
-
-
-#if 0 /* debug */
- {
- MatInside *m;
- for (m = re->render_volumes_inside.first; m; m = m->next) {
- printf("matinside: ma: %s\n", m->ma->id.name + 2);
- }
- }
-#endif
-}
-
-static void add_volume(Render *re, ObjectRen *obr, Material *ma)
-{
- struct VolumeOb *vo;
-
- vo = MEM_mallocN(sizeof(VolumeOb), "volume object");
-
- vo->ma = ma;
- vo->obr = obr;
-
- BLI_addtail(&re->volumes, vo);
-}
-
-#ifdef WITH_FREESTYLE
-static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm)
-{
- EdgeHash *edge_hash= NULL;
- FreestyleEdge *fed;
- MEdge *medge;
- int totedge, a;
-
- medge = dm->getEdgeArray(dm);
- totedge = dm->getNumEdges(dm);
- fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE);
- if (fed) {
- edge_hash = BLI_edgehash_new(__func__);
- for (a = 0; a < totedge; a++) {
- if (fed[a].flag & FREESTYLE_EDGE_MARK)
- BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
- }
- }
- return edge_hash;
-}
-
-static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
-{
- MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
- return (!medge) ? 0 : 1;
-}
-#endif
-
-static void init_render_mesh(Depsgraph *depsgraph, Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Mesh *me;
- MVert *mvert = NULL;
- MFace *mface;
- VlakRen *vlr; //, *vlr1;
- VertRen *ver;
- Material *ma;
- DerivedMesh *dm;
- CustomDataMask mask;
- float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
- float *orco = NULL;
- short (*loop_nors)[4][3] = NULL;
- bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
- bool need_nmap_tangent_concrete = false;
- int a, a1, ok, vertofs;
- int end, totvert = 0;
- bool do_autosmooth = false, do_displace = false;
- bool use_original_normals = false;
- int recalc_normals = 0; /* false by default */
- int negative_scale;
-#ifdef WITH_FREESTYLE
- FreestyleFace *ffa;
-#endif
-
- me= ob->data;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- copy_m3_m4(imat, ob->imat);
- negative_scale= is_negative_m4(mat);
-
- need_orco= 0;
- for (a=1; a<=ob->totcol; a++) {
- ma= give_render_material(re, ob, a);
- if (ma) {
- if (ma->texco & (TEXCO_ORCO|TEXCO_STRESS))
- need_orco= 1;
- if (ma->texco & TEXCO_STRESS)
- need_stress= 1;
- /* normalmaps, test if tangents needed, separated from shading */
- if (ma->mode_l & MA_TANGENT_V) {
- need_tangent= 1;
- if (me->mloopuv==NULL)
- need_orco= 1;
- }
- if (ma->mode_l & MA_NORMAP_TANG) {
- if (me->mloopuv==NULL) {
- need_orco= 1;
- }
- need_tangent= 1;
- }
- if (ma->mode2_l & MA_TANGENT_CONCRETE) {
- need_nmap_tangent_concrete = true;
- }
- }
- }
-
- if (re->flag & R_NEED_TANGENT) {
- /* exception for tangent space baking */
- if (me->mloopuv==NULL) {
- need_orco= 1;
- }
- need_tangent= 1;
- }
-
- /* check autosmooth and displacement, we then have to skip only-verts optimize
- * Note: not sure what we want to give higher priority, currently do_displace
- * takes precedence over do_autosmooth.
- */
- do_displace = test_for_displace(re, ob);
- do_autosmooth = ((me->flag & ME_AUTOSMOOTH) != 0) && !do_displace;
- if (do_autosmooth || do_displace)
- timeoffset = 0;
-
- /* origindex currently used when using autosmooth, or baking to vertex colors. */
- need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL)));
-
- mask = CD_MASK_RENDER_INTERNAL;
- if (!timeoffset)
- if (need_orco)
- mask |= CD_MASK_ORCO;
-
-#ifdef WITH_FREESTYLE
- mask |= CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
-#endif
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm= mesh_create_derived_view(depsgraph, re->scene, ob, mask);
- else
- dm= mesh_create_derived_render(depsgraph, re->scene, ob, mask);
- if (dm==NULL) return; /* in case duplicated object fails? */
-
- mvert= dm->getVertArray(dm);
- totvert= dm->getNumVerts(dm);
-
- if (totvert == 0) {
- dm->release(dm);
- return;
- }
-
- if (mask & CD_MASK_ORCO) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco= dm->getVertDataArray(dm, CD_ORCO);
- if (orco) {
- orco= MEM_dupallocN(orco);
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- /* attempt to autsmooth on original mesh, only without subsurf */
- if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
- use_original_normals= true;
-
- ma= give_render_material(re, ob, 1);
-
-
- if (ma->material_type == MA_TYPE_HALO) {
- make_render_halos(re, obr, me, totvert, mvert, ma, orco);
- }
- else {
- const int *index_vert_orig = NULL;
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
- if (need_origindex) {
- index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
- /* double lookup for faces -> polys */
-#ifdef WITH_FREESTYLE
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-#endif
- }
-
- for (a=0; a<totvert; a++, mvert++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, mvert->co);
- if (do_autosmooth == false) { /* autosmooth on original unrotated data to prevent differences between frames */
- normal_short_to_float_v3(ver->n, mvert->no);
- mul_m4_v3(mat, ver->co);
- mul_transposed_m3_v3(imat, ver->n);
- normalize_v3(ver->n);
- negate_v3(ver->n);
- }
-
- if (orco) {
- ver->orco= orco;
- orco+=3;
- }
-
- if (need_origindex) {
- int *origindex;
- origindex = RE_vertren_get_origindex(obr, ver, 1);
-
- /* Use orig index array if it's available (e.g. in the presence
- * of modifiers). */
- if (index_vert_orig)
- *origindex = index_vert_orig[a];
- else
- *origindex = a;
- }
- }
-
- if (!timeoffset) {
- short (*lnp)[4][3] = NULL;
-#ifdef WITH_FREESTYLE
- EdgeHash *edge_hash;
-
- /* create a hash table of Freestyle edge marks */
- edge_hash = make_freestyle_edge_mark_hash(dm);
-#endif
-
- /* store customdata names, because DerivedMesh is freed */
- RE_set_customdata_names(obr, &dm->faceData);
-
- /* add tangent layers if we need */
- if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
- dm->calcLoopTangents(
- dm, need_tangent,
- (const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
- obr->tangent_mask = dm->tangent_mask;
- DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
- }
-
- /* still to do for keys: the correct local texture coordinate */
-
- /* faces in order of color blocks */
- vertofs= obr->totvert - totvert;
- for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
-
- ma= give_render_material(re, ob, a1+1);
-
- /* test for 100% transparent */
- ok = 1;
- if ((ma->alpha == 0.0f) &&
- (ma->spectra == 0.0f) &&
- /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
- /* (ma->filter == 0.0f) && */
- (ma->mode & MA_TRANSP) &&
- (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
- {
- ok = 0;
- /* texture on transparency? */
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- if (ma->mtex[a]->mapto & MAP_ALPHA) ok= 1;
- }
- }
- }
-
- /* if wire material, and we got edges, don't do the faces */
- if (ma->material_type == MA_TYPE_WIRE) {
- end= dm->getNumEdges(dm);
- if (end) ok= 0;
- }
-
- if (ok) {
- end= dm->getNumTessFaces(dm);
- mface= dm->getTessFaceArray(dm);
- if (!loop_nors && do_autosmooth &&
- (dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL) != NULL))
- {
- lnp = loop_nors = MEM_mallocN(sizeof(*loop_nors) * end, __func__);
- }
-#ifdef WITH_FREESTYLE
- index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
- ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
-#endif
-
- for (a=0; a<end; a++, mface++) {
- int v1, v2, v3, v4, flag;
-
- if ( mface->mat_nr==a1 ) {
- float len;
- bool reverse_verts = (negative_scale != 0 && do_autosmooth == false);
- int rev_tab[] = {reverse_verts==0 ? 0 : 2, 1, reverse_verts==0 ? 2 : 0, 3};
- v1= reverse_verts==0 ? mface->v1 : mface->v3;
- v2= mface->v2;
- v3= reverse_verts==0 ? mface->v3 : mface->v1;
- v4= mface->v4;
- flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
- vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
- if (v4) vlr->v4 = RE_findOrAddVert(obr, vertofs+v4);
- else vlr->v4 = NULL;
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge/face marks */
- if (edge_hash) {
- int edge_mark = 0;
-
- if (has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2;
- if (has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3;
- if (!v4) {
- if (has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1;
- }
- else {
- if (has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4;
- if (has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1;
- }
- vlr->freestyle_edge_mark= edge_mark;
- }
- if (ffa) {
- int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
- vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
- }
- else {
- vlr->freestyle_face_mark= 0;
- }
-#endif
-
- /* render normals are inverted in render */
- if (use_original_normals) {
- MFace *mf= me->mface+a;
- MVert *mv= me->mvert;
-
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, mv[mf->v4].co, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
- else
- len= normal_tri_v3(vlr->n, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
- }
- else {
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
-
- vlr->mat= ma;
- vlr->flag= flag;
- vlr->ec= 0; /* mesh edges rendered separately */
-
- if (len==0) obr->totvlak--;
- else {
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn= 0, mcn= 0, mln = 0, vindex;
- char *name;
- int nr_verts = v4!=0 ? 4 : 3;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- int t;
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
- mtface= (MTFace*)layer->data;
- *mtf = mtface[a]; /* copy face info */
- for (vindex=0; vindex<nr_verts; vindex++)
- for (t=0; t<2; t++)
- mtf->uv[vindex][t]=mtface[a].uv[rev_tab[vindex]][t];
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
- mcol= (MCol*)layer->data;
- for (vindex=0; vindex<nr_verts; vindex++)
- mc[vindex]=mcol[a*4+rev_tab[vindex]];
- }
- else if (layer->type == CD_TANGENT) {
- if (need_nmap_tangent_concrete || need_tangent) {
- int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
- int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
-
- /* if there are no UVs, orco tangents are in first slot */
- int n = (uv_start >= 0 && uv_index >= 0) ? uv_index - uv_start : 0;
-
- const float *tangent = (const float *) layer->data;
- float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
-
- for (vindex=0; vindex<nr_verts; vindex++) {
- copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
- mul_mat3_m4_v3(mat, ftang+vindex*4);
- normalize_v3(ftang+vindex*4);
- }
- }
- }
- else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
- if (loop_nors) {
- const short (*lnors)[4][3] = (const short (*)[4][3])layer->data;
- for (vindex = 0; vindex < 4; vindex++) {
- //print_v3("lnors[a][rev_tab[vindex]]", lnors[a][rev_tab[vindex]]);
- copy_v3_v3_short((short *)lnp[0][vindex], lnors[a][rev_tab[vindex]]);
- /* If we copy loop normals, we are doing autosmooth, so we are still
- * in object space, no need to multiply with mat!
- */
- }
- lnp++;
- }
- mln++;
- }
- }
-
- if (need_origindex) {
- /* Find original index of mpoly for this tessface. Options:
- * - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly
- * - OR Tesselated mesh; look up from tessface -> mpoly
- * - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */
- int *origindex;
- origindex = RE_vlakren_get_origindex(obr, vlr, 1);
- if (index_mf_to_mpoly && index_mp_to_orig)
- *origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a);
- else if (index_mf_to_mpoly)
- *origindex = index_mf_to_mpoly[a];
- else
- *origindex = a;
- }
- }
- }
- }
- }
- }
-
-#ifdef WITH_FREESTYLE
- /* release the hash table of Freestyle edge marks */
- if (edge_hash)
- BLI_edgehash_free(edge_hash, NULL);
-#endif
-
- /* exception... we do edges for wire mode. potential conflict when faces exist... */
- end= dm->getNumEdges(dm);
- mvert= dm->getVertArray(dm);
- ma= give_render_material(re, ob, 1);
- if (end && (ma->material_type == MA_TYPE_WIRE)) {
- MEdge *medge;
- struct edgesort *edgetable;
- int totedge= 0;
- recalc_normals= 1;
-
- medge= dm->getEdgeArray(dm);
-
- /* we want edges to have UV and vcol too... */
- edgetable= make_mesh_edge_lookup(dm, &totedge);
-
- for (a1=0; a1<end; a1++, medge++) {
- if (medge->flag&ME_EDGERENDER) {
- MVert *v0 = &mvert[medge->v1];
- MVert *v1 = &mvert[medge->v2];
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+medge->v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+medge->v2);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- if (edgetable)
- use_mesh_edge_lookup(obr, dm, medge, vlr, edgetable, totedge);
-
- xn= -(v0->no[0]+v1->no[0]);
- yn= -(v0->no[1]+v1->no[1]);
- zn= -(v0->no[2]+v1->no[2]);
- /* transpose ! */
- vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(vlr->n);
-
- vlr->mat= ma;
- vlr->flag= 0;
- vlr->ec= ME_V1V2;
- }
- }
- if (edgetable)
- MEM_freeN(edgetable);
- }
- }
- }
-
- if (!timeoffset) {
- if (need_stress)
- calc_edge_stress(re, obr, me);
-
- if (do_displace) {
- calc_vertexnormals(re, obr, 1, 0, 0);
- displace(re, obr);
- recalc_normals = 0; /* Already computed by displace! */
- }
- else if (do_autosmooth) {
- recalc_normals = (loop_nors == NULL); /* Should never happen, but better be safe than sorry. */
- autosmooth(re, obr, mat, loop_nors);
- }
-
- if (recalc_normals!=0 || need_tangent!=0)
- calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
- }
-
- MEM_SAFE_FREE(loop_nors);
-
- dm->release(dm);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Lamps and Shadowbuffers */
-/* ------------------------------------------------------------------------- */
-
-static void initshadowbuf(Render *re, LampRen *lar, float mat[4][4])
-{
- struct ShadBuf *shb;
- float viewinv[4][4];
-
- /* if (la->spsi<16) return; */
-
- /* memory alloc */
- shb= (struct ShadBuf *)MEM_callocN(sizeof(struct ShadBuf), "initshadbuf");
- lar->shb= shb;
-
- if (shb==NULL) return;
-
- VECCOPY(shb->co, lar->co); /* int copy */
-
- /* percentage render: keep track of min and max */
- shb->size= (lar->bufsize*re->r.size)/100;
-
- if (shb->size<512) shb->size= 512;
- else if (shb->size > lar->bufsize) shb->size= lar->bufsize;
-
- shb->size &= ~15; /* make sure its multiples of 16 */
-
- shb->samp= lar->samp;
- shb->soft= lar->soft;
- shb->shadhalostep= lar->shadhalostep;
-
- normalize_m4(mat);
- invert_m4_m4(shb->winmat, mat); /* winmat is temp */
-
- /* matrix: combination of inverse view and lampmat */
- /* calculate again: the ortho-render has no correct viewinv */
- invert_m4_m4(viewinv, re->viewmat);
- mul_m4_m4m4(shb->viewmat, shb->winmat, viewinv);
-
- /* projection */
- shb->d= lar->clipsta;
- shb->clipend= lar->clipend;
-
- /* bias is percentage, made 2x larger because of correction for angle of incidence */
- /* when a ray is closer to parallel of a face, bias value is increased during render */
- shb->bias= (0.02f*lar->bias)*0x7FFFFFFF;
-
- /* halfway method (average of first and 2nd z) reduces bias issues */
- if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
- shb->bias= 0.1f*shb->bias;
-
- shb->compressthresh= lar->compressthresh;
-}
-
-void area_lamp_vectors(LampRen *lar)
-{
- float xsize= 0.5f*lar->area_size, ysize= 0.5f*lar->area_sizey, multifac;
-
- /* make it smaller, so area light can be multisampled */
- multifac= 1.0f/sqrtf((float)lar->ray_totsamp);
- xsize *= multifac;
- ysize *= multifac;
-
- /* corner vectors */
- lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
- /* only for correction button size, matrix size works on energy */
- lar->areasize= lar->dist*lar->dist/(4.0f*xsize*ysize);
-}
-
-/* If lar takes more lamp data, the decoupling will be better. */
-static GroupObject *add_render_lamp(Render *re, Object *ob)
-{
- Lamp *la= ob->data;
- LampRen *lar;
- GroupObject *go;
- float mat[4][4], angle, xn, yn;
- float vec[3];
- int c;
-
- /* previewrender sets this to zero... prevent accidents */
- if (la==NULL) return NULL;
-
- /* prevent only shadow from rendering light */
- if (la->mode & LA_ONLYSHADOW)
- if ((re->r.mode & R_SHADOW)==0)
- return NULL;
-
- re->totlamp++;
-
- /* groups is used to unify support for lightgroups, this is the global lightgroup */
- go= MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&re->lights, go);
- go->ob= ob;
- /* lamprens are in own list, for freeing */
- lar= (LampRen *)MEM_callocN(sizeof(LampRen), "lampren");
- BLI_addtail(&re->lampren, lar);
- go->lampren= lar;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
-
- copy_m4_m4(lar->lampmat, ob->obmat);
- copy_m3_m4(lar->mat, mat);
- copy_m3_m4(lar->imat, ob->imat);
-
- lar->bufsize = la->bufsize;
- lar->samp = la->samp;
- lar->buffers= la->buffers;
- if (lar->buffers==0) lar->buffers= 1;
- lar->buftype= la->buftype;
- lar->filtertype= la->filtertype;
- lar->soft = la->soft;
- lar->shadhalostep = la->shadhalostep;
- lar->clipsta = la->clipsta;
- lar->clipend = la->clipend;
-
- lar->bias = la->bias;
- lar->compressthresh = la->compressthresh;
-
- lar->type= la->type;
- lar->mode= la->mode;
-
- lar->energy= la->energy;
- if (la->mode & LA_NEG) lar->energy= -lar->energy;
-
- lar->vec[0]= -mat[2][0];
- lar->vec[1]= -mat[2][1];
- lar->vec[2]= -mat[2][2];
- normalize_v3(lar->vec);
- lar->co[0]= mat[3][0];
- lar->co[1]= mat[3][1];
- lar->co[2]= mat[3][2];
- lar->dist= la->dist;
- lar->haint= la->haint;
- lar->distkw= lar->dist*lar->dist;
- lar->r= lar->energy*la->r;
- lar->g= lar->energy*la->g;
- lar->b= lar->energy*la->b;
- lar->shdwr= la->shdwr;
- lar->shdwg= la->shdwg;
- lar->shdwb= la->shdwb;
- lar->k= la->k;
-
- /* area */
- lar->ray_samp= la->ray_samp;
- lar->ray_sampy= la->ray_sampy;
- lar->ray_sampz= la->ray_sampz;
-
- lar->area_size= la->area_size;
- lar->area_sizey= la->area_sizey;
- lar->area_sizez= la->area_sizez;
-
- lar->area_shape= la->area_shape;
-
- /* Annoying, lamp UI does this, but the UI might not have been used? - add here too.
- * make sure this matches buttons_shading.c's logic */
- if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
- if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
- if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
-
- lar->ray_samp_method= la->ray_samp_method;
- lar->ray_samp_type= la->ray_samp_type;
-
- lar->adapt_thresh= la->adapt_thresh;
- lar->sunsky = NULL;
-
- if ( ELEM(lar->type, LA_SPOT, LA_LOCAL)) {
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->area_shape = LA_AREA_SQUARE;
- lar->area_sizey= lar->area_size;
- }
- else if (lar->type==LA_AREA) {
- switch (lar->area_shape) {
- case LA_AREA_SQUARE:
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->ray_sampy= lar->ray_samp;
- lar->area_sizey= lar->area_size;
- break;
- case LA_AREA_RECT:
- lar->ray_totsamp= lar->ray_samp*lar->ray_sampy;
- break;
- case LA_AREA_CUBE:
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp;
- lar->ray_sampy= lar->ray_samp;
- lar->ray_sampz= lar->ray_samp;
- lar->area_sizey= lar->area_size;
- lar->area_sizez= lar->area_size;
- break;
- case LA_AREA_BOX:
- lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz;
- break;
- }
-
- area_lamp_vectors(lar);
- init_jitter_plane(lar); /* subsamples */
- }
- else if (lar->type==LA_SUN) {
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->area_shape = LA_AREA_SQUARE;
- lar->area_sizey= lar->area_size;
-
- if ((la->sun_effect_type & LA_SUN_EFFECT_SKY) ||
- (la->sun_effect_type & LA_SUN_EFFECT_AP))
- {
- lar->sunsky = (struct SunSky*)MEM_callocN(sizeof(struct SunSky), "sunskyren");
- lar->sunsky->effect_type = la->sun_effect_type;
-
- copy_v3_v3(vec, ob->obmat[2]);
- normalize_v3(vec);
-
- InitSunSky(
- lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness,
- la->spread, la->sun_brightness, la->sun_size, la->backscattered_light,
- la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace);
- InitAtmosphere(
- lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor,
- la->atm_distance_factor);
- }
- }
- else lar->ray_totsamp= 0;
-
- lar->spotsi= la->spotsize;
- if (lar->mode & LA_HALO) {
- if (lar->spotsi > DEG2RADF(170.0f)) lar->spotsi = DEG2RADF(170.0f);
- }
- lar->spotsi= cosf(lar->spotsi * 0.5f);
- lar->spotbl= (1.0f-lar->spotsi)*la->spotblend;
-
- memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *));
-
- lar->lay = ob->lay & 0xFFFFFF; /* higher 8 bits are localview layers */
-
- lar->falloff_type = la->falloff_type;
- lar->ld1= la->att1;
- lar->ld2= la->att2;
- lar->coeff_const= la->coeff_const;
- lar->coeff_lin= la->coeff_lin;
- lar->coeff_quad= la->coeff_quad;
- lar->curfalloff = curvemapping_copy(la->curfalloff);
-
- if (lar->curfalloff) {
- /* so threads don't conflict on init */
- curvemapping_initialize(lar->curfalloff);
- }
-
- if (lar->type==LA_SPOT) {
-
- normalize_v3(lar->imat[0]);
- normalize_v3(lar->imat[1]);
- normalize_v3(lar->imat[2]);
-
- xn = saacos(lar->spotsi);
- xn = sinf(xn) / cosf(xn);
- lar->spottexfac= 1.0f/(xn);
-
- if (lar->mode & LA_ONLYSHADOW) {
- if ((lar->mode & (LA_SHAD_BUF|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW;
- }
-
- }
-
- /* set flag for spothalo en initvars */
- if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
- (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
- {
- if (la->haint>0.0f) {
- re->flag |= R_LAMPHALO;
-
- /* camera position (0, 0, 0) rotate around lamp */
- 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);
-
- /* z factor, for a normalized volume */
- angle= saacos(lar->spotsi);
- xn= lar->spotsi;
- yn = sinf(angle);
- lar->sh_zfac= yn/xn;
- /* pre-scale */
- lar->sh_invcampos[2]*= lar->sh_zfac;
-
- /* halfway shadow buffer doesn't work for volumetric effects */
- if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
- lar->buftype = LA_SHADBUF_REGULAR;
-
- }
- }
- else if (la->type==LA_HEMI) {
- lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF);
- }
-
- for (c=0; c<MAX_MTEX; c++) {
- if (la->mtex[c] && la->mtex[c]->tex) {
- if (la->mtex[c]->mapto & LAMAP_COL)
- lar->mode |= LA_TEXTURE;
- if (la->mtex[c]->mapto & LAMAP_SHAD)
- lar->mode |= LA_SHAD_TEX;
-
- if (G.is_rendering) {
- if (re->osa) {
- if (la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX;
- }
- }
- }
- }
-
- /* old code checked for internal render (aka not yafray) */
- {
- /* to make sure we can check ray shadow easily in the render code */
- if (lar->mode & LA_SHAD_RAY) {
- if ( (re->r.mode & R_RAYTRACE)==0)
- lar->mode &= ~LA_SHAD_RAY;
- }
-
-
- if (re->r.mode & R_SHADOW) {
-
- if (la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) {
- init_jitter_plane(lar);
- }
- else if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) {
- /* Per lamp, one shadow buffer is made. */
- lar->bufflag= la->bufflag;
- copy_m4_m4(mat, ob->obmat);
- initshadowbuf(re, lar, mat); /* mat is altered */
- }
-
-
- /* this is the way used all over to check for shadow */
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
- LampShadowSample *ls;
- LampShadowSubSample *lss;
- int a, b;
-
- memset(re->shadowsamplenr, 0, sizeof(re->shadowsamplenr));
-
- lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
- ls= lar->shadsamp;
-
- /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
- for (a=0; a<re->r.threads; a++, ls++) {
- lss= ls->s;
- for (b=0; b<re->r.osa; b++, lss++) {
- lss->samplenr= -1; /* used to detect whether we store or read */
- lss->shadfac[0]= 1.0f;
- lss->shadfac[1]= 1.0f;
- lss->shadfac[2]= 1.0f;
- lss->shadfac[3]= 1.0f;
- }
- }
- }
- }
- }
-
- return go;
-}
-
-static bool is_object_restricted(Render *re, Object *ob)
-{
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- return (ob->restrictflag & OB_RESTRICT_VIEW) != 0;
- else
- return (ob->restrictflag & OB_RESTRICT_RENDER) != 0;
-}
-
-static bool is_object_hidden(Render *re, Object *ob)
-{
- if (is_object_restricted(re, ob))
- return true;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW) {
- /* Mesh deform cages and so on mess up the preview. To avoid the problem,
- * viewport doesn't show mesh object if its draw type is bounding box or wireframe.
- * Unless it's an active smoke domain!
- */
- ModifierData *md = NULL;
-
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
- (modifier_isEnabled(re->scene, md, eModifierMode_Realtime)))
- {
- return false;
- }
- return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE);
- }
- else {
- return false;
- }
-}
-
-/* layflag: allows material group to ignore layerflag */
-static void add_lightgroup(Render *re, Group *group, int exclusive)
-{
- group->id.tag &= ~LIB_TAG_DOIT;
-
-#if 0
- /* it's a bit too many loops in loops... but will survive */
- /* note that 'exclusive' will remove it from the global list */
- FOREACH_GROUP_BASE_BEGIN(group, base)
- {
- Object *object = base->object;
-
- if (is_object_hidden(re, object)) {
- continue;
- }
-
- if (base->flag & BASE_VISIBLED) {
- if (object && object->type == OB_LAMP) {
- for (GroupObject *gol = re->lights.first; gol; gol = gol->next) {
- if (gol->ob == object) {
- go->lampren = gol->lampren;
- break;
- }
- }
-
- if (go->lampren == NULL) {
- gol= add_render_lamp(re, object);
- }
-
- if (gol && exclusive) {
- BLI_remlink(&re->lights, gol);
- MEM_freeN(gol);
- }
- }
- }
- }
- FOREACH_GROUP_BASE_END;
-#else
- UNUSED_VARS(re, exclusive);
-#endif
-}
-
-static void set_material_lightgroups(Render *re)
-{
- Group *group;
- Material *ma;
-
- /* not for preview render */
- if (re->scene->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))
- return;
-
- for (group= re->main->group.first; group; group=group->id.next)
- group->id.tag |= LIB_TAG_DOIT;
-
- /* it's a bit too many loops in loops... but will survive */
- /* hola! materials not in use...? */
- for (ma= re->main->mat.first; ma; ma=ma->id.next) {
- if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT))
- add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* World */
-/* ------------------------------------------------------------------------- */
-
-void init_render_world(Render *re)
-{
- void *wrld_prev[2] = {
- re->wrld.aotables,
- re->wrld.aosphere,
- };
-
- int a;
-
- if (re->scene && re->scene->world) {
- re->wrld = *(re->scene->world);
-
- copy_v3_v3(re->grvec, re->viewmat[2]);
- normalize_v3(re->grvec);
- copy_m3_m4(re->imat, re->viewinv);
-
- for (a=0; a<MAX_MTEX; a++)
- if (re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX;
-
- /* AO samples should be OSA minimum */
- if (re->osa)
- while (re->wrld.aosamp*re->wrld.aosamp < re->osa)
- re->wrld.aosamp++;
- if (!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE))
- re->wrld.mode &= ~(WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT);
- }
- else {
- memset(&re->wrld, 0, sizeof(World));
- re->wrld.exp= 0.0f;
- re->wrld.range= 1.0f;
-
- /* for mist pass */
- re->wrld.miststa= re->clipsta;
- re->wrld.mistdist= re->clipend-re->clipsta;
- re->wrld.misi= 1.0f;
- }
-
- re->wrld.linfac= 1.0f + powf((2.0f*re->wrld.exp + 0.5f), -10);
- re->wrld.logfac= logf((re->wrld.linfac-1.0f)/re->wrld.linfac) / re->wrld.range;
-
- /* restore runtime vars, needed for viewport rendering [#36005] */
- re->wrld.aotables = wrld_prev[0];
- re->wrld.aosphere = wrld_prev[1];
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-/* Object Finalization */
-/* ------------------------------------------------------------------------- */
-
-/* prevent phong interpolation for giving ray shadow errors (terminator problem) */
-static void set_phong_threshold(ObjectRen *obr)
-{
-// VertRen *ver;
- VlakRen *vlr;
- float thresh= 0.0, dot;
- int tot=0, i;
-
- /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger
- * are taken into account. This threshold is meant to work on smooth geometry, not
- * for extreme cases (ton) */
-
- for (i=0; i<obr->totvlak; i++) {
- vlr= RE_findOrAddVlak(obr, i);
- if ((vlr->flag & R_SMOOTH) && (vlr->flag & R_STRAND)==0) {
- dot= dot_v3v3(vlr->n, vlr->v1->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
- dot= dot_v3v3(vlr->n, vlr->v2->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
-
- dot= dot_v3v3(vlr->n, vlr->v3->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
-
- if (vlr->v4) {
- dot= dot_v3v3(vlr->n, vlr->v4->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
- }
- }
- }
-
- if (tot) {
- thresh/= (float)tot;
- obr->ob->smoothresh= cosf(0.5f*(float)M_PI-saacos(thresh));
- }
-}
-
-/* per face check if all samples should be taken.
- * if raytrace or multisample, do always for raytraced material, or when material full_osa set */
-static void set_fullsample_trace_flag(Render *re, ObjectRen *obr)
-{
- VlakRen *vlr;
- int a, trace, mode, osa;
-
- osa= re->osa;
- trace= re->r.mode & R_RAYTRACE;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
- mode= vlr->mat->mode;
-
- if (trace && (mode & MA_TRACEBLE))
- vlr->flag |= R_TRACEBLE;
-
- if (osa) {
- if (mode & MA_FULL_OSA) {
- vlr->flag |= R_FULL_OSA;
- }
- else if (trace) {
- if (mode & MA_SHLESS) {
- /* pass */
- }
- else if (vlr->mat->material_type == MA_TYPE_VOLUME) {
- /* pass */
- }
- else if ((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) {
- /* for blurry reflect/refract, better to take more samples
- * inside the raytrace than as OSA samples */
- if ((vlr->mat->gloss_mir == 1.0f) && (vlr->mat->gloss_tra == 1.0f))
- vlr->flag |= R_FULL_OSA;
- }
- }
- }
- }
-}
-
-/* split quads for predictable baking
- * dir 1 == (0, 1, 2) (0, 2, 3), 2 == (1, 3, 0) (1, 2, 3)
- */
-static void split_quads(ObjectRen *obr, int dir)
-{
- VlakRen *vlr, *vlr1;
- int a;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
-
- /* test if rendering as a quad or triangle, skip wire */
- if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
-
- if (vlr->v4) {
-
- vlr1= RE_vlakren_copy(obr, vlr);
- vlr1->flag |= R_FACE_SPLIT;
-
- if ( dir==2 ) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
-
- /* new vertex pointers */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->v1= vlr->v2;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr->v3 = vlr->v4;
-
- vlr1->flag |= R_DIVIDE_24;
- }
- else {
- vlr1->v1= vlr->v1;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr1->flag &= ~R_DIVIDE_24;
- }
- vlr->v4 = vlr1->v4 = NULL;
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge marks */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- }
- else {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
- }
-#endif
-
- /* new normals */
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
- }
- /* clear the flag when not divided */
- else vlr->flag &= ~R_DIVIDE_24;
- }
- }
-}
-
-static void check_non_flat_quads(ObjectRen *obr)
-{
- VlakRen *vlr, *vlr1;
- VertRen *v1, *v2, *v3, *v4;
- float nor[3], xn, flen;
- int a;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
-
- /* test if rendering as a quad or triangle, skip wire */
- if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
-
- /* check if quad is actually triangle */
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
- sub_v3_v3v3(nor, v1->co, v2->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v1= v2;
- vlr->v2= v3;
- vlr->v3= v4;
- vlr->v4= NULL;
- vlr->flag |= (R_DIVIDE_24 | R_FACE_SPLIT);
- }
- else {
- sub_v3_v3v3(nor, v2->co, v3->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v2= v3;
- vlr->v3= v4;
- vlr->v4= NULL;
- vlr->flag |= R_FACE_SPLIT;
- }
- else {
- sub_v3_v3v3(nor, v3->co, v4->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v4= NULL;
- }
- else {
- sub_v3_v3v3(nor, v4->co, v1->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v4= NULL;
- }
- }
- }
- }
-
- if (vlr->v4) {
-
- /* Face is divided along edge with the least gradient */
- /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */
- /* 4---3 4---3 */
- /* |\ 1| or |1 /| */
- /* |0\ | |/ 0| */
- /* 1---2 1---2 0 = orig face, 1 = new face */
-
- /* render normals are inverted in render! we calculate normal of single tria here */
- flen= normal_tri_v3(nor, vlr->v4->co, vlr->v3->co, vlr->v1->co);
- if (flen==0.0f) normal_tri_v3(nor, vlr->v4->co, vlr->v2->co, vlr->v1->co);
-
- xn = dot_v3v3(nor, vlr->n);
-
- if (ABS(xn) < 0.999995f ) { /* checked on noisy fractal grid */
-
- float d1, d2;
-
- vlr1= RE_vlakren_copy(obr, vlr);
- vlr1->flag |= R_FACE_SPLIT;
-
- /* split direction based on vnorms */
- normal_tri_v3(nor, vlr->v1->co, vlr->v2->co, vlr->v3->co);
- d1 = dot_v3v3(nor, vlr->v1->n);
-
- normal_tri_v3(nor, vlr->v2->co, vlr->v3->co, vlr->v4->co);
- d2 = dot_v3v3(nor, vlr->v2->n);
-
- if (fabsf(d1) < fabsf(d2) ) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
-
- /* new vertex pointers */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->v1= vlr->v2;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr->v3 = vlr->v4;
-
- vlr1->flag |= R_DIVIDE_24;
- }
- else {
- vlr1->v1= vlr->v1;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr1->flag &= ~R_DIVIDE_24;
- }
- vlr->v4 = vlr1->v4 = NULL;
-
- /* new normals */
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge marks */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- }
- else {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
- }
-#endif
- }
- /* clear the flag when not divided */
- else vlr->flag &= ~R_DIVIDE_24;
- }
- }
- }
-}
-
-static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- VertRen *ver= NULL;
- StrandRen *strand= NULL;
- StrandBound *sbound= NULL;
- float min[3], max[3], smin[3], smax[3];
- int a, b;
-
- if (obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) {
- /* the exception below is because displace code now is in init_render_mesh call,
- * I will look at means to have autosmooth enabled for all object types
- * and have it as general postprocess, like displace */
- if (ob->type!=OB_MESH && test_for_displace(re, ob))
- displace(re, obr);
-
- if (!timeoffset) {
- /* phong normal interpolation can cause error in tracing
- * (terminator problem) */
- ob->smoothresh= 0.0;
- if ((re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW))
- set_phong_threshold(obr);
-
- if (re->flag & R_BAKING && re->r.bake_quad_split != 0) {
- /* Baking lets us define a quad split order */
- split_quads(obr, re->r.bake_quad_split);
- }
- else if (BKE_object_is_animated(re->scene, ob))
- split_quads(obr, 1);
- else {
- if ((re->r.mode & R_SIMPLIFY && re->r.simplify_flag & R_SIMPLE_NO_TRIANGULATE) == 0)
- check_non_flat_quads(obr);
- }
-
- set_fullsample_trace_flag(re, obr);
-
- /* compute bounding boxes for clipping */
- INIT_MINMAX(min, max);
- for (a=0; a<obr->totvert; a++) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- minmax_v3v3_v3(min, max, ver->co);
- }
-
- if (obr->strandbuf) {
- float width;
-
- /* compute average bounding box of strandpoint itself (width) */
- if (obr->strandbuf->flag & R_STRAND_B_UNITS)
- obr->strandbuf->maxwidth = max_ff(obr->strandbuf->ma->strand_sta, obr->strandbuf->ma->strand_end);
- else
- obr->strandbuf->maxwidth= 0.0f;
-
- width= obr->strandbuf->maxwidth;
- sbound= obr->strandbuf->bound;
- for (b=0; b<obr->strandbuf->totbound; b++, sbound++) {
-
- INIT_MINMAX(smin, smax);
-
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
- strand_minmax(strand, smin, smax, width);
- }
-
- copy_v3_v3(sbound->boundbox[0], smin);
- copy_v3_v3(sbound->boundbox[1], smax);
-
- minmax_v3v3_v3(min, max, smin);
- minmax_v3v3_v3(min, max, smax);
- }
- }
-
- copy_v3_v3(obr->boundbox[0], min);
- copy_v3_v3(obr->boundbox[1], max);
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Database */
-/* ------------------------------------------------------------------------- */
-
-static int render_object_type(short type)
-{
- return OB_TYPE_SUPPORT_MATERIAL(type);
-}
-
-static void find_dupli_instances(Render *re, ObjectRen *obr, DupliObject *dob)
-{
- ObjectInstanceRen *obi;
- float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
- int first = 1;
-
- mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
- invert_m4_m4(imat, obmat);
-
- /* for objects instanced by dupliverts/faces/particles, we go over the
- * list of instances to find ones that instance obr, and setup their
- * matrices and obr pointer */
- for (obi=re->instancetable.last; obi; obi=obi->prev) {
- if (!obi->obr && obi->ob == obr->ob && obi->psysindex == obr->psysindex) {
- obi->obr= obr;
-
- /* compute difference between object matrix and
- * object matrix with dupli transform, in viewspace */
- copy_m4_m4(obimat, obi->mat);
- mul_m4_m4m4(obi->mat, obimat, imat);
-
- copy_m3_m4(nmat, obi->mat);
- invert_m3_m3(obi->nmat, nmat);
- transpose_m3(obi->nmat);
-
- if (dob) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
-
- if (!first) {
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
- }
- else
- first= 0;
- }
- }
-}
-
-static void assign_dupligroup_dupli(Render *re, ObjectInstanceRen *obi, ObjectRen *obr, DupliObject *dob)
-{
- float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
-
- mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
- invert_m4_m4(imat, obmat);
-
- obi->obr= obr;
-
- /* compute difference between object matrix and
- * object matrix with dupli transform, in viewspace */
- copy_m4_m4(obimat, obi->mat);
- mul_m4_m4m4(obi->mat, obimat, imat);
-
- copy_m3_m4(nmat, obi->mat);
- invert_m3_m3(obi->nmat, nmat);
- transpose_m3(obi->nmat);
-
- if (dob) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
-
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
-}
-
-static ObjectRen *find_dupligroup_dupli(Render *re, Object *ob, int psysindex)
-{
- ObjectRen *obr;
-
- /* if the object is itself instanced, we don't want to create an instance
- * for it */
- if (ob->transflag & OB_RENDER_DUPLI)
- return NULL;
-
- /* try to find an object that was already created so we can reuse it
- * and save memory */
- for (obr=re->objecttable.first; obr; obr=obr->next)
- if (obr->ob == ob && obr->psysindex == psysindex && (obr->flag & R_INSTANCEABLE))
- return obr;
-
- return NULL;
-}
-
-static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob, float omat[4][4])
-{
- /* For duplis we need to have a matrix that transform the coordinate back
- * to it's original position, without the dupli transforms. We also check
- * the matrix is actually needed, to save memory on lots of dupliverts for
- * example */
- static Object *lastob= NULL;
- static int needtexmat= 0;
-
- /* init */
- if (!re) {
- lastob= NULL;
- needtexmat= 0;
- return;
- }
-
- /* check if we actually need it */
- if (lastob != dob->ob) {
- Material ***material;
- short a, *totmaterial;
-
- lastob= dob->ob;
- needtexmat= 0;
-
- totmaterial= give_totcolp(dob->ob);
- material= give_matarar(dob->ob);
-
- if (totmaterial && material)
- for (a= 0; a<*totmaterial; a++)
- if ((*material)[a] && (*material)[a]->texco & TEXCO_OBJECT)
- needtexmat= 1;
- }
-
- if (needtexmat) {
- float imat[4][4];
-
- obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4);
- invert_m4_m4(imat, dob->mat);
- mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv);
- }
-
- copy_v3_v3(obi->dupliorco, dob->orco);
- copy_v2_v2(obi->dupliuv, dob->uv);
-}
-
-static void init_render_object_data(Depsgraph *depsgraph, Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- ParticleSystem *psys;
- int i;
-
- if (obr->psysindex) {
- if ((!obr->prev || obr->prev->ob != ob || (obr->prev->flag & R_INSTANCEABLE)==0) && ob->type==OB_MESH) {
- /* the emitter mesh wasn't rendered so the modifier stack wasn't
- * evaluated with render settings */
- DerivedMesh *dm;
- const CustomDataMask mask = CD_MASK_RENDER_INTERNAL;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm = mesh_create_derived_view(depsgraph, re->scene, ob, mask);
- else
- dm = mesh_create_derived_render(depsgraph, re->scene, ob, mask);
- dm->release(dm);
- }
-
- for (psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++)
- psys= psys->next;
-
- render_new_particle_system(depsgraph, re, obr, psys, timeoffset);
- }
- else {
- if (ELEM(ob->type, OB_FONT, OB_CURVE))
- init_render_curve(depsgraph, re, obr, timeoffset);
- else if (ob->type==OB_SURF)
- init_render_surf(depsgraph, re, obr, timeoffset);
- else if (ob->type==OB_MESH)
- init_render_mesh(depsgraph, re, obr, timeoffset);
- else if (ob->type==OB_MBALL)
- init_render_mball(depsgraph, re, obr);
- }
-
- finalize_render_object(re, obr, timeoffset);
-
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
-}
-
-static void add_render_object(Depsgraph *depsgraph, Render *re, Object *ob, Object *par, DupliObject *dob,
- float omat[4][4], int timeoffset)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- ParticleSystem *psys;
- int show_emitter, allow_render= 1, index, psysindex, i;
-
- index= (dob)? dob->persistent_id[0]: 0;
-
- /* the emitter has to be processed first (render levels of modifiers) */
- /* so here we only check if the emitter should be rendered */
- if (ob->particlesystem.first) {
- show_emitter = (ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0;
-
- /* if no psys has "show emitter" selected don't render emitter */
- if (show_emitter == 0)
- allow_render= 0;
- }
-
- /* one render object for the data itself */
- if (allow_render) {
- obr= RE_addRenderObject(re, ob, par, index, 0, ob->lay);
- if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
- obr->flag |= R_INSTANCEABLE;
- copy_m4_m4(obr->obmat, ob->obmat);
- }
- init_render_object_data(depsgraph, re, obr, timeoffset);
-
- /* only add instance for objects that have not been used for dupli */
- if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
- if (dob) set_dupli_tex_mat(re, obi, dob, omat);
- }
- else
- find_dupli_instances(re, obr, dob);
-
- for (i=1; i<=ob->totcol; i++) {
- Material* ma = give_render_material(re, ob, i);
- if (ma && ma->material_type == MA_TYPE_VOLUME)
- add_volume(re, obr, ma);
- }
- }
-
- /* and one render object per particle system */
- if (ob->particlesystem.first) {
- psysindex= 1;
- for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
- if (!psys_check_enabled(ob, psys, G.is_rendering))
- continue;
-
- obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
- if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
- obr->flag |= R_INSTANCEABLE;
- copy_m4_m4(obr->obmat, ob->obmat);
- }
- if (dob)
- psys->flag |= PSYS_USE_IMAT;
- init_render_object_data(depsgraph, re, obr, timeoffset);
- psys->flag &= ~PSYS_USE_IMAT;
-
- /* only add instance for objects that have not been used for dupli */
- if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
- if (dob) set_dupli_tex_mat(re, obi, dob, omat);
- }
- else
- find_dupli_instances(re, obr, dob);
- }
- }
-}
-
-/* par = pointer to duplicator parent, needed for object lookup table */
-/* index = when duplicater copies same object (particle), the counter */
-static void init_render_object(Depsgraph *depsgraph, Render *re, Object *ob, Object *par, DupliObject *dob,
- float omat[4][4], int timeoffset)
-{
- static double lasttime= 0.0;
- double time;
- float mat[4][4];
-
- if (ob->type==OB_LAMP)
- add_render_lamp(re, ob);
- else if (render_object_type(ob->type))
- add_render_object(depsgraph, re, ob, par, dob, omat, timeoffset);
- else {
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- }
-
- time= PIL_check_seconds_timer();
- if (time - lasttime > 1.0) {
- lasttime= time;
- /* clumsy copying still */
- re->i.totvert= re->totvert;
- re->i.totface= re->totvlak;
- re->i.totstrand= re->totstrand;
- re->i.tothalo= re->tothalo;
- re->i.totlamp= re->totlamp;
- re->stats_draw(re->sdh, &re->i);
- }
-
- ob->flag |= OB_DONE;
-}
-
-void RE_Database_Free(Render *re)
-{
- LampRen *lar;
-
- /* will crash if we try to free empty database */
- if (!re->i.convertdone)
- return;
-
- /* statistics for debugging render memory usage */
- if ((G.debug & G_DEBUG) && (G.is_rendering)) {
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_image_print_memlist();
- MEM_printmemlist_stats();
- }
- }
-
- /* FREE */
-
- for (lar= re->lampren.first; lar; lar= lar->next) {
- freeshadowbuf(lar);
- if (lar->jitter) MEM_freeN(lar->jitter);
- if (lar->shadsamp) MEM_freeN(lar->shadsamp);
- if (lar->sunsky) MEM_freeN(lar->sunsky);
- curvemapping_free(lar->curfalloff);
- }
-
- free_volume_precache(re);
-
- BLI_freelistN(&re->lampren);
- BLI_freelistN(&re->lights);
-
- free_renderdata_tables(re);
-
- /* free orco */
- free_mesh_orco_hash(re);
-
- if (re->main) {
- end_render_materials(re->main);
- end_render_textures(re);
- free_pointdensities(re);
- }
-
- free_camera_inside_volumes(re);
-
- if (re->wrld.aosphere) {
- MEM_freeN(re->wrld.aosphere);
- re->wrld.aosphere= NULL;
- if (re->scene && re->scene->world)
- re->scene->world->aosphere= NULL;
- }
- if (re->wrld.aotables) {
- MEM_freeN(re->wrld.aotables);
- re->wrld.aotables= NULL;
- if (re->scene && re->scene->world)
- re->scene->world->aotables= NULL;
- }
- if (re->r.mode & R_RAYTRACE)
- free_render_qmcsampler(re);
-
- if (re->r.mode & R_RAYTRACE) freeraytree(re);
-
- free_sss(re);
- free_occ(re);
- free_strand_surface(re);
-
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->i.convertdone = false;
-
- re->bakebuf= NULL;
-
- if (re->scene)
- if (re->scene->r.scemode & R_FREE_IMAGE)
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
- BKE_image_free_all_textures();
-
- if (re->memArena) {
- BLI_memarena_free(re->memArena);
- re->memArena = NULL;
- }
-}
-
-static int allow_render_object(Render *re, Object *ob, int nolamps, int onlyselected, Object *actob)
-{
- if (is_object_hidden(re, ob))
- return 0;
-
- /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */
- if (!ob->particlesystem.first) {
- if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
- return 0;
- }
- }
-
- /* don't add non-basic meta objects, ends up having renderobjects with no geometry */
- if (ob->type == OB_MBALL && ob!=BKE_mball_basis_find(re->scene, ob))
- return 0;
-
- if (nolamps && (ob->type==OB_LAMP))
- return 0;
-
- if (onlyselected && (ob!=actob && !(ob->flag & SELECT)))
- return 0;
-
- return 1;
-}
-
-static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Object *obd)
-{
- ParticleSystem *psys;
- Material *ma;
- short a, *totmaterial;
-
- /* don't allow objects with halos. we need to have
- * all halo's to sort them globally in advance */
- totmaterial= give_totcolp(obd);
-
- if (totmaterial) {
- for (a= 0; a<*totmaterial; a++) {
- ma= give_current_material(obd, a + 1);
- if (ma && (ma->material_type == MA_TYPE_HALO))
- return 0;
- }
- }
-
- for (psys=obd->particlesystem.first; psys; psys=psys->next)
- if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
- return 0;
-
- /* don't allow lamp, animated duplis, or radio render */
- return (render_object_type(obd->type) &&
- (!(dob->type == OB_DUPLIGROUP) || !dob->animated));
-}
-
-static int get_vector_viewlayers(Scene *UNUSED(sce))
-{
- return 0;
-}
-
-static void add_group_render_dupli_obs(Depsgraph *depsgraph, Render *re, Group *group, int nolamps,
- int onlyselected, Object *actob, int timeoffset, int level)
-{
- /* Simple preventing of too deep nested groups. */
- if (level > MAX_DUPLI_RECUR) return;
-
- /* Recursively go into dupligroups to find objects with OB_RENDER_DUPLI
- * that were not created yet. */
- FOREACH_GROUP_OBJECT_BEGIN(group, ob)
- {
- if (ob->flag & OB_DONE) {
- if (ob->transflag & OB_RENDER_DUPLI) {
- if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(depsgraph, re, ob, NULL, NULL, NULL, timeoffset);
- ob->transflag &= ~OB_RENDER_DUPLI;
-
- if (ob->dup_group) {
- add_group_render_dupli_obs(depsgraph, re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
- }
- }
- }
- }
- }
- FOREACH_GROUP_OBJECT_END;
-}
-
-static void database_init_objects(Depsgraph *depsgraph, Render *re, unsigned int UNUSED(renderlay),
- int nolamps, int onlyselected, Object *actob, int timeoffset)
-{
- Base *base;
- Object *ob;
- Group *group;
- ObjectInstanceRen *obi;
- Scene *sce_iter;
-
- /* for duplis we need the Object texture mapping to work as if
- * untransformed, set_dupli_tex_mat sets the matrix to allow that
- * NULL is just for init */
- set_dupli_tex_mat(NULL, NULL, NULL, NULL);
-
- /* loop over all objects rather then using SETLOOPER because we may
- * reference an mtex-mapped object which isn't rendered or is an
- * empty in a dupli group. We could scan all render material/lamp/world
- * mtex's for mapto objects but its easier just to set the
- * 'imat' / 'imat_ren' on all and unlikely to be a performance hit
- * See bug: [#28744] - campbell */
- for (ob= re->main->object.first; ob; ob= ob->id.next) {
- float mat[4][4];
-
- /* imat objects has to be done here, since displace can have texture using Object map-input */
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat_ren, mat);
- copy_m4_m4(ob->imat, ob->imat_ren);
- /* each object should only be rendered once */
- ob->flag &= ~OB_DONE;
- ob->transflag &= ~OB_RENDER_DUPLI;
- }
-
- for (SETLOOPER(re->scene, sce_iter, base)) {
- ob= base->object;
-
-#if 0
- TODO_LAYER; /* investigate if this is an issue*/
- /* in the prev/next pass for making speed vectors, avoid creating
- * objects that are not on a renderlayer with a vector pass, can
- * save a lot of time in complex scenes */
- vectorlay= get_vector_viewlayers(re->scene);
-#endif
-
- /* if the object is not visible, ignore it */
- if ((base->flag & BASE_VISIBLED) == 0) {
- continue;
- }
-
- /* OB_DONE means the object itself got duplicated, so was already converted */
- if (ob->flag & OB_DONE) {
- /* OB_RENDER_DUPLI means instances for it were already created, now
- * it still needs to create the ObjectRen containing the data */
- if (ob->transflag & OB_RENDER_DUPLI) {
- if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(depsgraph, re, ob, NULL, NULL, NULL, timeoffset);
- ob->transflag &= ~OB_RENDER_DUPLI;
- }
- }
- }
- else if (((base->flag & BASE_VISIBLED) != 0) || (ob->type==OB_LAMP)) {
- if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
- DupliObject *dob;
- ListBase *duplilist;
- DupliApplyData *duplilist_apply_data = NULL;
- int i;
-
- /* create list of duplis generated by this object, particle
- * system need to have render settings set for dupli particles */
- duplilist = object_duplilist(depsgraph, re->scene, ob);
- duplilist_apply_data = duplilist_apply(depsgraph, ob, NULL, duplilist);
-
- for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
- DupliExtraData *dob_extra = &duplilist_apply_data->extra[i];
- Object *obd= dob->ob;
-
- copy_m4_m4(obd->obmat, dob->mat);
-
- /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
- if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
- continue;
-
- if (is_object_hidden(re, obd))
- continue;
-
- if (obd->type==OB_MBALL)
- continue;
-
- if (!allow_render_object(re, obd, nolamps, onlyselected, actob))
- continue;
-
- if (allow_render_dupli_instance(re, dob, obd)) {
- ParticleSystem *psys;
- ObjectRen *obr = NULL;
- int psysindex;
- float mat[4][4];
-
- obi=NULL;
-
- /* instances instead of the actual object are added in two cases, either
- * this is a duplivert/face/particle, or it is a non-animated object in
- * a dupligroup that has already been created before */
- if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) {
- mul_m4_m4m4(mat, re->viewmat, dob->mat);
- /* ob = particle system, use that layer */
- obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob);
-
- /* fill in instance variables for texturing */
- set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
- if (dob->type != OB_DUPLIGROUP) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
- else {
- /* for the second case, setup instance to point to the already
- * created object, and possibly setup instances if this object
- * itself was duplicated. for the first case find_dupli_instances
- * will be called later. */
- assign_dupligroup_dupli(re, obi, obr, dob);
- if (obd->transflag & OB_RENDER_DUPLI)
- find_dupli_instances(re, obr, dob);
- }
- }
-
- /* same logic for particles, each particle system has it's own object, so
- * need to go over them separately */
- psysindex= 1;
- for (psys=obd->particlesystem.first; psys; psys=psys->next) {
- if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
- if (obi == NULL)
- mul_m4_m4m4(mat, re->viewmat, dob->mat);
- obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob);
-
- set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
- if (dob->type != OB_DUPLIGROUP) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
- else {
- assign_dupligroup_dupli(re, obi, obr, dob);
- if (obd->transflag & OB_RENDER_DUPLI)
- find_dupli_instances(re, obr, dob);
- }
- }
- }
-
- if (obi==NULL)
- /* can't instance, just create the object */
- init_render_object(depsgraph, re, obd, ob, dob, dob_extra->obmat, timeoffset);
-
- if (dob->type != OB_DUPLIGROUP) {
- obd->flag |= OB_DONE;
- obd->transflag |= OB_RENDER_DUPLI;
- }
- }
- else
- init_render_object(depsgraph, re, obd, ob, dob, dob_extra->obmat, timeoffset);
-
- if (re->test_break(re->tbh)) break;
- }
-
- if (duplilist_apply_data) {
- duplilist_restore(duplilist, duplilist_apply_data);
- duplilist_free_apply_data(duplilist_apply_data);
- }
- free_object_duplilist(duplilist);
-
- if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(depsgraph, re, ob, NULL, NULL, NULL, timeoffset);
- }
- else if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(depsgraph, re, ob, NULL, NULL, NULL, timeoffset);
- }
-
- if (re->test_break(re->tbh)) break;
- }
-
- /* objects in groups with OB_RENDER_DUPLI set still need to be created,
- * since they may not be part of the scene */
- for (group= re->main->group.first; group; group=group->id.next)
- add_group_render_dupli_obs(depsgraph, re, group, nolamps, onlyselected, actob, timeoffset, 0);
-
- if (!re->test_break(re->tbh))
- RE_makeRenderInstances(re);
-}
-
-void RE_Database_CameraOnly(Render *re, Main *bmain, Scene *scene, unsigned int lay, int use_camera_view)
-{
- Object *camera;
- float mat[4][4];
-
- re->main= bmain;
- re->scene= scene;
- re->lay= lay;
-
- /* scene needs to be set to get camera */
- camera= RE_GetCamera(re);
-
- /* if no camera, viewmat should have been set! */
- if (use_camera_view && camera) {
- /* called before but need to call again in case of lens animation from the
- * above call to BKE_scene_graph_update_for_newframe, fixes bug. [#22702].
- * following calls don't depend on 'RE_SetCamera' */
- RE_SetCamera(re, camera);
- RE_GetCameraModelMatrix(re, camera, mat);
- invert_m4(mat);
- RE_SetView(re, mat);
-
- /* force correct matrix for scaled cameras */
- DEG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
- }
-}
-
-/* used to be 'rotate scene' */
-void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int lay, int use_camera_view)
-{
- Object *camera;
- float mat[4][4];
- float amb[3];
-
- re->main= bmain;
- re->scene= scene;
- re->lay= lay;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
-
- /* scene needs to be set to get camera */
- camera= RE_GetCamera(re);
-
- /* per second, per object, stats print this */
- re->i.infostr= "Preparing Scene data";
- re->i.cfra= scene->r.cfra;
- BLI_strncpy(re->i.scene_name, scene->id.name + 2, sizeof(re->i.scene_name));
-
- /* XXX add test if dbase was filled already? */
-
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "render db arena");
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->lights.first= re->lights.last= NULL;
- re->lampren.first= re->lampren.last= NULL;
-
- re->i.partsdone = false; /* signal now in use for previewrender */
-
- /* in localview, lamps are using normal layers, objects only local bits */
- if (re->lay & 0xFF000000)
- lay &= 0xFF000000;
-
- /* applies changes fully */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
- }
-
- /* if no camera, viewmat should have been set! */
- if (use_camera_view && camera) {
- /* called before but need to call again in case of lens animation from the
- * above call to BKE_scene_graph_update_for_newframe, fixes bug. [#22702].
- * following calls don't depend on 'RE_SetCamera' */
- RE_SetCamera(re, camera);
- RE_GetCameraModelMatrix(re, camera, mat);
- invert_m4(mat);
- RE_SetView(re, mat);
-
- /* force correct matrix for scaled cameras */
- DEG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
- }
-
- /* store for incremental render, viewmat rotates dbase */
- copy_m4_m4(re->viewmat_orig, re->viewmat);
-
- init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if (re->r.mode & R_RAYTRACE) {
- init_render_qmcsampler(re);
-
- if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
- if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(re, &re->wrld);
- }
-
- /* still bad... doing all */
- init_render_textures(re);
- copy_v3_v3(amb, &re->wrld.ambr);
- init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0);
- set_node_shader_lamp_loop(shade_material_loop);
-
- /* MAKE RENDER DATA */
- Depsgraph *depsgraph = NULL;
- BLI_assert(depsgraph);
- /* This will break things, and it should because honestly this function is deprecated and no one uses it.
- * maybe freestyle? But even so, this need to change. Even freestyle need to get data from depsgraph
- * so we can't create the database only once. */
- database_init_objects(depsgraph, re, lay, 0, 0, NULL, 0);
-
- if (!re->test_break(re->tbh)) {
- set_material_lightgroups(re);
-
- /* for now some clumsy copying still */
- re->i.totvert= re->totvert;
- re->i.totface= re->totvlak;
- re->i.totstrand= re->totstrand;
- re->i.tothalo= re->tothalo;
- re->i.totlamp= re->totlamp;
- re->stats_draw(re->sdh, &re->i);
- }
-}
-
-void RE_Database_Preprocess(Depsgraph *depsgraph, Render *re)
-{
- if (!re->test_break(re->tbh)) {
- int tothalo;
-
- tothalo= re->tothalo;
- sort_halos(re, tothalo);
-
- init_camera_inside_volumes(re);
-
- re->i.infostr = IFACE_("Creating Shadowbuffers");
- re->stats_draw(re->sdh, &re->i);
-
- /* SHADOW BUFFER */
- threaded_makeshadowbufs(re);
-
- /* old code checked for internal render (aka not yafray) */
- {
- /* raytree */
- if (!re->test_break(re->tbh)) {
- if (re->r.mode & R_RAYTRACE) {
- makeraytree(re);
- }
- }
- /* ENVIRONMENT MAPS */
- if (!re->test_break(re->tbh))
- make_envmaps(re);
-
- /* point density texture */
- if (!re->test_break(re->tbh))
- make_pointdensities(depsgraph, re);
- /* voxel data texture */
- if (!re->test_break(re->tbh))
- make_voxeldata(re);
- }
-
- if (!re->test_break(re->tbh))
- project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
-
- /* Occlusion */
- if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
- if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
- if (re->r.mode & R_SHADOW)
- make_occ_tree(re);
-
- /* SSS */
- if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
- make_sss_tree(re);
-
- if (!re->test_break(re->tbh))
- if (re->r.mode & R_RAYTRACE)
- volume_precache(re);
- }
-
- re->i.convertdone = true;
-
- if (re->test_break(re->tbh))
- RE_Database_Free(re);
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-/* exported call to recalculate hoco for vertices, when winmat changed */
-void RE_DataBase_ApplyWindow(Render *re)
-{
- project_renderdata(re, projectverto, 0, 0, 0);
-}
-
-/* exported call to rotate render data again, when viewmat changed */
-void RE_DataBase_IncrementalView(Render *re, float viewmat[4][4], int restore)
-{
- float oldviewinv[4][4], tmat[4][4];
-
- invert_m4_m4(oldviewinv, re->viewmat_orig);
-
- /* we have to correct for the already rotated vertexcoords */
- mul_m4_m4m4(tmat, viewmat, oldviewinv);
-
- copy_m4_m4(re->viewmat, viewmat);
- invert_m4_m4(re->viewinv, re->viewmat);
-
- init_camera_inside_volumes(re);
-
- env_rotate_scene(re, tmat, !restore);
-
- /* SSS points distribution depends on view */
- if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
- make_sss_tree(re);
-}
-
-
-void RE_DataBase_GetView(Render *re, float mat[4][4])
-{
- copy_m4_m4(mat, re->viewmat);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Speed Vectors */
-/* ------------------------------------------------------------------------- */
-
-static void database_fromscene_vectors(Depsgraph *depsgraph,
- Render *re,
- Scene *scene,
- unsigned int lay,
- int timeoffset)
-{
- Object *camera= RE_GetCamera(re);
- float mat[4][4];
-
- re->scene= scene;
- re->lay= lay;
-
- /* XXX add test if dbase was filled already? */
-
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vector render db arena");
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0;
- re->lights.first= re->lights.last= NULL;
-
- /* applies changes fully */
- scene->r.cfra += timeoffset;
- BKE_scene_graph_update_for_newframe(depsgraph, re->main);
-
- /* if no camera, viewmat should have been set! */
- if (camera) {
- RE_GetCameraModelMatrix(re, camera, mat);
- normalize_m4(mat);
- invert_m4(mat);
- RE_SetView(re, mat);
- }
-
- /* MAKE RENDER DATA */
- database_init_objects(depsgraph, re, lay, 0, 0, NULL, timeoffset);
-
- if (!re->test_break(re->tbh))
- project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
-
- /* do this in end, particles for example need cfra */
- scene->r.cfra -= timeoffset;
-}
-
-/* choose to use static, to prevent giving too many args to this call */
-static void speedvector_project(Render *re, float zco[2], const float co[3], const float ho[4])
-{
- static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f;
- static int pano= 0;
- float div;
-
- /* initialize */
- if (re) {
- pano= re->r.mode & R_PANORAMA;
-
- /* precalculate amount of radians 1 pixel rotates */
- if (pano) {
- /* size of 1 pixel mapped to viewplane coords */
- float psize;
-
- psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx;
- /* x angle of a pixel */
- pixelphix = atan(psize / re->clipsta);
-
- psize = BLI_rctf_size_y(&re->viewplane) / (float)re->winy;
- /* y angle of a pixel */
- pixelphiy = atan(psize / re->clipsta);
- }
- zmulx= re->winx/2;
- zmuly= re->winy/2;
-
- return;
- }
-
- /* now map hocos to screenspace, uses very primitive clip still */
- if (ho[3]<0.1f) div= 10.0f;
- else div= 1.0f/ho[3];
-
- /* use cylinder projection */
- if (pano) {
- float vec[3], ang;
- /* angle between (0, 0, -1) and (co) */
- copy_v3_v3(vec, co);
-
- ang= saacos(-vec[2]/sqrtf(vec[0]*vec[0] + vec[2]*vec[2]));
- if (vec[0]<0.0f) ang= -ang;
- zco[0]= ang/pixelphix + zmulx;
-
- ang= 0.5f*(float)M_PI - saacos(vec[1] / len_v3(vec));
- zco[1]= ang/pixelphiy + zmuly;
-
- }
- else {
- zco[0]= zmulx*(1.0f+ho[0]*div);
- zco[1]= zmuly*(1.0f+ho[1]*div);
- }
-}
-
-static void calculate_speedvector(const float vectors[2], int step, float winsq, float winroot, const float co[3], const float ho[4], float speed[4])
-{
- float zco[2], len;
-
- speedvector_project(NULL, zco, co, ho);
-
- zco[0]= vectors[0] - zco[0];
- zco[1]= vectors[1] - zco[1];
-
- /* enable nice masks for hardly moving stuff or float inaccuracy */
- if (zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
- zco[0]= 0.0f;
- zco[1]= 0.0f;
- }
-
- /* maximize speed for image width, otherwise it never looks good */
- len= zco[0]*zco[0] + zco[1]*zco[1];
- if (len > winsq) {
- len= winroot/sqrtf(len);
- zco[0]*= len;
- zco[1]*= len;
- }
-
- /* note; in main vecblur loop speedvec is negated again */
- if (step) {
- speed[2]= -zco[0];
- speed[3]= -zco[1];
- }
- else {
- speed[0]= zco[0];
- speed[1]= zco[1];
- }
-}
-
-static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen *obi, StrandSurface *mesh)
-{
- if (mesh->co && mesh->prevco && mesh->nextco) {
- float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */
- float winroot= sqrtf(winsq);
- float (*winspeed)[4];
- float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
- int a;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- winspeed= MEM_callocN(sizeof(float)*4*mesh->totvert, "StrandSurfWin");
-
- for (a=0; a<mesh->totvert; a++) {
- projectvert(mesh->co[a], winmat, ho);
-
- projectvert(mesh->prevco[a], winmat, prevho);
- speedvector_project(NULL, vec, mesh->prevco[a], prevho);
- calculate_speedvector(vec, 0, winsq, winroot, mesh->co[a], ho, winspeed[a]);
-
- projectvert(mesh->nextco[a], winmat, nextho);
- speedvector_project(NULL, vec, mesh->nextco[a], nextho);
- calculate_speedvector(vec, 1, winsq, winroot, mesh->co[a], ho, winspeed[a]);
- }
-
- return (float *)winspeed;
- }
-
- return NULL;
-}
-
-static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
-{
- ObjectRen *obr= obi->obr;
- VertRen *ver= NULL;
- StrandRen *strand= NULL;
- StrandBuffer *strandbuf;
- StrandSurface *mesh= NULL;
- float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
- float *co1, *co2, *co3, *co4, w[4];
- float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq); /* int's can wrap on large images */
- int a, *face, *index;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- if (obr->vertnodes) {
- for (a=0; a<obr->totvert; a++, vectors+=2) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- speed= RE_vertren_get_winspeed(obi, ver, 1);
- projectvert(ver->co, winmat, ho);
- calculate_speedvector(vectors, step, winsq, winroot, ver->co, ho, speed);
- }
- }
-
- if (obr->strandnodes) {
- strandbuf= obr->strandbuf;
- mesh= (strandbuf)? strandbuf->surface: NULL;
-
- /* compute speed vectors at surface vertices */
- if (mesh)
- winspeed= (float(*)[4])calculate_strandsurface_speedvectors(re, obi, mesh);
-
- if (winspeed) {
- for (a=0; a<obr->totstrand; a++, vectors+=2) {
- if ((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
-
- index= RE_strandren_get_face(obr, strand, 0);
- if (index && *index < mesh->totface) {
- speed= RE_strandren_get_winspeed(obi, strand, 1);
-
- /* interpolate speed vectors from strand surface */
- face= mesh->face[*index];
-
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
- interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
- }
- else {
- interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
- }
-
- zero_v4(speed);
- madd_v4_v4fl(speed, winspeed[face[0]], w[0]);
- madd_v4_v4fl(speed, winspeed[face[1]], w[1]);
- madd_v4_v4fl(speed, winspeed[face[2]], w[2]);
- if (face[3])
- madd_v4_v4fl(speed, winspeed[face[3]], w[3]);
- }
- }
-
- MEM_freeN(winspeed);
- }
- }
-}
-
-static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
-{
- ObjectRen *obr= obi->obr;
- Object *fsob= obr->ob;
- VertRen *ver= NULL;
- float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0};
- float zmulx= re->winx/2, zmuly= re->winy/2, len;
- float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */
- int a, j;
- float hoco[4], ho[4], fsvec[4], camco[4];
- float mat[4][4], winmat[4][4];
- float imat[4][4];
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsob, eModifierType_Fluidsim);
- FluidsimSettings *fss;
- FluidVertexVelocity *velarray = NULL;
-
- /* only one step needed */
- if (step) return 1;
-
- if (fluidmd)
- fss = fluidmd->fss;
- else
- return 0;
-
- copy_m4_m4(mat, re->viewmat);
- invert_m4_m4(imat, mat);
-
- /* set first vertex OK */
- if (!fss->meshVelocities) return 0;
-
- if ( obr->totvert != fss->totvert) {
- //fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", obr->totvert, fsob->fluidsimSettings->meshSurface->totvert); // DEBUG
- return 0;
- }
-
- velarray = fss->meshVelocities;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- /* (bad) HACK calculate average velocity */
- /* better solution would be fixing getVelocityAt() in intern/elbeem/intern/solver_util.cpp
- * so that also small drops/little water volumes return a velocity != 0.
- * But I had no luck in fixing that function - DG */
- for (a=0; a<obr->totvert; a++) {
- for (j=0;j<3;j++) avgvel[j] += velarray[a].vel[j];
-
- }
- for (j=0;j<3;j++) avgvel[j] /= (float)(obr->totvert);
-
-
- for (a=0; a<obr->totvert; a++, vectors+=2) {
- if ((a & 255)==0)
- ver= obr->vertnodes[a>>8].vert;
- else
- ver++;
-
- /* get fluid velocity */
- fsvec[3] = 0.0f;
- //fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.0; fsvec[2] = 2.0f; // NT fixed test
- for (j=0;j<3;j++) fsvec[j] = velarray[a].vel[j];
-
- /* (bad) HACK insert average velocity if none is there (see previous comment) */
- if ((fsvec[0] == 0.0f) && (fsvec[1] == 0.0f) && (fsvec[2] == 0.0f)) {
- fsvec[0] = avgvel[0];
- fsvec[1] = avgvel[1];
- fsvec[2] = avgvel[2];
- }
-
- /* transform (=rotate) to cam space */
- camco[0] = dot_v3v3(imat[0], fsvec);
- camco[1] = dot_v3v3(imat[1], fsvec);
- camco[2] = dot_v3v3(imat[2], fsvec);
-
- /* get homogeneous coordinates */
- projectvert(camco, winmat, hoco);
- projectvert(ver->co, winmat, ho);
-
- /* now map hocos to screenspace, uses very primitive clip still */
- /* use ho[3] of original vertex, xy component of vel. direction */
- if (ho[3]<0.1f) div= 10.0f;
- else div= 1.0f/ho[3];
- zco[0]= zmulx*hoco[0]*div;
- zco[1]= zmuly*hoco[1]*div;
-
- /* maximize speed as usual */
- len= zco[0]*zco[0] + zco[1]*zco[1];
- if (len > winsq) {
- len= winroot/sqrtf(len);
- zco[0]*= len; zco[1]*= len;
- }
-
- speed= RE_vertren_get_winspeed(obi, ver, 1);
- /* set both to the same value */
- speed[0]= speed[2]= zco[0];
- speed[1]= speed[3]= zco[1];
- //if (a < 20) fprintf(stderr,"speed %d %f,%f | camco %f,%f,%f | hoco %f,%f,%f,%f\n", a, speed[0], speed[1], camco[0],camco[1], camco[2], hoco[0],hoco[1], hoco[2],hoco[3]); // NT DEBUG
- }
-
- return 1;
-}
-
-/* makes copy per object of all vectors */
-/* result should be that we can free entire database */
-static void copy_dbase_object_vectors(Render *re, ListBase *lb)
-{
- ObjectInstanceRen *obi, *obilb;
- ObjectRen *obr;
- VertRen *ver= NULL;
- float *vec, ho[4], winmat[4][4];
- int a, totvector;
-
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- obr= obi->obr;
-
- obilb= MEM_mallocN(sizeof(ObjectInstanceRen), "ObInstanceVector");
- memcpy(obilb, obi, sizeof(ObjectInstanceRen));
- BLI_addtail(lb, obilb);
-
- obilb->totvector= totvector= obr->totvert;
-
- if (totvector > 0) {
- vec= obilb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array");
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- for (a=0; a<obr->totvert; a++, vec+=2) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- projectvert(ver->co, winmat, ho);
- speedvector_project(NULL, vec, ver->co, ho);
- }
- }
- }
-}
-
-static void free_dbase_object_vectors(ListBase *lb)
-{
- ObjectInstanceRen *obi;
-
- for (obi= lb->first; obi; obi= obi->next)
- if (obi->vectors)
- MEM_freeN(obi->vectors);
- BLI_freelistN(lb);
-}
-
-void RE_Database_FromScene_Vectors(Depsgraph *depsgraph, Render *re, Main *bmain, Scene *sce, unsigned int lay)
-{
- ObjectInstanceRen *obi, *oldobi;
- StrandSurface *mesh;
- ListBase *table;
- ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL};
- ListBase strandsurface;
- int step;
-
- re->i.infostr = IFACE_("Calculating previous frame vectors");
- re->r.mode |= R_SPEED;
-
- speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */
-
- /* creates entire dbase */
- database_fromscene_vectors(depsgraph, re, sce, lay, -1);
-
- /* copy away vertex info */
- copy_dbase_object_vectors(re, &oldtable);
-
- /* free dbase and make the future one */
- strandsurface= re->strandsurface;
- memset(&re->strandsurface, 0, sizeof(ListBase));
- re->i.convertdone = true;
- RE_Database_Free(re);
- re->strandsurface= strandsurface;
-
- if (!re->test_break(re->tbh)) {
- /* creates entire dbase */
- re->i.infostr = IFACE_("Calculating next frame vectors");
-
- database_fromscene_vectors(depsgraph, re, sce, lay, +1);
- }
- /* copy away vertex info */
- copy_dbase_object_vectors(re, &newtable);
-
- /* free dbase and make the real one */
- strandsurface= re->strandsurface;
- memset(&re->strandsurface, 0, sizeof(ListBase));
- re->i.convertdone = true;
- RE_Database_Free(re);
- re->strandsurface= strandsurface;
-
- if (!re->test_break(re->tbh)) {
- RE_Database_FromScene(re, bmain, sce, lay, 1);
- RE_Database_Preprocess(depsgraph, re);
- }
-
- if (!re->test_break(re->tbh)) {
- int vectorlay= get_vector_viewlayers(re->scene);
-
- for (step= 0; step<2; step++) {
-
- if (step)
- table= &newtable;
- else
- table= &oldtable;
-
- oldobi= table->first;
- for (obi= re->instancetable.first; obi && oldobi; obi= obi->next) {
- int ok= 1;
- FluidsimModifierData *fluidmd;
-
- if (!(obi->lay & vectorlay))
- continue;
-
- obi->totvector= obi->obr->totvert;
-
- /* find matching object in old table */
- if (oldobi->ob!=obi->ob || oldobi->par!=obi->par || oldobi->index!=obi->index || oldobi->psysindex!=obi->psysindex) {
- ok= 0;
- for (oldobi= table->first; oldobi; oldobi= oldobi->next)
- if (oldobi->ob==obi->ob && oldobi->par==obi->par && oldobi->index==obi->index && oldobi->psysindex==obi->psysindex)
- break;
- if (oldobi==NULL)
- oldobi= table->first;
- else
- ok= 1;
- }
- if (ok==0) {
- printf("speed table: missing object %s\n", obi->ob->id.name + 2);
- continue;
- }
-
- /* NT check for fluidsim special treatment */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(obi->ob, eModifierType_Fluidsim);
- if (fluidmd && fluidmd->fss && (fluidmd->fss->type & OB_FLUIDSIM_DOMAIN)) {
- /* use preloaded per vertex simulation data, only does calculation for step=1 */
- /* NOTE/FIXME - velocities and meshes loaded unnecessarily often during the database_fromscene_vectors calls... */
- load_fluidsimspeedvectors(re, obi, oldobi->vectors, step);
- }
- else {
- /* check if both have same amounts of vertices */
- if (obi->totvector==oldobi->totvector)
- calculate_speedvectors(re, obi, oldobi->vectors, step);
- else
- printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name + 2);
- } /* not fluidsim */
-
- oldobi= oldobi->next;
- }
- }
- }
-
- free_dbase_object_vectors(&oldtable);
- free_dbase_object_vectors(&newtable);
-
- for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
- if (mesh->prevco) {
- MEM_freeN(mesh->prevco);
- mesh->prevco= NULL;
- }
- if (mesh->nextco) {
- MEM_freeN(mesh->nextco);
- mesh->nextco= NULL;
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-
-/* ------------------------------------------------------------------------- */
-/* Baking */
-/* ------------------------------------------------------------------------- */
-
-/* setup for shaded view or bake, so only lamps and materials are initialized */
-/* type:
- * RE_BAKE_LIGHT: for shaded view, only add lamps
- * RE_BAKE_ALL: for baking, all lamps and objects
- * RE_BAKE_NORMALS:for baking, no lamps and only selected objects
- * RE_BAKE_AO: for baking, no lamps, but all objects
- * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects
- * RE_BAKE_VERTEX_COLORS:for baking, no lamps, only selected objects
- * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects
- * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects
- * RE_BAKE_SHADOW: for baking, only shadows, but all objects
- */
-void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer,
- unsigned int lay, const int type, Object *actob)
-{
- Object *camera;
- float mat[4][4];
- float amb[3];
- const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
- const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
-
- re->main= bmain;
- re->scene= scene;
- re->lay= lay;
-
- /* renderdata setup and exceptions */
- render_copy_renderdata(&re->r, &scene->r);
-
- RE_init_threadcount(re);
-
- Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
- DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
-
- re->flag |= R_BAKING;
- re->excludeob= actob;
- if (actob)
- re->flag |= R_BAKE_TRACE;
-
- if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT)
- re->flag |= R_NEED_TANGENT;
-
- if (type==RE_BAKE_VERTEX_COLORS)
- re->flag |= R_NEED_VCOL;
-
- if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
- re->r.mode &= ~R_SHADOW;
- re->r.mode &= ~R_RAYTRACE;
- }
-
- if (!actob && (type==RE_BAKE_SHADOW)) {
- re->r.mode |= R_SHADOW;
- }
-
- /* setup render stuff */
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bake db arena");
-
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->lights.first= re->lights.last= NULL;
- re->lampren.first= re->lampren.last= NULL;
-
- /* in localview, lamps are using normal layers, objects only local bits */
- if (re->lay & 0xFF000000)
- lay &= 0xFF000000;
-
- camera= RE_GetCamera(re);
-
- /* if no camera, set unit */
- if (camera) {
- normalize_m4_m4(mat, camera->obmat);
- invert_m4(mat);
- RE_SetView(re, mat);
- }
- else {
- unit_m4(mat);
- RE_SetView(re, mat);
- }
- copy_m3_m4(re->imat, re->viewinv);
-
- /* TODO: deep shadow maps + baking + strands */
- /* strands use the window matrix and view size, there is to correct
- * window matrix but at least avoids malloc and crash loop [#27807] */
- unit_m4(re->winmat);
- re->winx= re->winy= 256;
- /* done setting dummy values */
-
- init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if (re->r.mode & R_RAYTRACE) {
- init_render_qmcsampler(re);
-
- if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
- if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(re, &re->wrld);
- }
-
- /* still bad... doing all */
- init_render_textures(re);
-
- copy_v3_v3(amb, &re->wrld.ambr);
- init_render_materials(re->main, re->r.mode, amb, true);
-
- set_node_shader_lamp_loop(shade_material_loop);
-
- /* MAKE RENDER DATA */
- database_init_objects(depsgraph, re, lay, nolamps, onlyselected, actob, 0);
-
- set_material_lightgroups(re);
-
- /* SHADOW BUFFER */
- if (type!=RE_BAKE_LIGHT)
- if (re->r.mode & R_SHADOW)
- threaded_makeshadowbufs(re);
-
- /* raytree */
- if (!re->test_break(re->tbh))
- if (re->r.mode & R_RAYTRACE)
- makeraytree(re);
-
- /* point density texture */
- if (!re->test_break(re->tbh))
- make_pointdensities(depsgraph, re);
-
- /* voxel data texture */
- if (!re->test_break(re->tbh))
- make_voxeldata(re);
-
- /* occlusion */
- if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
- if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
- if (re->r.mode & R_SHADOW)
- make_occ_tree(re);
-
- re->i.convertdone = true;
-}
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
deleted file mode 100644
index a5f914b5ca1..00000000000
--- a/source/blender/render/intern/source/envmap.c
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * ***** 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 "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_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_lamp_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_main.h"
-#include "BKE_image.h" /* BKE_imbuf_write */
-#include "BKE_layer.h"
-#include "BKE_texture.h"
-#include "BKE_scene.h"
-
-/* this module */
-#include "render_types.h"
-#include "envmap.h"
-#include "renderdatabase.h"
-#include "renderpipeline.h"
-#include "texture.h"
-#include "zbuf.h"
-#include "render_result.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_thread_lock(LOCK_IMAGE);
- if (env->cube[1] == NULL) {
-
- BKE_texture_envmap_free_data(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_thread_unlock(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.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
- BLI_freelistN(&envre->view_layers);
- BLI_freelistN(&envre->r.views);
- 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, &re->view_layers, re->active_view_layer, NULL, cuberes, cuberes, NULL);
- envre->main = re->main;
- 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);
- copy_m4_m4(envre->viewmat_orig, re->viewmat_orig);
-
- /* callbacks */
- envre->display_update = re->display_update;
- envre->duh = re->duh;
- envre->test_break = re->test_break;
- envre->tbh = re->tbh;
- envre->current_scene_update = re->current_scene_update;
- envre->suh = re->suh;
-
- /* 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;
- BLI_listbase_clear(&envre->lights);
- BLI_listbase_clear(&envre->objecttable);
- BLI_listbase_clear(&envre->customdata_names);
- envre->raytree = NULL;
- BLI_listbase_clear(&envre->instancetable);
- 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_m4_m4m4(mat, tmat, rotmat);
-}
-/* ------------------------------------------------------------------------- */
-
-static void env_set_imats(Render *re)
-{
- float mat[4][4];
-
- FOREACH_SCENE_OBJECT_BEGIN(re->scene, ob)
- {
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- }
- FOREACH_SCENE_OBJECT_END;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- LampRen *lar = NULL;
- HaloRen *har = NULL;
- float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
- int a;
-
- if (do_rotate == 0) {
- invert_m4_m4(tmat, mat);
- copy_m3_m4(imat, tmat);
-
- copy_m4_m4(mat_inverse, mat);
- }
- else {
- copy_m4_m4(tmat, mat);
- copy_m3_m4(imat, mat);
-
- invert_m4_m4(mat_inverse, tmat);
- }
-
- 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);
- mul_m4_m4m4(obi->mat, tmat, tmpmat);
- }
- else if (do_rotate == 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 (do_rotate == 0)
- obi->flag &= ~R_ENV_TRANSFORMED;
- else {
- obi->flag |= R_ENV_TRANSFORMED;
- copy_m4_m4(obi->imat, mat_inverse);
- }
- }
-
-
- 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);
- }
-
- /* imat_ren is needed for correct texture coordinates */
- mul_m4_m4m4(obr->ob->imat_ren, re->viewmat, obr->ob->obmat);
- invert_m4(obr->ob->imat_ren);
- }
-
- for (lar = re->lampren.first; lar; lar = lar->next) {
- float lamp_imat[4][4];
-
- /* copy from add_render_lamp */
- if (do_rotate == 1)
- mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat);
- else
- mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat);
-
- invert_m4_m4(lamp_imat, tmpmat);
- copy_m3_m4(lar->mat, tmpmat);
- copy_m3_m4(lar->imat, lamp_imat);
-
- lar->vec[0]= -tmpmat[2][0];
- lar->vec[1]= -tmpmat[2][1];
- lar->vec[2]= -tmpmat[2][2];
- normalize_v3(lar->vec);
- lar->co[0]= tmpmat[3][0];
- lar->co[1]= tmpmat[3][1];
- lar->co[2]= tmpmat[3][2];
-
- if (lar->type == LA_AREA) {
- area_lamp_vectors(lar);
- }
- else if (lar->type == LA_SPOT) {
- normalize_v3(lar->imat[0]);
- normalize_v3(lar->imat[1]);
- normalize_v3(lar->imat[2]);
-
- 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 (do_rotate == 1) {
- mul_m4_m4m4(smat, lar->shb->viewmat, mat_inverse);
- mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat);
- }
- else mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat);
- }
- }
- }
-
- if (do_rotate) {
- init_render_world(re);
- env_set_imats(re);
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-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 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 */
- mul_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 */
- mul_m4_m4m4(tmat, envre->viewmat, oldviewinv);
- invert_m4_m4(env->imat, tmat);
-
- env_rotate_scene(envre, tmat, 1);
- project_renderdata(envre, projectverto, 0, 0, 1);
- env_layerflags(envre, env->notlay);
- env_hideobject(envre, env->object);
-
- 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) {
- int y;
- float *alpha;
- float *rect;
-
- if (envre->result->do_exr_tile) {
- BLI_rw_mutex_lock(&envre->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(envre);
- BLI_rw_mutex_unlock(&envre->resultmutex);
- }
-
- RenderLayer *rl = envre->result->layers.first;
-
- /* envmap is rendered independently of multiview */
- rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, "");
- ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
- memcpy(ibuf->rect_float, rect, 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_texture_envmap_free_data(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;
- bool do_init = false;
- int 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 */
- mul_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_texture_envmap_free_data(env);
- /* free when size larger */
- else if (env->lastsize < re->r.size)
- BKE_texture_envmap_free_data(env);
- /* free when env is in recalcmode */
- else if (env->recalc)
- BKE_texture_envmap_free_data(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, const bool skip_load_image)
-{
- 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;
-
- if (env->type == ENV_PLANE)
- tex->extend = TEX_EXTEND;
-
- 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);
- if (osatex) {
- mul_m3_v3(env->obimat, dxt);
- mul_m3_v3(env->obimat, dyt);
- }
- }
- else {
- if (!BKE_scene_use_world_space_shading(R.scene)) {
- // texvec is in view space
- mul_mat3_m4_v3(R.viewinv, vec);
- if (osatex) {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
- }
- }
-
- face = envcube_isect(env, vec, sco);
- ibuf = env->cube[face];
-
- if (osatex) {
- set_dxtdyt(dxts, dyts, dxt, dyt, face);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
-
- /* 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, skip_load_image);
- }
- 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, skip_load_image);
- }
- 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, skip_load_image);
- }
-
- return 1;
-}
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 79a414381db..03be96a20bc 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -47,6 +47,7 @@
#include "BKE_global.h"
#include "BKE_colortools.h"
#include "BKE_layer.h"
+#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -69,22 +70,13 @@
#include "renderpipeline.h"
#include "render_types.h"
#include "render_result.h"
-#include "rendercore.h"
/* Render Engine Types */
-static RenderEngineType internal_render_type = {
- NULL, NULL,
- "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL | RE_USE_LEGACY_PIPELINE,
- NULL, NULL, NULL, NULL, NULL, NULL, render_internal_update_passes, NULL, NULL, NULL,
- {NULL, NULL, NULL}
-};
-
ListBase R_engines = {NULL, NULL};
void RE_engines_init(void)
{
- RE_engines_register(NULL, &internal_render_type);
DRW_engines_register();
}
@@ -133,7 +125,7 @@ RenderEngineType *RE_engines_find(const char *idname)
type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
if (!type)
- type = &internal_render_type;
+ type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname));
return type;
}
@@ -493,13 +485,6 @@ rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_
}
tiles[total_tiles] = pa->disprect;
- if (pa->crop) {
- tiles[total_tiles].xmin += pa->crop;
- tiles[total_tiles].ymin += pa->crop;
- tiles[total_tiles].xmax -= pa->crop;
- tiles[total_tiles].ymax -= pa->crop;
- }
-
total_tiles++;
}
}
@@ -601,7 +586,7 @@ bool RE_bake_engine(
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
- RE_parts_init(re, false);
+ RE_parts_init(re);
engine->tile_x = re->r.tilex;
engine->tile_y = re->r.tiley;
@@ -733,7 +718,7 @@ int RE_engine_render(Render *re, int do_all)
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
- RE_parts_init(re, false);
+ RE_parts_init(re);
engine->tile_x = re->partx;
engine->tile_y = re->party;
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 6e5d10fcc84..db28a5db531 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -53,16 +53,11 @@
#include "BKE_image.h"
#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
#include "render_types.h"
#include "texture.h"
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, const short imaprepeat, const short imapextend);
/* *********** IMAGEWRAPPING ****************** */
@@ -211,11 +206,6 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
}
}
- /* warning, no return before setting back! */
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect+= (ibuf->x*ibuf->y);
- }
-
/* keep this before interpolation [#29761] */
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
@@ -243,10 +233,6 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
ibuf_get_color(&texres->tr, ibuf, x, y);
}
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect-= (ibuf->x*ibuf->y);
- }
-
if (texres->nor) {
if (tex->imaflag & TEX_NORMALMAP) {
/* qdn: normal from color
@@ -979,17 +965,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
fy = texvec[1];
}
- if (ibuf->flags & IB_fields) {
- if (R.r.mode & R_FIELDS) { /* field render */
- if (R.flag & R_SEC_FIELD) { /* correction for 2nd field */
- /* fac1= 0.5/( (float)ibuf->y ); */
- /* fy-= fac1; */
- }
- else /* first field */
- fy += 0.5f/( (float)ibuf->y );
- }
- }
-
/* pixel coordinates */
minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
@@ -1129,10 +1104,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
intpol = tex->imaflag & TEX_INTERPOL;
- /* warning no return! */
- if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
- ibuf->rect += ibuf->x*ibuf->y;
-
/* struct common data */
copy_v2_v2(AFD.dxt, dxt);
copy_v2_v2(AFD.dyt, dyt);
@@ -1311,9 +1282,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
texres->tin = texres->ta;
if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta;
- if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
- ibuf->rect -= ibuf->x*ibuf->y;
-
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */
/* The invert of the red channel is to make
* the normal map compliant with the outside world.
@@ -1411,18 +1379,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
fy= texvec[1];
}
- if (ibuf->flags & IB_fields) {
- if (R.r.mode & R_FIELDS) { /* field render */
- if (R.flag & R_SEC_FIELD) { /* correction for 2nd field */
- /* fac1= 0.5/( (float)ibuf->y ); */
- /* fy-= fac1; */
- }
- else { /* first field */
- fy+= 0.5f/( (float)ibuf->y );
- }
- }
- }
-
/* pixel coordinates */
minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
@@ -1580,11 +1536,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
}
}
- /* warning no return! */
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect+= (ibuf->x*ibuf->y);
- }
-
/* choice: */
if (tex->imaflag & TEX_MIPMAP) {
ImBuf *previbuf, *curibuf;
@@ -1731,10 +1682,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect-= (ibuf->x*ibuf->y);
- }
-
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
/* qdn: normal from color
* The invert of the red channel is to make
@@ -1772,16 +1719,10 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu
return;
}
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
- ibuf->rect+= (ibuf->x*ibuf->y);
-
texres.talpha = true; /* boxsample expects to be initialized */
boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1);
copy_v4_v4(result, &texres.tr);
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
- ibuf->rect-= (ibuf->x*ibuf->y);
-
ima->flag|= IMA_USED_FOR_RENDER;
BKE_image_pool_release_ibuf(ima, ibuf, pool);
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 13c95dac05d..4274d641674 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -38,18 +38,12 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
#include "BLI_utildefines.h"
#include "DNA_camera_types.h"
-#include "DNA_image_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_camera.h"
-#include "DEG_depsgraph.h"
-
/* this module */
#include "renderpipeline.h"
#include "render_types.h"
@@ -58,31 +52,6 @@
#include "initrender.h"
-/* ********************** */
-
-static void init_render_jit(Render *re)
-{
- static float jit[32][2]; /* simple caching */
- static float mblur_jit[32][2]; /* simple caching */
- static int lastjit = 0;
- static int last_mblur_jit = 0;
-
- if (lastjit != re->r.osa || last_mblur_jit != re->r.mblur_samples) {
- memset(jit, 0, sizeof(jit));
- BLI_jitter_init(jit, re->r.osa);
-
- memset(mblur_jit, 0, sizeof(mblur_jit));
- BLI_jitter_init(mblur_jit, re->r.mblur_samples);
- }
-
- lastjit = re->r.osa;
- memcpy(re->jit, jit, sizeof(jit));
-
- last_mblur_jit = re->r.mblur_samples;
- memcpy(re->mblur_jit, mblur_jit, sizeof(mblur_jit));
-}
-
-
/* ****************** MASKS and LUTS **************** */
static float filt_quadratic(float x)
@@ -173,256 +142,6 @@ float RE_filter_value(int type, float x)
return 0.0f;
}
-static float calc_weight(Render *re, float *weight, int i, int j)
-{
- float x, y, dist, totw = 0.0;
- int a;
-
- for (a = 0; a < re->osa; a++) {
- x = re->jit[a][0] + i;
- y = re->jit[a][1] + j;
- dist = sqrtf(x * x + y * y);
-
- weight[a] = 0.0;
-
- /* Weighting choices */
- switch (re->r.filtertype) {
- case R_FILTER_BOX:
- if (i == 0 && j == 0) weight[a] = 1.0;
- break;
-
- case R_FILTER_TENT:
- if (dist < re->r.gauss)
- weight[a] = re->r.gauss - dist;
- break;
-
- case R_FILTER_GAUSS:
- x = dist * re->r.gauss;
- weight[a] = (1.0f / expf(x * x) - 1.0f / expf(re->r.gauss * re->r.gauss * 2.25f));
- break;
-
- case R_FILTER_MITCH:
- weight[a] = filt_mitchell(dist * re->r.gauss);
- break;
-
- case R_FILTER_QUAD:
- weight[a] = filt_quadratic(dist * re->r.gauss);
- break;
-
- case R_FILTER_CUBIC:
- weight[a] = filt_cubic(dist * re->r.gauss);
- break;
-
- case R_FILTER_CATROM:
- weight[a] = filt_catrom(dist * re->r.gauss);
- break;
-
- }
-
- totw += weight[a];
-
- }
- return totw;
-}
-
-void free_sample_tables(Render *re)
-{
- int a;
-
- if (re->samples) {
- for (a = 0; a < 9; a++) {
- MEM_freeN(re->samples->fmask1[a]);
- MEM_freeN(re->samples->fmask2[a]);
- }
-
- MEM_freeN(re->samples->centmask);
- MEM_freeN(re->samples);
- re->samples = NULL;
- }
-}
-
-/* based on settings in render, it makes the lookup tables */
-void make_sample_tables(Render *re)
-{
- static int firsttime = 1;
- SampleTables *st;
- float flweight[32];
- float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
- int i, j, a, centmasksize;
-
- /* optimization tables, only once */
- if (firsttime) {
- firsttime = 0;
- }
-
- free_sample_tables(re);
-
- init_render_jit(re); /* needed for mblur too */
-
- if (re->osa == 0) {
- /* just prevents cpu cycles for larger render and copying */
- re->r.filtertype = 0;
- return;
- }
-
- st = re->samples = MEM_callocN(sizeof(SampleTables), "sample tables");
-
- for (a = 0; a < 9; a++) {
- st->fmask1[a] = MEM_callocN(256 * sizeof(float), "initfilt");
- st->fmask2[a] = MEM_callocN(256 * sizeof(float), "initfilt");
- }
- for (a = 0; a < 256; a++) {
- st->cmask[a] = 0;
- if (a & 1) st->cmask[a]++;
- if (a & 2) st->cmask[a]++;
- if (a & 4) st->cmask[a]++;
- if (a & 8) st->cmask[a]++;
- if (a & 16) st->cmask[a]++;
- if (a & 32) st->cmask[a]++;
- if (a & 64) st->cmask[a]++;
- if (a & 128) st->cmask[a]++;
- }
-
- centmasksize = (1 << re->osa);
- st->centmask = MEM_mallocN(centmasksize, "Initfilt3");
-
- for (a = 0; a < 16; a++) {
- st->centLut[a] = -0.45f + ((float)a) / 16.0f;
- }
-
- /* calculate totw */
- totw = 0.0;
- for (j = -1; j < 2; j++) {
- for (i = -1; i < 2; i++) {
- totw += calc_weight(re, weight, i, j);
- }
- }
-
- for (j = -1; j < 2; j++) {
- for (i = -1; i < 2; i++) {
- /* calculate using jit, with offset the weights */
-
- memset(weight, 0, sizeof(weight));
- calc_weight(re, weight, i, j);
-
- for (a = 0; a < 16; a++) flweight[a] = weight[a] * (1.0f / totw);
-
- m3 = st->fmask1[3 * (j + 1) + i + 1];
- m4 = st->fmask2[3 * (j + 1) + i + 1];
-
- for (a = 0; a < 256; a++) {
- if (a & 1) {
- m3[a] += flweight[0];
- m4[a] += flweight[8];
- }
- if (a & 2) {
- m3[a] += flweight[1];
- m4[a] += flweight[9];
- }
- if (a & 4) {
- m3[a] += flweight[2];
- m4[a] += flweight[10];
- }
- if (a & 8) {
- m3[a] += flweight[3];
- m4[a] += flweight[11];
- }
- if (a & 16) {
- m3[a] += flweight[4];
- m4[a] += flweight[12];
- }
- if (a & 32) {
- m3[a] += flweight[5];
- m4[a] += flweight[13];
- }
- if (a & 64) {
- m3[a] += flweight[6];
- m4[a] += flweight[14];
- }
- if (a & 128) {
- m3[a] += flweight[7];
- m4[a] += flweight[15];
- }
- }
- }
- }
-
- /* centmask: the correct subpixel offset per mask */
-
- fpx1 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpx2 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpy1 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpy2 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- for (a = 0; a < 256; a++) {
- fpx1[a] = fpx2[a] = 0.0;
- fpy1[a] = fpy2[a] = 0.0;
- if (a & 1) {
- fpx1[a] += re->jit[0][0];
- fpy1[a] += re->jit[0][1];
- fpx2[a] += re->jit[8][0];
- fpy2[a] += re->jit[8][1];
- }
- if (a & 2) {
- fpx1[a] += re->jit[1][0];
- fpy1[a] += re->jit[1][1];
- fpx2[a] += re->jit[9][0];
- fpy2[a] += re->jit[9][1];
- }
- if (a & 4) {
- fpx1[a] += re->jit[2][0];
- fpy1[a] += re->jit[2][1];
- fpx2[a] += re->jit[10][0];
- fpy2[a] += re->jit[10][1];
- }
- if (a & 8) {
- fpx1[a] += re->jit[3][0];
- fpy1[a] += re->jit[3][1];
- fpx2[a] += re->jit[11][0];
- fpy2[a] += re->jit[11][1];
- }
- if (a & 16) {
- fpx1[a] += re->jit[4][0];
- fpy1[a] += re->jit[4][1];
- fpx2[a] += re->jit[12][0];
- fpy2[a] += re->jit[12][1];
- }
- if (a & 32) {
- fpx1[a] += re->jit[5][0];
- fpy1[a] += re->jit[5][1];
- fpx2[a] += re->jit[13][0];
- fpy2[a] += re->jit[13][1];
- }
- if (a & 64) {
- fpx1[a] += re->jit[6][0];
- fpy1[a] += re->jit[6][1];
- fpx2[a] += re->jit[14][0];
- fpy2[a] += re->jit[14][1];
- }
- if (a & 128) {
- fpx1[a] += re->jit[7][0];
- fpy1[a] += re->jit[7][1];
- fpx2[a] += re->jit[15][0];
- fpy2[a] += re->jit[15][1];
- }
- }
-
- for (a = centmasksize - 1; a > 0; a--) {
- val = st->cmask[a & 255] + st->cmask[a >> 8];
- i = 8 + (15.9f * (fpy1[a & 255] + fpy2[a >> 8]) / val);
- CLAMP(i, 0, 15);
- j = 8 + (15.9f * (fpx1[a & 255] + fpx2[a >> 8]) / val);
- CLAMP(j, 0, 15);
- i = j + (i << 4);
- st->centmask[a] = i;
- }
-
- MEM_freeN(fpx1);
- MEM_freeN(fpx2);
- MEM_freeN(fpy1);
- MEM_freeN(fpy2);
-}
-
-
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
struct Object *RE_GetCamera(Render *re)
{
@@ -437,37 +156,11 @@ static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_o
re->clipsta = params->clipsta;
re->clipend = params->clipend;
- re->ycor = params->ycor;
- re->viewdx = params->viewdx;
- re->viewdy = params->viewdy;
re->viewplane = params->viewplane;
BKE_camera_object_mode(&re->r, cam_ob);
}
-void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clipsta, float clipend)
-{
- CameraParams params;
-
- /* setup parameters */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
-
- params.lens = 16.0f * viewscale;
- params.sensor_x = 32.0f;
- params.sensor_y = 32.0f;
- params.sensor_fit = CAMERA_SENSOR_FIT_AUTO;
- params.clipsta = clipsta;
- params.clipend = clipend;
-
- /* compute matrix, viewplane, .. */
- BKE_camera_params_compute_viewplane(&params, re->winx, re->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- /* extract results */
- re_camera_params_get(re, &params, cam_ob);
-}
-
void RE_SetOverrideCamera(Render *re, Object *camera)
{
re->camera_override = camera;
@@ -489,10 +182,6 @@ void RE_SetCamera(Render *re, Object *cam_ob)
BKE_camera_params_from_object(&params, cam_ob);
re_camera_params_stereo3d(re, &params, cam_ob);
- params.use_fields = (re->r.mode & R_FIELDS);
- params.field_second = (re->flag & R_SEC_FIELD);
- params.field_odd = (re->r.mode & R_ODDFIELD);
-
/* compute matrix, viewplane, .. */
BKE_camera_params_compute_viewplane(&params, re->winx, re->winy, re->r.xasp, re->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -501,12 +190,6 @@ void RE_SetCamera(Render *re, Object *cam_ob)
re_camera_params_get(re, &params, cam_ob);
}
-void RE_SetPixelSize(Render *re, float pixsize)
-{
- re->viewdx = pixsize;
- re->viewdy = re->ycor * pixsize;
-}
-
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4])
{
re->r.cfra = frame;
@@ -524,13 +207,6 @@ void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4
void RE_parts_free(Render *re)
{
- RenderPart *part = re->parts.first;
-
- while (part) {
- if (part->rectp) MEM_freeN(part->rectp);
- if (part->rectz) MEM_freeN(part->rectz);
- part = part->next;
- }
BLI_freelistN(&re->parts);
}
@@ -541,7 +217,7 @@ void RE_parts_clamp(Render *re)
re->party = max_ii(1, min_ii(re->r.tiley, re->recty));
}
-void RE_parts_init(Render *re, bool do_crop)
+void RE_parts_init(Render *re)
{
int nr, xd, yd, partx, party, xparts, yparts;
int xminb, xmaxb, yminb, ymaxb;
@@ -567,10 +243,6 @@ void RE_parts_init(Render *re, bool do_crop)
xparts = (re->rectx + partx - 1) / partx;
yparts = (re->recty + party - 1) / party;
- /* calculate rotation factor of 1 pixel */
- if (re->r.mode & R_PANORAMA)
- re->panophi = panorama_pixel_rot(re);
-
for (nr = 0; nr < xparts * yparts; nr++) {
rcti disprect;
int rectx, recty;
@@ -603,16 +275,6 @@ void RE_parts_init(Render *re, bool do_crop)
if (rectx > 0 && recty > 0) {
RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part");
- /* Non-box filters need 2 pixels extra to work */
- if (do_crop && (re->r.filtertype || (re->r.mode & R_EDGE))) {
- pa->crop = 2;
- disprect.xmin -= pa->crop;
- disprect.ymin -= pa->crop;
- disprect.xmax += pa->crop;
- disprect.ymax += pa->crop;
- rectx += 2 * pa->crop;
- recty += 2 * pa->crop;
- }
pa->disprect = disprect;
pa->rectx = rectx;
pa->recty = recty;
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index ddab8b23b59..9fb7e718b18 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -36,6 +36,7 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -59,10 +60,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rendercore.h"
-
typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data,
void *bake_data, ImBuf *ibuf, const int face_index, const int lvl,
const float st[2], float tangmat[3][3], const int x, const int y);
@@ -115,19 +112,6 @@ typedef struct {
const int *orig_index_mp_to_orig;
} MNormalBakeData;
-typedef struct {
- int number_of_rays;
- float bias;
-
- unsigned short *permutation_table_1;
- unsigned short *permutation_table_2;
-
- RayObject *raytree;
- RayFace *rayfaces;
-
- const int *orig_index_mp_to_orig;
-} MAOBakeData;
-
static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int tri_num, const int vert_index)
{
const int poly_index = data->mlooptri[tri_num].poly;
@@ -884,6 +868,8 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
}
}
+/* TODO: restore ambient occlusion baking support, using BLI BVH? */
+#if 0
/* **************** Ambient Occlusion Baker **************** */
// must be a power of two
@@ -1176,6 +1162,68 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void
rrgb[3] = 255;
}
}
+#endif
+
+/* ******$***************** Post processing ************************* */
+
+static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
+{
+ /* must check before filtering */
+ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
+
+ /* Margin */
+ if (filter) {
+ IMB_filter_extend(ibuf, mask, filter);
+ }
+
+ /* if the bake results in new alpha then change the image setting */
+ if (is_new_alpha) {
+ ibuf->planes = R_IMF_PLANES_RGBA;
+ }
+ else {
+ if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
+ /* clear alpha added by filtering */
+ IMB_rectfill_alpha(ibuf, 1.0f);
+ }
+ }
+}
+
+static void bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
+{
+ int i;
+ const float *current_displacement = displacement;
+ const char *current_mask = mask;
+ float max_distance;
+
+ max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
+
+ for (i = 0; i < ibuf->x * ibuf->y; i++) {
+ if (*current_mask == FILTER_MASK_USED) {
+ float normalized_displacement;
+
+ if (max_distance > 1e-5f)
+ normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
+ else
+ normalized_displacement = 0.5f;
+
+ if (ibuf->rect_float) {
+ /* currently baking happens to RGBA only */
+ float *fp = ibuf->rect_float + i * 4;
+ fp[0] = fp[1] = fp[2] = normalized_displacement;
+ fp[3] = 1.0f;
+ }
+
+ if (ibuf->rect) {
+ unsigned char *cp = (unsigned char *) (ibuf->rect + i);
+ cp[0] = cp[1] = cp[2] = FTOCHAR(normalized_displacement);
+ cp[3] = 255;
+ }
+ }
+
+ current_displacement++;
+ current_mask++;
+ }
+}
/* **************** Common functions public API relates on **************** */
@@ -1229,12 +1277,14 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
do_multires_bake(bkr, ima, true, apply_tangmat_callback, init_normal_data, free_normal_data, result);
break;
case RE_BAKE_DISPLACEMENT:
- case RE_BAKE_DERIVATIVE:
do_multires_bake(bkr, ima, false, apply_heights_callback, init_heights_data, free_heights_data, result);
break;
+/* TODO: restore ambient occlusion baking support. */
+#if 0
case RE_BAKE_AO:
do_multires_bake(bkr, ima, false, apply_ao_callback, init_ao_data, free_ao_data, result);
break;
+#endif
}
}
@@ -1247,7 +1297,7 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
{
LinkData *link;
- bool use_displacement_buffer = ELEM(bkr->mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE);
+ bool use_displacement_buffer = bkr->mode == RE_BAKE_DISPLACEMENT;
for (link = bkr->image.first; link; link = link->next) {
Image *ima = (Image *)link->data;
@@ -1258,17 +1308,11 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
continue;
if (use_displacement_buffer) {
- if (bkr->mode == RE_BAKE_DERIVATIVE) {
- RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- result->height_min, result->height_max, bkr->user_scale);
- }
- else {
- RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- result->height_min, result->height_max);
- }
+ bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
+ result->height_min, result->height_max);
}
- RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
+ bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
deleted file mode 100644
index 42200a8278c..00000000000
--- a/source/blender/render/intern/source/occlusion.c
+++ /dev/null
@@ -1,1533 +0,0 @@
-/*
- * ***** 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) 2008 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/occlusion.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_memarena.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_node.h"
-#include "BKE_scene.h"
-
-
-#include "RE_shader_ext.h"
-
-/* local includes */
-#include "occlusion.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "shading.h"
-
-/* ------------------------- Declarations --------------------------- */
-
-#define INVPI ((float)M_1_PI)
-#define TOTCHILD 8
-#define CACHE_STEP 3
-
-typedef struct OcclusionCacheSample {
- float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2;
- int x, y, filled;
-} OcclusionCacheSample;
-
-typedef struct OcclusionCache {
- OcclusionCacheSample *sample;
- int x, y, w, h, step;
-} OcclusionCache;
-
-typedef struct OccFace {
- int obi;
- int facenr;
-} OccFace;
-
-typedef struct OccNode {
- float co[3], area;
- float sh[9], dco;
- float occlusion, rad[3];
- int childflag;
- union {
- //OccFace face;
- int face;
- struct OccNode *node;
- } child[TOTCHILD];
-} OccNode;
-
-typedef struct OcclusionTree {
- MemArena *arena;
-
- float (*co)[3]; /* temporary during build */
-
- OccFace *face; /* instance and face indices */
- float *occlusion; /* occlusion for faces */
- float (*rad)[3]; /* radiance for faces */
-
- OccNode *root;
-
- OccNode **stack[BLENDER_MAX_THREADS];
- int maxdepth;
-
- int totface;
-
- float error;
- float distfac;
-
- int dothreadedbuild;
- int totbuildthread;
- int doindirect;
-
- OcclusionCache *cache;
-
- int num_threads;
-} OcclusionTree;
-
-typedef struct OcclusionThread {
- Render *re;
- StrandSurface *mesh;
- float (*faceao)[3];
- float (*faceenv)[3];
- float (*faceindirect)[3];
- int begin, end;
- int thread;
-} OcclusionThread;
-
-typedef struct OcclusionBuildThread {
- OcclusionTree *tree;
- int begin, end, depth;
- OccNode *node;
-} OcclusionBuildThread;
-
-/* ------------------------- Shading --------------------------- */
-
-extern Render R; /* meh */
-
-static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
-{
- ShadeInput *shi = ssamp->shi;
- ShadeResult *shr = ssamp->shr;
- float l, u, v, *v1, *v2, *v3;
-
- /* init */
- if (vlr->v4) {
- shi->u = u = 0.5f;
- shi->v = v = 0.5f;
- }
- else {
- shi->u = u = 1.0f / 3.0f;
- shi->v = v = 1.0f / 3.0f;
- }
-
- /* setup render coordinates */
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
-
- /* renderco */
- l = 1.0f - u - v;
-
- shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
- shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
- shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
-
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* set up view vector */
- copy_v3_v3(shi->view, shi->co);
- normalize_v3(shi->view);
-
- /* cache for shadow */
- shi->samplenr++;
-
- shi->xs = 0; /* TODO */
- shi->ys = 0;
-
- shade_input_set_normals(shi);
-
- /* no normal flip */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */
-
- /* not a pretty solution, but fixes common cases */
- if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- }
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* render */
- shade_input_set_shade_texco(shi);
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
- }
- else {
- shade_material_loop(shi, shr);
- }
-
- copy_v3_v3(rad, shr->combined);
-}
-
-static void occ_build_shade(Render *re, OcclusionTree *tree)
-{
- ShadeSample ssamp;
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- int a;
-
- R = *re;
-
- /* setup shade sample with correct passes */
- memset(&ssamp, 0, sizeof(ShadeSample));
- ssamp.shi[0].lay = re->lay;
- ssamp.shi[0].passflag = SCE_PASS_DIFFUSE | SCE_PASS_RGBA;
- ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
- ssamp.tot = 1;
-
- for (a = 0; a < tree->totface; a++) {
- obi = &R.objectinstance[tree->face[a].obi];
- vlr = RE_findOrAddVlak(obi->obr, tree->face[a].facenr);
-
- occ_shade(&ssamp, obi, vlr, tree->rad[a]);
-
- if (re->test_break(re->tbh))
- break;
- }
-}
-
-/* ------------------------- Spherical Harmonics --------------------------- */
-
-/* Use 2nd order SH => 9 coefficients, stored in this order:
- * 0 = (0,0),
- * 1 = (1,-1), 2 = (1,0), 3 = (1,1),
- * 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */
-
-static void sh_copy(float *shresult, float *sh)
-{
- memcpy(shresult, sh, sizeof(float) * 9);
-}
-
-static void sh_mul(float *sh, float f)
-{
- int i;
-
- for (i = 0; i < 9; i++)
- sh[i] *= f;
-}
-
-static void sh_add(float *shresult, float *sh1, float *sh2)
-{
- int i;
-
- for (i = 0; i < 9; i++)
- shresult[i] = sh1[i] + sh2[i];
-}
-
-static void sh_from_disc(float *n, float area, float *shresult)
-{
- /* See formula (3) in:
- * "An Efficient Representation for Irradiance Environment Maps" */
- float sh[9], x, y, z;
-
- x = n[0];
- y = n[1];
- z = n[2];
-
- sh[0] = 0.282095f;
-
- sh[1] = 0.488603f * y;
- sh[2] = 0.488603f * z;
- sh[3] = 0.488603f * x;
-
- sh[4] = 1.092548f * x * y;
- sh[5] = 1.092548f * y * z;
- sh[6] = 0.315392f * (3.0f * z * z - 1.0f);
- sh[7] = 1.092548f * x * z;
- sh[8] = 0.546274f * (x * x - y * y);
-
- sh_mul(sh, area);
- sh_copy(shresult, sh);
-}
-
-static float sh_eval(float *sh, float *v)
-{
- /* See formula (13) in:
- * "An Efficient Representation for Irradiance Environment Maps" */
- static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f;
- static const float c4 = 0.886227f, c5 = 0.247708f;
- float x, y, z, sum;
-
- x = v[0];
- y = v[1];
- z = v[2];
-
- sum = c1 * sh[8] * (x * x - y * y);
- sum += c3 * sh[6] * z * z;
- sum += c4 * sh[0];
- sum += -c5 * sh[6];
- sum += 2.0f * c1 * (sh[4] * x * y + sh[7] * x * z + sh[5] * y * z);
- sum += 2.0f * c2 * (sh[3] * x + sh[1] * y + sh[2] * z);
-
- return sum;
-}
-
-/* ------------------------------ Building --------------------------------- */
-
-static void occ_face(const OccFace *face, float co[3], float normal[3], float *area)
-{
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- float v1[3], v2[3], v3[3], v4[3];
-
- obi = &R.objectinstance[face->obi];
- vlr = RE_findOrAddVlak(obi->obr, face->facenr);
-
- if (co) {
- if (vlr->v4)
- mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co);
- else
- mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, co);
- }
-
- if (normal) {
- normal[0] = -vlr->n[0];
- normal[1] = -vlr->n[1];
- normal[2] = -vlr->n[2];
-
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, normal);
- }
-
- if (area) {
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
- if (vlr->v4) copy_v3_v3(v4, vlr->v4->co);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- if (vlr->v4) mul_m4_v3(obi->mat, v4);
- }
-
- /* todo: correct area for instances */
- if (vlr->v4)
- *area = area_quad_v3(v1, v2, v3, v4);
- else
- *area = area_tri_v3(v1, v2, v3);
- }
-}
-
-static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node)
-{
- OccNode *child;
- float occ, area, totarea, rad[3];
- int a, b, indirect = tree->doindirect;
-
- occ = 0.0f;
- totarea = 0.0f;
- if (indirect) zero_v3(rad);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- a = node->child[b].face;
- occ_face(&tree->face[a], NULL, NULL, &area);
- occ += area * tree->occlusion[a];
- if (indirect) madd_v3_v3fl(rad, tree->rad[a], area);
- totarea += area;
- }
- else if (node->child[b].node) {
- child = node->child[b].node;
- occ_sum_occlusion(tree, child);
-
- occ += child->area * child->occlusion;
- if (indirect) madd_v3_v3fl(rad, child->rad, child->area);
- totarea += child->area;
- }
- }
-
- if (totarea != 0.0f) {
- occ /= totarea;
- if (indirect) mul_v3_fl(rad, 1.0f / totarea);
- }
-
- node->occlusion = occ;
- if (indirect) copy_v3_v3(node->rad, rad);
-}
-
-static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max)
-{
- float len, maxlen = -1.0f;
- int a, axis = 0;
-
- INIT_MINMAX(min, max);
-
- for (a = begin; a < end; a++) {
- minmax_v3v3_v3(min, max, tree->co[a]);
- }
-
- for (a = 0; a < 3; a++) {
- len = max[a] - min[a];
-
- if (len > maxlen) {
- maxlen = len;
- axis = a;
- }
- }
-
- return axis;
-}
-
-static void occ_node_from_face(OccFace *face, OccNode *node)
-{
- float n[3];
-
- occ_face(face, node->co, n, &node->area);
- node->dco = 0.0f;
- sh_from_disc(n, node->area, node->sh);
-}
-
-static void occ_build_dco(OcclusionTree *tree, OccNode *node, const float co[3], float *dco)
-{
- int b;
- for (b = 0; b < TOTCHILD; b++) {
- float dist, d[3], nco[3];
-
- if (node->childflag & (1 << b)) {
- occ_face(tree->face + node->child[b].face, nco, NULL, NULL);
- }
- else if (node->child[b].node) {
- OccNode *child = node->child[b].node;
- occ_build_dco(tree, child, co, dco);
- copy_v3_v3(nco, child->co);
- }
- else {
- continue;
- }
-
- sub_v3_v3v3(d, nco, co);
- dist = dot_v3v3(d, d);
- if (dist > *dco)
- *dco = dist;
- }
-}
-
-static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split)
-{
- float min[3], max[3], mid;
- int axis, a, enda;
-
- /* split in middle of boundbox. this seems faster than median split
- * on complex scenes, possibly since it avoids two distant faces to
- * be in the same node better? */
- axis = occ_find_bbox_axis(tree, begin, end, min, max);
- mid = 0.5f * (min[axis] + max[axis]);
-
- a = begin;
- enda = end;
- while (a < enda) {
- if (tree->co[a][axis] > mid) {
- enda--;
- SWAP(OccFace, tree->face[a], tree->face[enda]);
- swap_v3_v3(tree->co[a], tree->co[enda]);
- }
- else
- a++;
- }
-
- *split = enda;
-}
-
-static void occ_build_8_split(OcclusionTree *tree, int begin, int end, int *offset, int *count)
-{
- /* split faces into eight groups */
- int b, splitx, splity[2], splitz[4];
-
- occ_build_split(tree, begin, end, &splitx);
-
- /* force split if none found, to deal with degenerate geometry */
- if (splitx == begin || splitx == end)
- splitx = (begin + end) / 2;
-
- occ_build_split(tree, begin, splitx, &splity[0]);
- occ_build_split(tree, splitx, end, &splity[1]);
-
- occ_build_split(tree, begin, splity[0], &splitz[0]);
- occ_build_split(tree, splity[0], splitx, &splitz[1]);
- occ_build_split(tree, splitx, splity[1], &splitz[2]);
- occ_build_split(tree, splity[1], end, &splitz[3]);
-
- offset[0] = begin;
- offset[1] = splitz[0];
- offset[2] = splity[0];
- offset[3] = splitz[1];
- offset[4] = splitx;
- offset[5] = splitz[2];
- offset[6] = splity[1];
- offset[7] = splitz[3];
-
- for (b = 0; b < 7; b++)
- count[b] = offset[b + 1] - offset[b];
- count[7] = end - offset[7];
-}
-
-static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth);
-
-static void *exec_occ_build(void *data)
-{
- OcclusionBuildThread *othread = (OcclusionBuildThread *)data;
-
- occ_build_recursive(othread->tree, othread->node, othread->begin, othread->end, othread->depth);
-
- return NULL;
-}
-
-static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth)
-{
- ListBase threads;
- OcclusionBuildThread othreads[BLENDER_MAX_THREADS];
- OccNode *child, tmpnode;
- /* OccFace *face; */
- int a, b, totthread = 0, offset[TOTCHILD], count[TOTCHILD];
-
- /* add a new node */
- node->occlusion = 1.0f;
-
- /* leaf node with only children */
- if (end - begin <= TOTCHILD) {
- for (a = begin, b = 0; a < end; a++, b++) {
- /* face= &tree->face[a]; */
- node->child[b].face = a;
- node->childflag |= (1 << b);
- }
- }
- else {
- /* order faces */
- occ_build_8_split(tree, begin, end, offset, count);
-
- if (depth == 1 && tree->dothreadedbuild)
- BLI_threadpool_init(&threads, exec_occ_build, tree->totbuildthread);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (count[b] == 0) {
- node->child[b].node = NULL;
- }
- else if (count[b] == 1) {
- /* face= &tree->face[offset[b]]; */
- node->child[b].face = offset[b];
- node->childflag |= (1 << b);
- }
- else {
- if (tree->dothreadedbuild)
- BLI_thread_lock(LOCK_CUSTOM1);
-
- child = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
- node->child[b].node = child;
-
- /* keep track of maximum depth for stack */
- if (depth >= tree->maxdepth)
- tree->maxdepth = depth + 1;
-
- if (tree->dothreadedbuild)
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- if (depth == 1 && tree->dothreadedbuild) {
- othreads[totthread].tree = tree;
- othreads[totthread].node = child;
- othreads[totthread].begin = offset[b];
- othreads[totthread].end = offset[b] + count[b];
- othreads[totthread].depth = depth + 1;
- BLI_threadpool_insert(&threads, &othreads[totthread]);
- totthread++;
- }
- else
- occ_build_recursive(tree, child, offset[b], offset[b] + count[b], depth + 1);
- }
- }
-
- if (depth == 1 && tree->dothreadedbuild)
- BLI_threadpool_end(&threads);
- }
-
- /* combine area, position and sh */
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- child = &tmpnode;
- occ_node_from_face(tree->face + node->child[b].face, &tmpnode);
- }
- else {
- child = node->child[b].node;
- }
-
- if (child) {
- node->area += child->area;
- sh_add(node->sh, node->sh, child->sh);
- madd_v3_v3fl(node->co, child->co, child->area);
- }
- }
-
- if (node->area != 0.0f)
- mul_v3_fl(node->co, 1.0f / node->area);
-
- /* compute maximum distance from center */
- node->dco = 0.0f;
- if (node->area > 0.0f)
- occ_build_dco(tree, node, node->co, &node->dco);
-}
-
-static void occ_build_sh_normalize(OccNode *node)
-{
- /* normalize spherical harmonics to not include area, so
- * we can clamp the dot product and then multiply by area */
- int b;
-
- if (node->area != 0.0f)
- sh_mul(node->sh, 1.0f / node->area);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- /* pass */
- }
- else if (node->child[b].node) {
- occ_build_sh_normalize(node->child[b].node);
- }
- }
-}
-
-static OcclusionTree *occ_tree_build(Render *re)
-{
- const int num_threads = re->r.threads;
- OcclusionTree *tree;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- Material *ma;
- VlakRen *vlr = NULL;
- int a, b, c, totface;
-
- /* count */
- totface = 0;
- for (obi = re->instancetable.first; obi; obi = obi->next) {
- obr = obi->obr;
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- ma = vlr->mat;
-
- if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE))
- totface++;
- }
- }
-
- if (totface == 0)
- return NULL;
-
- tree = MEM_callocN(sizeof(OcclusionTree), "OcclusionTree");
- tree->totface = totface;
-
- /* parameters */
- tree->error = get_render_aosss_error(&re->r, re->wrld.ao_approx_error);
- tree->distfac = (re->wrld.aomode & WO_AODIST) ? re->wrld.aodistfac : 0.0f;
- tree->doindirect = (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0);
-
- /* allocation */
- tree->arena = BLI_memarena_new(0x8000 * sizeof(OccNode), "occ tree arena");
- BLI_memarena_use_calloc(tree->arena);
-
- if (re->wrld.aomode & WO_AOCACHE)
- tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache");
-
- tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace");
- tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo");
- tree->occlusion = MEM_callocN(sizeof(float) * totface, "OcclusionOcclusion");
-
- if (tree->doindirect)
- tree->rad = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionRad");
-
- /* make array of face pointers */
- for (b = 0, c = 0, obi = re->instancetable.first; obi; obi = obi->next, c++) {
- obr = obi->obr;
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- ma = vlr->mat;
-
- if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) {
- tree->face[b].obi = c;
- tree->face[b].facenr = a;
- tree->occlusion[b] = 1.0f;
- occ_face(&tree->face[b], tree->co[b], NULL, NULL);
- b++;
- }
- }
- }
-
- /* threads */
- tree->totbuildthread = (re->r.threads > 1 && totface > 10000) ? 8 : 1;
- tree->dothreadedbuild = (tree->totbuildthread > 1);
-
- /* recurse */
- tree->root = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
- tree->maxdepth = 1;
- occ_build_recursive(tree, tree->root, 0, totface, 1);
-
- if (tree->doindirect) {
- if (!(re->test_break(re->tbh)))
- occ_build_shade(re, tree);
-
- if (!(re->test_break(re->tbh)))
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(tree->co);
- tree->co = NULL;
-
- if (!(re->test_break(re->tbh)))
- occ_build_sh_normalize(tree->root);
-
- for (a = 0; a < num_threads; a++)
- tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack");
-
- tree->num_threads = num_threads;
-
- return tree;
-}
-
-static void occ_free_tree(OcclusionTree *tree)
-{
- int a;
-
- if (tree) {
- if (tree->arena) BLI_memarena_free(tree->arena);
- for (a = 0; a < tree->num_threads; a++)
- if (tree->stack[a])
- MEM_freeN(tree->stack[a]);
- if (tree->occlusion) MEM_freeN(tree->occlusion);
- if (tree->cache) MEM_freeN(tree->cache);
- if (tree->face) MEM_freeN(tree->face);
- if (tree->rad) MEM_freeN(tree->rad);
- MEM_freeN(tree);
- }
-}
-
-/* ------------------------- Traversal --------------------------- */
-
-static float occ_solid_angle(OccNode *node, const float v[3], float d2, float invd2, const float receivenormal[3])
-{
- float dotreceive, dotemit;
- float ev[3];
-
- ev[0] = -v[0] * invd2;
- ev[1] = -v[1] * invd2;
- ev[2] = -v[2] * invd2;
- dotemit = sh_eval(node->sh, ev);
- dotreceive = dot_v3v3(receivenormal, v) * invd2;
-
- CLAMP(dotemit, 0.0f, 1.0f);
- CLAMP(dotreceive, 0.0f, 1.0f);
-
- return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI;
-}
-
-static float occ_form_factor(OccFace *face, float *p, float *n)
-{
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- float v1[3], v2[3], v3[3], v4[3], q0[3], q1[3], q2[3], q3[3], contrib = 0.0f;
-
- obi = &R.objectinstance[face->obi];
- vlr = RE_findOrAddVlak(obi->obr, face->facenr);
-
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- }
-
- if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += form_factor_quad(p, n, q0, q1, q2, q3);
-
- if (vlr->v4) {
- copy_v3_v3(v4, vlr->v4->co);
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, v4);
-
- if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += form_factor_quad(p, n, q0, q1, q2, q3);
- }
-
- return contrib;
-}
-
-static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude,
- const float pp[3], const float pn[3], float *occ, float rad[3], float bentn[3])
-{
- OccNode *node, **stack;
- OccFace *face;
- float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2;
- float distfac, fac, error, d2, weight, emitarea;
- int b, f, totstack;
-
- /* init variables */
- copy_v3_v3(p, pp);
- copy_v3_v3(n, pn);
- madd_v3_v3fl(p, n, 1e-4f);
-
- if (bentn)
- copy_v3_v3(bentn, n);
-
- error = tree->error;
- distfac = tree->distfac;
-
- resultocc = 0.0f;
- zero_v3(resultrad);
-
- /* init stack */
- stack = tree->stack[thread];
- stack[0] = tree->root;
- totstack = 1;
-
- while (totstack) {
- /* pop point off the stack */
- node = stack[--totstack];
-
- sub_v3_v3v3(v, node->co, p);
- d2 = dot_v3v3(v, v) + 1e-16f;
- emitarea = MAX2(node->area, node->dco);
-
- if (d2 * error > emitarea) {
- if (distfac != 0.0f) {
- fac = 1.0f / (1.0f + distfac * d2);
- if (fac < 0.01f)
- continue;
- }
- else
- fac = 1.0f;
-
- /* accumulate occlusion from spherical harmonics */
- invd2 = 1.0f / sqrtf(d2);
- weight = occ_solid_angle(node, v, d2, invd2, n);
-
- if (rad)
- madd_v3_v3fl(resultrad, node->rad, weight * fac);
-
- weight *= node->occlusion;
-
- if (bentn) {
- bentn[0] -= weight * invd2 * v[0];
- bentn[1] -= weight * invd2 * v[1];
- bentn[2] -= weight * invd2 * v[2];
- }
-
- resultocc += weight * fac;
- }
- else {
- /* traverse into children */
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- f = node->child[b].face;
- face = &tree->face[f];
-
- /* accumulate occlusion with face form factor */
- if (!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) {
- if (bentn || distfac != 0.0f) {
- occ_face(face, co, NULL, NULL);
- sub_v3_v3v3(v, co, p);
- d2 = dot_v3v3(v, v) + 1e-16f;
-
- fac = (distfac == 0.0f) ? 1.0f : 1.0f / (1.0f + distfac * d2);
- if (fac < 0.01f)
- continue;
- }
- else
- fac = 1.0f;
-
- weight = occ_form_factor(face, p, n);
-
- if (rad)
- madd_v3_v3fl(resultrad, tree->rad[f], weight * fac);
-
- weight *= tree->occlusion[f];
-
- if (bentn) {
- invd2 = 1.0f / sqrtf(d2);
- bentn[0] -= weight * invd2 * v[0];
- bentn[1] -= weight * invd2 * v[1];
- bentn[2] -= weight * invd2 * v[2];
- }
-
- resultocc += weight * fac;
- }
- }
- else if (node->child[b].node) {
- /* push child on the stack */
- stack[totstack++] = node->child[b].node;
- }
- }
- }
- }
-
- if (occ) *occ = resultocc;
- if (rad) copy_v3_v3(rad, resultrad);
-#if 0
- if (rad && exclude) {
- int a;
- for (a = 0; a < tree->totface; a++)
- if ((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr))
- copy_v3_v3(rad, tree->rad[a]);
- }
-#endif
- if (bentn) normalize_v3(bentn);
-}
-
-static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce)
-{
- float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ;
- int bounce, i;
-
- rad = MEM_callocN(sizeof(float) * 3 * tree->totface, "OcclusionBounceRad");
- sum = MEM_dupallocN(tree->rad);
-
- for (bounce = 1; bounce < totbounce; bounce++) {
- for (i = 0; i < tree->totface; i++) {
- occ_face(&tree->face[i], co, n, NULL);
- madd_v3_v3fl(co, n, 1e-8f);
-
- occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL);
- rad[i][0] = MAX2(rad[i][0], 0.0f);
- rad[i][1] = MAX2(rad[i][1], 0.0f);
- rad[i][2] = MAX2(rad[i][2], 0.0f);
- add_v3_v3(sum[i], rad[i]);
-
- if (re->test_break(re->tbh))
- break;
- }
-
- if (re->test_break(re->tbh))
- break;
-
- tmp = tree->rad;
- tree->rad = rad;
- rad = tmp;
-
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(rad);
- MEM_freeN(tree->rad);
- tree->rad = sum;
-
- if (!re->test_break(re->tbh))
- occ_sum_occlusion(tree, tree->root);
-}
-
-static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass)
-{
- float *occ, co[3], n[3];
- int pass, i;
-
- occ = MEM_callocN(sizeof(float) * tree->totface, "OcclusionPassOcc");
-
- for (pass = 0; pass < totpass; pass++) {
- for (i = 0; i < tree->totface; i++) {
- occ_face(&tree->face[i], co, n, NULL);
- negate_v3(n);
- madd_v3_v3fl(co, n, 1e-8f);
-
- occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL);
- if (re->test_break(re->tbh))
- break;
- }
-
- if (re->test_break(re->tbh))
- break;
-
- for (i = 0; i < tree->totface; i++) {
- tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f);
- if (tree->occlusion[i] < 0.0f)
- tree->occlusion[i] = 0.0f;
- }
-
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(occ);
-}
-
-static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude,
- const float co[3], const float n[3], int thread, int onlyshadow,
- float *ao, float *env, float *indirect)
-{
- float nn[3], bn[3], fac, occ, occlusion, correction, rad[3];
- int envcolor;
-
- envcolor = re->wrld.aocolor;
- if (onlyshadow)
- envcolor = WO_AOPLAIN;
-
- negate_v3_v3(nn, n);
-
- occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect) ? rad : NULL, (env && envcolor) ? bn : NULL);
-
- correction = re->wrld.ao_approx_correction;
-
- occlusion = (1.0f - correction) * (1.0f - occ);
- CLAMP(occlusion, 0.0f, 1.0f);
- if (correction != 0.0f)
- occlusion += correction * expf(-occ);
-
- if (env) {
- /* sky shading using bent normal */
- if (ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) {
- fac = 0.5f * (1.0f + dot_v3v3(bn, re->grvec));
- env[0] = (1.0f - fac) * re->wrld.horr + fac * re->wrld.zenr;
- env[1] = (1.0f - fac) * re->wrld.horg + fac * re->wrld.zeng;
- env[2] = (1.0f - fac) * re->wrld.horb + fac * re->wrld.zenb;
-
- mul_v3_fl(env, occlusion);
- }
- else {
- env[0] = occlusion;
- env[1] = occlusion;
- env[2] = occlusion;
- }
-#if 0
- else { /* WO_AOSKYTEX */
- float dxyview[3];
- bn[0] = -bn[0];
- bn[1] = -bn[1];
- bn[2] = -bn[2];
- dxyview[0] = 1.0f;
- dxyview[1] = 1.0f;
- dxyview[2] = 0.0f;
- shadeSkyView(ao, co, bn, dxyview);
- }
-#endif
- }
-
- if (ao) {
- ao[0] = occlusion;
- ao[1] = occlusion;
- ao[2] = occlusion;
- }
-
- if (tree->doindirect) copy_v3_v3(indirect, rad);
- else zero_v3(indirect);
-}
-
-/* ---------------------------- Caching ------------------------------- */
-
-static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y)
-{
- x -= cache->x;
- y -= cache->y;
-
- x /= cache->step;
- y /= cache->step;
- x *= cache->step;
- y *= cache->step;
-
- if (x < 0 || x >= cache->w || y < 0 || y >= cache->h)
- return NULL;
- else
- return &cache->sample[y * cache->w + x];
-}
-
-static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect)
-{
- OcclusionCache *cache;
- OcclusionCacheSample *samples[4], *sample;
- float wn[4], wz[4], wb[4], tx, ty, w, totw, mino, maxo;
- float d[3], dist2;
- int i, x1, y1, x2, y2;
-
- if (!tree->cache)
- return 0;
-
- /* first try to find a sample in the same pixel */
- cache = &tree->cache[thread];
-
- if (cache->sample && cache->step) {
- sample = &cache->sample[(y - cache->y) * cache->w + (x - cache->x)];
- if (sample->filled) {
- sub_v3_v3v3(d, sample->co, co);
- dist2 = dot_v3v3(d, d);
- if (dist2 < 0.5f * sample->dist2 && dot_v3v3(sample->n, n) > 0.98f) {
- copy_v3_v3(ao, sample->ao);
- copy_v3_v3(env, sample->env);
- copy_v3_v3(indirect, sample->indirect);
- return 1;
- }
- }
- }
- else
- return 0;
-
- /* try to interpolate between 4 neighboring pixels */
- samples[0] = find_occ_sample(cache, x, y);
- samples[1] = find_occ_sample(cache, x + cache->step, y);
- samples[2] = find_occ_sample(cache, x, y + cache->step);
- samples[3] = find_occ_sample(cache, x + cache->step, y + cache->step);
-
- for (i = 0; i < 4; i++)
- if (!samples[i] || !samples[i]->filled)
- return 0;
-
- /* require intensities not being too different */
- mino = min_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
- maxo = max_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
-
- if (maxo - mino > 0.05f)
- return 0;
-
- /* compute weighted interpolation between samples */
- zero_v3(ao);
- zero_v3(env);
- zero_v3(indirect);
- totw = 0.0f;
-
- x1 = samples[0]->x;
- y1 = samples[0]->y;
- x2 = samples[3]->x;
- y2 = samples[3]->y;
-
- tx = (float)(x2 - x) / (float)(x2 - x1);
- ty = (float)(y2 - y) / (float)(y2 - y1);
-
- wb[3] = (1.0f - tx) * (1.0f - ty);
- wb[2] = (tx) * (1.0f - ty);
- wb[1] = (1.0f - tx) * (ty);
- wb[0] = tx * ty;
-
- for (i = 0; i < 4; i++) {
- sub_v3_v3v3(d, samples[i]->co, co);
- //dist2 = dot_v3v3(d, d);
-
- wz[i] = 1.0f; //(samples[i]->dist2/(1e-4f + dist2));
- wn[i] = pow(dot_v3v3(samples[i]->n, n), 32.0f);
-
- w = wb[i] * wn[i] * wz[i];
-
- totw += w;
- madd_v3_v3fl(ao, samples[i]->ao, w);
- madd_v3_v3fl(env, samples[i]->env, w);
- madd_v3_v3fl(indirect, samples[i]->indirect, w);
- }
-
- if (totw >= 0.9f) {
- totw = 1.0f / totw;
- mul_v3_fl(ao, totw);
- mul_v3_fl(env, totw);
- mul_v3_fl(indirect, totw);
- return 1;
- }
-
- return 0;
-}
-
-static void sample_occ_surface(ShadeInput *shi)
-{
- StrandRen *strand = shi->strand;
- StrandSurface *mesh = strand->buffer->surface;
- const int *face, *index = RE_strandren_get_face(shi->obr, strand, 0);
- float w[4], *co1, *co2, *co3, *co4;
-
- if (mesh && mesh->face && mesh->co && mesh->ao && index) {
- face = mesh->face[*index];
-
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
- interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
- }
- else {
- interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
- }
-
- zero_v3(shi->ao);
- zero_v3(shi->env);
- zero_v3(shi->indirect);
-
- madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]);
- madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]);
- madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]);
- madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]);
- madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]);
- madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]);
- if (face[3]) {
- madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]);
- madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]);
- }
- }
- else {
- shi->ao[0] = 1.0f;
- shi->ao[1] = 1.0f;
- shi->ao[2] = 1.0f;
- zero_v3(shi->env);
- zero_v3(shi->indirect);
- }
-}
-
-/* ------------------------- External Functions --------------------------- */
-
-static void *exec_strandsurface_sample(void *data)
-{
- OcclusionThread *othread = (OcclusionThread *)data;
- Render *re = othread->re;
- StrandSurface *mesh = othread->mesh;
- float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4;
- int a, *face;
-
- for (a = othread->begin; a < othread->end; a++) {
- face = mesh->face[a];
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
-
- mid_v3_v3v3(co, co1, co3);
- normal_quad_v3(n, co1, co2, co3, co4);
- }
- else {
- mid_v3_v3v3v3(co, co1, co2, co3);
- normal_tri_v3(n, co1, co2, co3);
- }
- negate_v3(n);
-
- sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect);
- copy_v3_v3(othread->faceao[a], ao);
- copy_v3_v3(othread->faceenv[a], env);
- copy_v3_v3(othread->faceindirect[a], indirect);
- }
-
- return NULL;
-}
-
-void make_occ_tree(Render *re)
-{
- OcclusionThread othreads[BLENDER_MAX_THREADS];
- OcclusionTree *tree;
- StrandSurface *mesh;
- ListBase threads;
- float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3];
- int a, totface, totthread, *face, *count;
-
- /* ugly, needed for occ_face */
- R = *re;
-
- re->i.infostr = IFACE_("Occlusion preprocessing");
- re->stats_draw(re->sdh, &re->i);
-
- re->occlusiontree = tree = occ_tree_build(re);
-
- if (tree && !re->test_break(re->tbh)) {
- if (re->wrld.ao_approx_passes > 0)
- occ_compute_passes(re, tree, re->wrld.ao_approx_passes);
- if (tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT))
- occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces);
-
- for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
- if (!mesh->face || !mesh->co || !mesh->ao)
- continue;
-
- count = MEM_callocN(sizeof(int) * mesh->totvert, "OcclusionCount");
- faceao = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceAO");
- faceenv = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceEnv");
- faceindirect = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceIndirect");
-
- totthread = (mesh->totface > 10000) ? re->r.threads : 1;
- totface = mesh->totface / totthread;
- for (a = 0; a < totthread; a++) {
- othreads[a].re = re;
- othreads[a].faceao = faceao;
- othreads[a].faceenv = faceenv;
- othreads[a].faceindirect = faceindirect;
- othreads[a].thread = a;
- othreads[a].mesh = mesh;
- othreads[a].begin = a * totface;
- othreads[a].end = (a == totthread - 1) ? mesh->totface : (a + 1) * totface;
- }
-
- if (totthread == 1) {
- exec_strandsurface_sample(&othreads[0]);
- }
- else {
- BLI_threadpool_init(&threads, exec_strandsurface_sample, totthread);
-
- for (a = 0; a < totthread; a++)
- BLI_threadpool_insert(&threads, &othreads[a]);
-
- BLI_threadpool_end(&threads);
- }
-
- for (a = 0; a < mesh->totface; a++) {
- face = mesh->face[a];
-
- copy_v3_v3(ao, faceao[a]);
- copy_v3_v3(env, faceenv[a]);
- copy_v3_v3(indirect, faceindirect[a]);
-
- add_v3_v3(mesh->ao[face[0]], ao);
- add_v3_v3(mesh->env[face[0]], env);
- add_v3_v3(mesh->indirect[face[0]], indirect);
- count[face[0]]++;
- add_v3_v3(mesh->ao[face[1]], ao);
- add_v3_v3(mesh->env[face[1]], env);
- add_v3_v3(mesh->indirect[face[1]], indirect);
- count[face[1]]++;
- add_v3_v3(mesh->ao[face[2]], ao);
- add_v3_v3(mesh->env[face[2]], env);
- add_v3_v3(mesh->indirect[face[2]], indirect);
- count[face[2]]++;
-
- if (face[3]) {
- add_v3_v3(mesh->ao[face[3]], ao);
- add_v3_v3(mesh->env[face[3]], env);
- add_v3_v3(mesh->indirect[face[3]], indirect);
- count[face[3]]++;
- }
- }
-
- for (a = 0; a < mesh->totvert; a++) {
- if (count[a]) {
- mul_v3_fl(mesh->ao[a], 1.0f / count[a]);
- mul_v3_fl(mesh->env[a], 1.0f / count[a]);
- mul_v3_fl(mesh->indirect[a], 1.0f / count[a]);
- }
- }
-
- MEM_freeN(count);
- MEM_freeN(faceao);
- MEM_freeN(faceenv);
- MEM_freeN(faceindirect);
- }
- }
-}
-
-void free_occ(Render *re)
-{
- if (re->occlusiontree) {
- occ_free_tree(re->occlusiontree);
- re->occlusiontree = NULL;
- }
-}
-
-void sample_occ(Render *re, ShadeInput *shi)
-{
- OcclusionTree *tree = re->occlusiontree;
- OcclusionCache *cache;
- OcclusionCacheSample *sample;
- OccFace exclude;
- int onlyshadow;
-
- if (tree) {
- if (shi->strand) {
- sample_occ_surface(shi);
- }
- /* try to get result from the cache if possible */
- else if (shi->depth != 0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) {
- /* no luck, let's sample the occlusion */
- exclude.obi = shi->obi - re->objectinstance;
- exclude.facenr = shi->vlr->index;
- onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
- sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
-
- /* fill result into sample, each time */
- if (tree->cache) {
- cache = &tree->cache[shi->thread];
-
- if (cache->sample && cache->step) {
- sample = &cache->sample[(shi->ys - cache->y) * cache->w + (shi->xs - cache->x)];
- copy_v3_v3(sample->co, shi->co);
- copy_v3_v3(sample->n, shi->vno);
- copy_v3_v3(sample->ao, shi->ao);
- copy_v3_v3(sample->env, shi->env);
- copy_v3_v3(sample->indirect, shi->indirect);
- sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
- sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
- sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
- sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
- sample->filled = 1;
- }
- }
- }
- }
- else {
- shi->ao[0] = 1.0f;
- shi->ao[1] = 1.0f;
- shi->ao[2] = 1.0f;
-
- shi->env[0] = 0.0f;
- shi->env[1] = 0.0f;
- shi->env[2] = 0.0f;
-
- shi->indirect[0] = 0.0f;
- shi->indirect[1] = 0.0f;
- shi->indirect[2] = 0.0f;
- }
-}
-
-void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp)
-{
- OcclusionTree *tree = re->occlusiontree;
- PixStr ps;
- OcclusionCache *cache;
- OcclusionCacheSample *sample;
- OccFace exclude;
- ShadeInput *shi;
- intptr_t *rd = NULL;
- int *ro = NULL, *rp = NULL, *rz = NULL, onlyshadow;
- int x, y, step = CACHE_STEP;
-
- if (!tree->cache)
- return;
-
- cache = &tree->cache[pa->thread];
- cache->w = pa->rectx;
- cache->h = pa->recty;
- cache->x = pa->disprect.xmin;
- cache->y = pa->disprect.ymin;
- cache->step = step;
- cache->sample = MEM_callocN(sizeof(OcclusionCacheSample) * cache->w * cache->h, "OcclusionCacheSample");
- sample = cache->sample;
-
- if (re->osa) {
- rd = pa->rectdaps;
- }
- else {
- /* fake pixel struct for non-osa */
- ps.next = NULL;
- ps.mask = 0xFFFF;
-
- ro = pa->recto;
- rp = pa->rectp;
- rz = pa->rectz;
- }
-
- /* compute a sample at every step pixels */
- for (y = pa->disprect.ymin; y < pa->disprect.ymax; y++) {
- for (x = pa->disprect.xmin; x < pa->disprect.xmax; x++, sample++, rd++, ro++, rp++, rz++) {
- if (!(((x - pa->disprect.xmin + step) % step) == 0 || x == pa->disprect.xmax - 1))
- continue;
- if (!(((y - pa->disprect.ymin + step) % step) == 0 || y == pa->disprect.ymax - 1))
- continue;
-
- if (re->osa) {
- if (!*rd) continue;
-
- shade_samples_fill_with_ps(ssamp, (PixStr *)(*rd), x, y);
- }
- else {
- if (!*rp) continue;
-
- ps.obi = *ro;
- ps.facenr = *rp;
- ps.z = *rz;
- shade_samples_fill_with_ps(ssamp, &ps, x, y);
- }
-
- shi = ssamp->shi;
- if (shi->vlr) {
- onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
- exclude.obi = shi->obi - re->objectinstance;
- exclude.facenr = shi->vlr->index;
- sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
-
- copy_v3_v3(sample->co, shi->co);
- copy_v3_v3(sample->n, shi->vno);
- copy_v3_v3(sample->ao, shi->ao);
- copy_v3_v3(sample->env, shi->env);
- copy_v3_v3(sample->indirect, shi->indirect);
- sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
- sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
- sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
- sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
- sample->x = shi->xs;
- sample->y = shi->ys;
- sample->filled = 1;
- }
-
- if (re->test_break(re->tbh))
- break;
- }
- }
-}
-
-void free_occ_samples(Render *re, RenderPart *pa)
-{
- OcclusionTree *tree = re->occlusiontree;
- OcclusionCache *cache;
-
- if (tree->cache) {
- cache = &tree->cache[pa->thread];
-
- if (cache->sample)
- MEM_freeN(cache->sample);
-
- cache->w = 0;
- cache->h = 0;
- cache->step = 0;
- }
-}
-
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index ba50467f9ea..dd2042d3220 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -92,6 +92,7 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#include "RE_render_ext.h"
#ifdef WITH_FREESTYLE
# include "FRS_freestyle.h"
@@ -100,14 +101,10 @@
#include "DEG_depsgraph.h"
/* internal */
+#include "initrender.h"
+#include "renderpipeline.h"
#include "render_result.h"
#include "render_types.h"
-#include "renderpipeline.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "initrender.h"
-#include "pixelblending.h"
-#include "zbuf.h"
/* render flow
*
@@ -142,19 +139,10 @@ static struct {
ListBase renderlist;
} RenderGlobal = {{NULL, NULL}};
-/* hardcopy of current render, used while rendering for speed */
-Render R;
-
/* ********* alloc and free ******** */
static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const int totvideos, const char *name_override);
-static volatile int g_break = 0;
-static int thread_break(void *UNUSED(arg))
-{
- return g_break;
-}
-
/* default callbacks, set in each new render */
static void result_nothing(void *UNUSED(arg), RenderResult *UNUSED(rr)) {}
static void result_rcti_nothing(void *UNUSED(arg), RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) {}
@@ -289,18 +277,6 @@ RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
return rr->layers.first;
}
-static int UNUSED_FUNCTION(render_scene_needs_vector)(Render *re)
-{
- ViewLayer *view_layer;
- for (view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next)
- if (view_layer->flag & VIEW_LAYER_RENDER) {
- if (view_layer->passflag & SCE_PASS_VECTOR) {
- return 1;
- }
- }
- return 0;
-}
-
static bool render_scene_has_layers_to_render(Scene *scene)
{
ViewLayer *view_layer;
@@ -525,9 +501,6 @@ Render *RE_NewRender(const char *name)
RE_InitRenderCB(re);
- /* init some variables */
- re->ycor = 1.0f;
-
return re;
}
@@ -598,9 +571,6 @@ void RE_FreeRender(Render *re)
re->main = NULL;
re->scene = NULL;
- RE_Database_Free(re); /* view render can still have full database */
- free_sample_tables(re);
-
render_result_free(re->result);
render_result_free(re->pushedresult);
@@ -667,15 +637,10 @@ void RE_FreePersistentData(void)
/* clear full sample and tile flags if needed */
static int check_mode_full_sample(RenderData *rd)
{
- const char *engine_id = rd->engine;
int scemode = rd->scemode;
- if (!STREQ(engine_id, RE_engine_id_BLENDER_RENDER)) {
- scemode &= ~R_FULL_SAMPLE;
- }
-
- if ((rd->mode & R_OSA) == 0)
- scemode &= ~R_FULL_SAMPLE;
+ /* not supported by any current renderer */
+ scemode &= ~R_FULL_SAMPLE;
#ifdef WITH_OPENEXR
if (scemode & R_FULL_SAMPLE)
@@ -695,7 +660,7 @@ static void re_init_resolution(Render *re, Render *source,
re->winy = winy;
if (source && (source->r.mode & R_BORDER)) {
/* eeh, doesn't seem original bordered disprect is storing anywhere
- * after insertion on black happening in do_render_fields_blur_3d(),
+ * after insertion on black happening in do_render(),
* so for now simply re-calculate disprect using border from source
* renderer (sergey)
*/
@@ -724,9 +689,6 @@ static void re_init_resolution(Render *re, Render *source,
re->rectx = winx;
re->recty = winy;
}
-
- /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
- re->clipcrop = 1.0f + 2.0f / (float)(re->winx > re->winy ? re->winy : re->winx);
}
void render_copy_renderdata(RenderData *to, RenderData *from)
@@ -789,23 +751,6 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.scemode = check_mode_full_sample(&re->r);
- /* fullsample wants uniform osa levels */
- if (source && (re->r.scemode & R_FULL_SAMPLE)) {
- /* but, if source has no full sample we disable it */
- if ((source->r.scemode & R_FULL_SAMPLE) == 0)
- re->r.scemode &= ~R_FULL_SAMPLE;
- else
- re->r.osa = re->osa = source->osa;
- }
- else {
- /* check state variables, osa? */
- if (re->r.mode & (R_OSA)) {
- re->osa = re->r.osa;
- if (re->osa > 16) re->osa = 16;
- }
- else re->osa = 0;
- }
-
if (view_layer) {
int index = BLI_findindex(render_layers, view_layer);
if (index != -1) {
@@ -814,9 +759,6 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
}
}
- /* always call, checks for gamma, gamma tables and jitter too */
- make_sample_tables(re);
-
/* if preview render, we try to keep old result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
@@ -867,9 +809,9 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
BLI_rw_mutex_unlock(&re->resultmutex);
- re->mblur_offs = re->field_offs = 0.f;
-
RE_init_threadcount(re);
+
+ RE_point_density_fix_linking();
}
/* This function is only called by view3d rendering, which doesn't support
@@ -962,7 +904,6 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
re->r.gauss = rd->gauss;
/* motion blur */
- re->r.mblur_samples = rd->mblur_samples;
re->r.blurfac = rd->blurfac;
/* freestyle */
@@ -1090,709 +1031,21 @@ void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
/* *************************************** */
-static int render_display_update_enabled(Render *re)
-{
- /* don't show preprocess for previewrender sss */
- if (re->sss_points)
- return !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW));
- else
- return 1;
-}
-
-/* the main thread call, renders an entire part */
-static void *do_part_thread(void *pa_v)
-{
- RenderPart *pa = pa_v;
-
- pa->status = PART_STATUS_IN_PROGRESS;
-
- /* need to return nicely all parts on esc */
- if (R.test_break(R.tbh) == 0) {
-
- if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
- pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname);
- else
- pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname);
-
- /* Copy EXR tile settings, so pipeline knows whether this is a result
- * for Save Buffers enabled rendering.
- *
- * TODO(sergey): This actually duplicates logic with external engine, so
- * worth looking into more generic solution.
- */
- pa->result->do_exr_tile = R.result->do_exr_tile;
-
- if (R.sss_points)
- zbufshade_sss_tile(pa);
- else if (R.osa)
- zbufshadeDA_tile(pa);
- else
- zbufshade_tile(pa);
-
- /* we do actually write pixels, but don't allocate/deallocate anything,
- * so it is safe with other threads reading at the same time */
- BLI_rw_mutex_lock(&R.resultmutex, THREAD_LOCK_READ);
-
- /* merge too on break! */
- if (R.result->do_exr_tile) {
- render_result_exr_file_merge(R.result, pa->result, R.viewname);
- }
- else if (render_display_update_enabled(&R)) {
- /* on break, don't merge in result for preview renders, looks nicer */
- if (R.test_break(R.tbh) && (R.r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- /* pass */
- }
- else {
- render_result_merge(R.result, pa->result);
- }
- }
-
- BLI_rw_mutex_unlock(&R.resultmutex);
- }
-
- pa->status = PART_STATUS_MERGED;
-
- return NULL;
-}
-
-/* calculus for how much 1 pixel rendered should rotate the 3d geometry */
-/* is not that simple, needs to be corrected for errors of larger viewplane sizes */
-/* called in initrender.c, RE_parts_init() and convertblender.c, for speedvectors */
-float panorama_pixel_rot(Render *re)
-{
- float psize, phi, xfac;
- float borderfac = (float)BLI_rcti_size_x(&re->disprect) / (float)re->winx;
- int xparts = (re->rectx + re->partx - 1) / re->partx;
-
- /* size of 1 pixel mapped to viewplane coords */
- psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx;
- /* angle of a pixel */
- phi = atan(psize / re->clipsta);
-
- /* correction factor for viewplane shifting, first calculate how much the viewplane angle is */
- xfac = borderfac * BLI_rctf_size_x(&re->viewplane) / (float)xparts;
- xfac = atan(0.5f * xfac / re->clipsta);
- /* and how much the same viewplane angle is wrapped */
- psize = 0.5f * phi * ((float)re->partx);
-
- /* the ratio applied to final per-pixel angle */
- phi *= xfac / psize;
-
- return phi;
-}
-
-/* for panorama, we render per Y slice, and update
- * camera parameters when we go the next slice */
-static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewplane)
-{
- RenderPart *pa, *best = NULL;
- bool found = false;
-
- *minx = re->winx;
-
- if (!(re->r.mode & R_PANORAMA)) {
- /* for regular render, just one 'slice' */
- found = (*slice == 0);
- (*slice)++;
- return found;
- }
-
- /* most left part of the non-rendering parts */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (pa->disprect.xmin < *minx) {
- found = true;
- best = pa;
- *minx = pa->disprect.xmin;
- }
- }
- }
-
- if (best) {
- float phi = panorama_pixel_rot(re);
-
- R.panodxp = (re->winx - (best->disprect.xmin + best->disprect.xmax) ) / 2;
- R.panodxv = (BLI_rctf_size_x(viewplane) * R.panodxp) / (float)(re->winx);
-
- /* shift viewplane */
- R.viewplane.xmin = viewplane->xmin + R.panodxv;
- R.viewplane.xmax = viewplane->xmax + R.panodxv;
- RE_SetWindow(re, &R.viewplane, R.clipsta, R.clipend);
- copy_m4_m4(R.winmat, re->winmat);
-
- /* rotate database according to part coordinates */
- project_renderdata(re, projectverto, 1, -R.panodxp * phi, 1);
- R.panosi = sinf(R.panodxp * phi);
- R.panoco = cosf(R.panodxp * phi);
- }
-
- (*slice)++;
-
- return found;
-}
-
-typedef struct SortRenderPart {
- RenderPart *pa;
- long long int dist;
-} SortRenderPart;
-
-static int sort_render_part(const void *pa1, const void *pa2) {
- const SortRenderPart *rpa1 = pa1;
- const SortRenderPart *rpa2 = pa2;
-
- if (rpa1->dist > rpa2->dist) return 1;
- else if (rpa1->dist < rpa2->dist) return -1;
-
- return 0;
-}
-
-static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue)
-{
- RenderPart *pa;
-
- /* long long int's needed because of overflow [#24414] */
- long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1;
- int totsort = 0;
-
- /* find center of rendered parts, image center counts for 1 too */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status >= PART_STATUS_RENDERED) {
- centx += BLI_rcti_cent_x(&pa->disprect);
- centy += BLI_rcti_cent_y(&pa->disprect);
- tot++;
- }
- else if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
- totsort++;
- }
- }
- }
- centx /= tot;
- centy /= tot;
-
- if (totsort > 0) {
- SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort");
- long int i = 0;
-
- /* prepare the list */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
- long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
- long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
- sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty);
- sortlist[i].pa = pa;
- i++;
- }
- }
- }
-
- /* Now sort it */
- qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part);
-
- /* Finally flush it to the workqueue */
- for (i = 0; i < totsort; i++) {
- pa = sortlist[i].pa;
- pa->nr = i + 1; /* for nicest part, and for stats */
- BLI_thread_queue_push(workqueue, pa);
- }
-
- MEM_freeN(sortlist);
-
- return totsort;
- }
-
- return 0;
-}
-
-static void print_part_stats(Render *re, RenderPart *pa)
-{
- char str[64];
-
- BLI_snprintf(str, sizeof(str), IFACE_("%s, Part %d-%d"), re->scene->id.name + 2, pa->nr, re->i.totpart);
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
-}
-
-typedef struct RenderThread {
- ThreadQueue *workqueue;
- ThreadQueue *donequeue;
-
- int number;
-
- void (*display_update)(void *handle, RenderResult *rr, volatile rcti *rect);
- void *duh;
-} RenderThread;
-
-static void *do_render_thread(void *thread_v)
-{
- RenderThread *thread = thread_v;
- RenderPart *pa;
-
- while ((pa = BLI_thread_queue_pop(thread->workqueue))) {
- pa->thread = thread->number;
- do_part_thread(pa);
-
- if (thread->display_update) {
- thread->display_update(thread->duh, pa->result, NULL);
- }
-
- BLI_thread_queue_push(thread->donequeue, pa);
-
- if (R.test_break(R.tbh))
- break;
- }
-
- return NULL;
-}
-
-static void UNUSED_FUNCTION(main_render_result_end)(Render *re)
-{
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- if (re->r.scemode & R_EXR_CACHE_FILE) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_cache_write(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-}
-
-static void main_render_result_new(Render *re)
-{
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
-
- /* first step; free the entire render result, make new, and/or prepare exr buffer saving */
- if (re->result == NULL || !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- render_result_free(re->result);
-
- if (re->sss_points && render_display_update_enabled(re))
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
- else if (re->r.scemode & R_FULL_SAMPLE)
- re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS);
- else
- re->result = render_result_new(re, &re->disprect, 0,
- (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
- }
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- if (re->result) {
- if (re->result->do_exr_tile) {
- render_result_exr_file_begin(re);
- }
- }
-}
-
-static void threaded_tile_processor(Render *re)
-{
- RenderThread thread[BLENDER_MAX_THREADS];
- ThreadQueue *workqueue, *donequeue;
- ListBase threads;
- RenderPart *pa;
- rctf viewplane = re->viewplane;
- double lastdraw, elapsed, redrawtime = 1.0f;
- int totpart = 0, minx = 0, slice = 0, a, wait;
-
- if (re->result == NULL)
- return;
-
- /* warning; no return here without closing exr file */
- RE_parts_init(re, true);
-
- /* assuming no new data gets added to dbase... */
- R = *re;
-
- /* set threadsafe break */
- R.test_break = thread_break;
-
- /* create and fill work queue */
- workqueue = BLI_thread_queue_init();
- donequeue = BLI_thread_queue_init();
-
- /* for panorama we loop over slices */
- while (find_next_pano_slice(re, &slice, &minx, &viewplane)) {
- /* gather parts into queue */
- totpart = sort_and_queue_parts(re, minx, workqueue);
-
- BLI_thread_queue_nowait(workqueue);
-
- /* start all threads */
- BLI_threadpool_init(&threads, do_render_thread, re->r.threads);
-
- for (a = 0; a < re->r.threads; a++) {
- thread[a].workqueue = workqueue;
- thread[a].donequeue = donequeue;
- thread[a].number = a;
-
- if (render_display_update_enabled(re)) {
- thread[a].display_update = re->display_update;
- thread[a].duh = re->duh;
- }
- else {
- thread[a].display_update = NULL;
- thread[a].duh = NULL;
- }
-
- BLI_threadpool_insert(&threads, &thread[a]);
- }
-
- /* wait for results to come back */
- lastdraw = PIL_check_seconds_timer();
-
- while (1) {
- elapsed = PIL_check_seconds_timer() - lastdraw;
- wait = (redrawtime - elapsed)*1000;
-
- /* handle finished part */
- if ((pa=BLI_thread_queue_pop_timeout(donequeue, wait))) {
- if (pa->result) {
- print_part_stats(re, pa);
-
- render_result_free_list(&pa->fullresult, pa->result);
- pa->result = NULL;
- re->i.partsdone++;
- re->progress(re->prh, re->i.partsdone / (float)re->i.totpart);
- }
-
- totpart--;
- }
-
- /* check for render cancel */
- if ((g_break=re->test_break(re->tbh)))
- break;
-
- /* or done with parts */
- if (totpart == 0)
- break;
-
- /* redraw in progress parts */
- elapsed = PIL_check_seconds_timer() - lastdraw;
- if (elapsed > redrawtime) {
- if (render_display_update_enabled(re))
- for (pa = re->parts.first; pa; pa = pa->next)
- if ((pa->status == PART_STATUS_IN_PROGRESS) && pa->nr && pa->result)
- re->display_update(re->duh, pa->result, &pa->result->renrect);
-
- lastdraw = PIL_check_seconds_timer();
- }
- }
-
- BLI_threadpool_end(&threads);
-
- if ((g_break=re->test_break(re->tbh)))
- break;
- }
-
- if (g_break) {
- /* review the done queue and handle all the render parts,
- * so no unfreed render result are lurking around
- */
- BLI_thread_queue_nowait(donequeue);
- while ((pa = BLI_thread_queue_pop(donequeue))) {
- if (pa->result) {
- render_result_free_list(&pa->fullresult, pa->result);
- pa->result = NULL;
- }
- }
- }
-
- BLI_thread_queue_free(donequeue);
- BLI_thread_queue_free(workqueue);
-
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_save_empty_result_tiles(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- /* unset threadsafety */
- g_break = 0;
- BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
- RE_parts_free(re);
- BLI_rw_mutex_unlock(&re->partsmutex);
- re->viewplane = viewplane; /* restore viewplane, modified by pano render */
-}
-
#ifdef WITH_FREESTYLE
static void init_freestyle(Render *re);
static void add_freestyle(Render *re, int render);
static void free_all_freestyle_renders(void);
#endif
-/* currently only called by preview renders and envmap */
-void RE_TileProcessor(Render *re)
-{
- main_render_result_new(re);
- threaded_tile_processor(re);
-
- re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
- re->stats_draw(re->sdh, &re->i);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS) {
- if (!re->test_break(re->tbh)) {
- init_freestyle(re);
- add_freestyle(re, 1);
- free_all_freestyle_renders();
-
- re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
- re->stats_draw(re->sdh, &re->i);
- }
- }
-#endif
-
-}
/* ************ This part uses API, for rendering Blender scenes ********** */
static void do_render_3d(Render *re)
{
re->current_scene_update(re->suh, re->scene);
-
- /* All the rendering pipeline goes through "external" render engines. */
RE_engine_render(re, 0);
}
-/* called by blur loop, accumulate RGBA key alpha */
-static void addblur_rect_key(RenderResult *rr, float *rectf, float *rectf1, float blurfac)
-{
- float mfac = 1.0f - blurfac;
- int a, b, stride = 4 * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a++) {
- if (blurfac == 1.0f) {
- memcpy(rectf, rectf1, len);
- }
- else {
- float *rf = rectf, *rf1 = rectf1;
-
- for (b = rr->rectx; b > 0; b--, rf += 4, rf1 += 4) {
- if (rf1[3] < 0.01f)
- rf[3] = mfac * rf[3];
- else if (rf[3] < 0.01f) {
- rf[0] = rf1[0];
- rf[1] = rf1[1];
- rf[2] = rf1[2];
- rf[3] = blurfac * rf1[3];
- }
- else {
- rf[0] = mfac * rf[0] + blurfac * rf1[0];
- rf[1] = mfac * rf[1] + blurfac * rf1[1];
- rf[2] = mfac * rf[2] + blurfac * rf1[2];
- rf[3] = mfac * rf[3] + blurfac * rf1[3];
- }
- }
- }
- rectf += stride;
- rectf1 += stride;
- }
-}
-
-/* called by blur loop, accumulate renderlayers */
-static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
-{
- float mfac = 1.0f - blurfac;
- int a, b, stride = channels * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a++) {
- if (blurfac == 1.0f) {
- memcpy(rectf, rectf1, len);
- }
- else {
- float *rf = rectf, *rf1 = rectf1;
-
- for (b = rr->rectx * channels; b > 0; b--, rf++, rf1++) {
- rf[0] = mfac * rf[0] + blurfac * rf1[0];
- }
- }
- rectf += stride;
- rectf1 += stride;
- }
-}
-
-
-/* called by blur loop, accumulate renderlayers */
-static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac, bool key_alpha)
-{
- RenderLayer *rl, *rl1;
- RenderPass *rpass, *rpass1;
-
- rl1 = brr->layers.first;
- for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) {
- /* passes are allocated in sync */
- rpass1 = rl1->passes.first;
- for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && key_alpha)
- addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac);
- else
- addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
- }
- }
-}
-
-/* main blur loop, can be called by fields too */
-static void do_render_blur_3d(Render *re)
-{
- RenderResult *rres;
- float blurfac;
- int blur = re->r.mblur_samples;
-
- /* create accumulation render result */
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- /* do the blur steps */
- while (blur--) {
- re->mblur_offs = re->r.blurfac * ((float)(re->r.mblur_samples - blur)) / (float)re->r.mblur_samples;
-
- re->i.curblur = re->r.mblur_samples - blur; /* stats */
-
- do_render_3d(re);
-
- blurfac = 1.0f / (float)(re->r.mblur_samples - blur);
-
- merge_renderresult_blur(rres, re->result, blurfac, false);
- if (re->test_break(re->tbh)) break;
- }
-
- /* swap results */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_free(re->result);
- re->result = rres;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->mblur_offs = 0.0f;
- re->i.curblur = 0; /* stats */
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- re->display_update(re->duh, re->result, NULL);
-}
-
-
-/* function assumes rectf1 and rectf2 to be half size of rectf */
-static void interleave_rect(RenderResult *rr, float *rectf, float *rectf1, float *rectf2, int channels)
-{
- int a, stride = channels * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a += 2) {
- memcpy(rectf, rectf1, len);
- rectf += stride;
- rectf1 += stride;
- memcpy(rectf, rectf2, len);
- rectf += stride;
- rectf2 += stride;
- }
-}
-
-/* merge render results of 2 fields */
-static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, RenderResult *rr2)
-{
- RenderLayer *rl, *rl1, *rl2;
- RenderPass *rpass, *rpass1, *rpass2;
-
- rl1 = rr1->layers.first;
- rl2 = rr2->layers.first;
- for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) {
-
- /* passes are allocated in sync */
- rpass1 = rl1->passes.first;
- rpass2 = rl2->passes.first;
- for (rpass = rl->passes.first;
- rpass && rpass1 && rpass2;
- rpass = rpass->next, rpass1 = rpass1->next, rpass2 = rpass2->next)
- {
- interleave_rect(rr, rpass->rect, rpass1->rect, rpass2->rect, rpass->channels);
- }
- }
-}
-
-
-/* interleaves 2 frames */
-static void do_render_fields_3d(Render *re)
-{
- Object *camera = RE_GetCamera(re);
- RenderResult *rr1, *rr2 = NULL;
-
- /* no render result was created, we can safely halve render y */
- re->winy /= 2;
- re->recty /= 2;
- re->disprect.ymin /= 2;
- re->disprect.ymax /= 2;
-
- re->i.curfield = 1; /* stats */
-
- /* first field, we have to call camera routine for correct aspect and subpixel offset */
- RE_SetCamera(re, camera);
- if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rr1 = re->result;
- re->result = NULL;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- /* second field */
- if (!re->test_break(re->tbh)) {
-
- re->i.curfield = 2; /* stats */
-
- re->flag |= R_SEC_FIELD;
- if ((re->r.mode & R_FIELDSTILL) == 0) {
- re->field_offs = 0.5f;
- }
- RE_SetCamera(re, camera);
- if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
- re->flag &= ~R_SEC_FIELD;
-
- re->field_offs = 0.0f;
-
- rr2 = re->result;
- }
-
- /* allocate original height new buffers */
- re->winy *= 2;
- re->recty *= 2;
- re->disprect.ymin *= 2;
- re->disprect.ymax *= 2;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- if (rr2) {
- if (re->r.mode & R_ODDFIELD)
- merge_renderresult_fields(re->result, rr2, rr1);
- else
- merge_renderresult_fields(re->result, rr1, rr2);
-
- render_result_free(rr2);
- }
-
- render_result_free(rr1);
-
- re->i.curfield = 0; /* stats */
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->display_update(re->duh, re->result, NULL);
-}
-
/* make sure disprect is not affected by the render border */
static void render_result_disprect_to_full_resolution(Render *re)
{
@@ -1853,7 +1106,7 @@ static void render_result_uncrop(Render *re)
}
/* main render routine, no compositing */
-static void do_render_fields_blur_3d(Render *re)
+static void do_render(Render *re)
{
Object *camera = RE_GetCamera(re);
/* also check for camera here */
@@ -1866,12 +1119,7 @@ static void do_render_fields_blur_3d(Render *re)
/* now use renderdata and camera to set viewplane */
RE_SetCamera(re, camera);
- if (re->r.mode & R_FIELDS)
- do_render_fields_3d(re);
- else if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
+ do_render_3d(re);
/* when border render, check if we have to insert it in black */
render_result_uncrop(re);
@@ -1906,7 +1154,6 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->main = re->main;
resc->scene = sce;
resc->lay = sce->lay;
- resc->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
/* ensure scene has depsgraph, base flags etc OK */
BKE_scene_set_background(re->main, sce);
@@ -1921,7 +1168,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->current_scene_update = re->current_scene_update;
resc->suh = re->suh;
- do_render_fields_blur_3d(resc);
+ do_render(resc);
}
/* helper call to detect if this scene needs a render, or if there's a any render layer to render */
@@ -2189,12 +1436,14 @@ static void ntree_render_scenes(Render *re)
}
/* bad call... need to think over proper method still */
-static void render_composit_stats(void *UNUSED(arg), const char *str)
+static void render_composit_stats(void *arg, const char *str)
{
+ Render *re = (Render*)arg;
+
RenderStats i;
- memcpy(&i, &R.i, sizeof(i));
+ memcpy(&i, &re->i, sizeof(i));
i.infostr = str;
- R.stats_draw(R.sdh, &i);
+ re->stats_draw(re->sdh, &i);
}
#ifdef WITH_FREESTYLE
@@ -2221,63 +1470,24 @@ static void add_freestyle(Render *re, int render)
ViewLayer *view_layer, *active_view_layer;
LinkData *link;
Render *r;
- const bool do_link = (re->r.mode & R_MBLUR) == 0 || re->i.curblur == re->r.mblur_samples;
active_view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
FRS_begin_stroke_rendering(re);
for (view_layer = (ViewLayer *)re->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (do_link) {
- link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
- BLI_addtail(&re->freestyle_renders, link);
- }
+ link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
+ BLI_addtail(&re->freestyle_renders, link);
+
if ((re->r.scemode & R_SINGLE_LAYER) && view_layer != active_view_layer)
continue;
if (FRS_is_freestyle_enabled(view_layer)) {
r = FRS_do_stroke_rendering(re, view_layer, render);
- if (do_link)
- link->data = (void *)r;
+ link->data = (void *)r;
}
}
FRS_end_stroke_rendering(re);
-
- /* restore the global R value (invalidated by nested execution of the internal renderer) */
- R = *re;
-}
-
-/* merges the results of Freestyle stroke rendering into a given render result */
-static void composite_freestyle_renders(Render *re, int sample)
-{
- Render *freestyle_render;
- RenderView *rv;
- ViewLayer *view_layer, *active_view_layer;
- LinkData *link;
-
- active_view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
-
- link = (LinkData *)re->freestyle_renders.first;
-
- for (rv = re->result->views.first; rv; rv = rv->next) {
- for (view_layer = (ViewLayer *)re->view_layers.first; view_layer; view_layer = view_layer->next) {
- if ((re->r.scemode & R_SINGLE_LAYER) && view_layer != active_view_layer)
- continue;
-
- if (FRS_is_freestyle_enabled(view_layer)) {
- freestyle_render = (Render *)link->data;
-
- /* may be NULL in case of empty render layer */
- if (freestyle_render) {
- render_result_exr_file_read_sample(freestyle_render, sample);
- FRS_composite_result(re, view_layer, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
- }
- }
- link = link->next;
- }
- }
}
/* releases temporary scenes and renders for Freestyle stroke rendering */
@@ -2313,238 +1523,8 @@ static void free_all_freestyle_renders(void)
}
#endif
-/* reads all buffers, calls optional composite, merges in first result->views rectf */
-static void do_merge_fullsample(Render *re, bNodeTree *ntree)
-{
- ListBase *rectfs;
- RenderView *rv;
- rcti filter_mask = re->disprect;
- float *rectf, filt[3][3];
- int x, y, sample;
- int nr, numviews;
-
- /* interaction callbacks */
- if (ntree) {
- ntree->stats_draw = render_composit_stats;
- ntree->test_break = re->test_break;
- ntree->progress = re->progress;
- ntree->sdh = re->sdh;
- ntree->tbh = re->tbh;
- ntree->prh = re->prh;
- }
-
- /* filtmask needs it */
- R = *re;
-
- /* temporary storage of the acccumulation buffers */
- rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers");
-
- numviews = BLI_listbase_count(&re->result->views);
- for (nr = 0; nr < numviews; nr++) {
- rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
-
- /* we accumulate in here */
- rv->rectf = MEM_mapallocN(re->result->rectx * re->result->recty * sizeof(float) * 4, "fullsample rgba");
- BLI_addtail(rectfs, rv);
- }
-
- for (sample = 0; sample < re->r.osa; sample++) {
- Scene *sce;
- Render *re1;
- RenderResult rres;
- int mask;
-
- /* enable full sample print */
- R.i.curfsa = sample + 1;
-
- /* set all involved renders on the samplebuffers (first was done by render itself, but needs tagged) */
- /* also function below assumes this */
-
- tag_scenes_for_render(re);
- for (sce = re->main->scene.first; sce; sce = sce->id.next) {
- if (sce->id.tag & LIB_TAG_DOIT) {
- re1 = RE_GetSceneRender(sce);
-
- if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) {
- if (sample) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_read_sample(re1, sample);
-#ifdef WITH_FREESTYLE
- if (re1->r.mode & R_EDGE_FRS)
- composite_freestyle_renders(re1, sample);
-#endif
- BLI_rw_mutex_unlock(&re->resultmutex);
- render_result_uncrop(re1);
- }
- ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */
- }
- }
- }
-
-#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
- tag_groups_for_render(re);
-#endif
-
- /* composite */
- if (ntree) {
- ntreeCompositTagRender(re->scene);
- ntreeCompositTagAnimated(ntree);
-
- for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
- }
- }
-
- for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) {
- rectf = rv->rectf;
-
- /* ensure we get either composited result or the active layer */
- RE_AcquireResultImage(re, &rres, nr);
-
- /* accumulate with filter, and clip */
- mask = (1 << sample);
- mask_array(mask, filt);
-
- for (y = 0; y < re->result->recty; y++) {
- float *rf = rectf + 4 * y * re->result->rectx;
- float *col = rres.rectf + 4 * y * re->result->rectx;
-
- for (x = 0; x < re->result->rectx; x++, rf += 4, col += 4) {
- /* clamping to 1.0 is needed for correct AA */
- CLAMP(col[0], 0.0f, 1.0f);
- CLAMP(col[1], 0.0f, 1.0f);
- CLAMP(col[2], 0.0f, 1.0f);
-
- add_filt_fmask_coord(filt, col, rf, re->result->rectx, x, y, &filter_mask);
- }
- }
-
- RE_ReleaseResultImage(re);
-
- /* show stuff */
- if (sample != re->osa - 1) {
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- RE_SetActiveRenderView(re, rv->name);
- re->display_update(re->duh, re->result, NULL);
- }
- }
- }
-
- for (nr = 0; nr < numviews; nr++) {
- rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
-
- /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->result->recty; y++) {
- float *rf = rectf + 4 * y * re->result->rectx;
-
- for (x = 0; x < re->result->rectx; x++, rf += 4) {
- rf[0] = MAX2(rf[0], 0.0f);
- rf[1] = MAX2(rf[1], 0.0f);
- rf[2] = MAX2(rf[2], 0.0f);
- CLAMP(rf[3], 0.0f, 1.0f);
- }
- }
-
- /* store the final result */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rv = RE_RenderViewGetById(re->result, nr);
- if (rv->rectf)
- MEM_freeN(rv->rectf);
- rv->rectf = rectf;
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- /* clear interaction callbacks */
- if (ntree) {
- ntree->stats_draw = NULL;
- ntree->test_break = NULL;
- ntree->progress = NULL;
- ntree->tbh = ntree->sdh = ntree->prh = NULL;
- }
-
- /* disable full sample print */
- R.i.curfsa = 0;
-
- /* garbage collection */
- while (rectfs->first) {
- rv = rectfs->first;
- BLI_remlink(rectfs, rv);
- MEM_freeN(rv);
- }
- MEM_freeN(rectfs);
-}
-
-/* called externally, via compositor */
-void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
-{
- Scene *scene;
- bNode *node;
-
- /* default start situation */
- G.is_break = false;
-
- re->main = bmain;
- re->scene = sce;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
-
- /* first call RE_ReadRenderResult on every renderlayer scene. this creates Render structs */
-
- /* tag scenes unread */
- for (scene = re->main->scene.first; scene; scene = scene->id.next)
- scene->id.tag |= LIB_TAG_DOIT;
-
-#ifdef WITH_FREESTYLE
- if (re->freestyle_bmain) {
- for (scene = re->freestyle_bmain->scene.first; scene; scene = scene->id.next)
- scene->id.tag &= ~LIB_TAG_DOIT;
- }
-#endif
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
- Scene *nodescene = (Scene *)node->id;
-
- if (nodescene == NULL) nodescene = sce;
- if (nodescene->id.tag & LIB_TAG_DOIT) {
- nodescene->r.mode |= R_OSA; /* render struct needs tables */
- RE_ReadRenderResult(sce, nodescene);
- nodescene->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* own render result should be read/allocated */
- if (re->scene->id.tag & LIB_TAG_DOIT) {
- RE_ReadRenderResult(re->scene, re->scene);
- re->scene->id.tag &= ~LIB_TAG_DOIT;
- }
-
- /* and now we can draw (result is there) */
- re->display_init(re->dih, re->result);
- re->display_clear(re->dch, re->result);
-
-#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS) {
- init_freestyle(re);
- add_freestyle(re, 0);
- }
-#endif
-
- do_merge_fullsample(re, ntree);
-
-#ifdef WITH_FREESTYLE
- free_all_freestyle_renders();
-#endif
-
-#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
- /* Restore their visibility based on the viewport visibility flags. */
- tag_groups_for_render(re);
-#endif
-}
-
/* returns fully composited render-result on given time step (in RenderData) */
-static void do_render_composite_fields_blur_3d(Render *re)
+static void do_render_composite(Render *re)
{
bNodeTree *ntree = re->scene->nodetree;
int update_newframe = 0;
@@ -2560,7 +1540,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
* it could be optimized to render only the needed view
* but what if a scene has a different number of views
* than the main scene? */
- do_render_fields_blur_3d(re);
+ do_render(re);
}
else {
re->i.cfra = re->r.cfra;
@@ -2603,27 +1583,17 @@ static void do_render_composite_fields_blur_3d(Render *re)
ntree->stats_draw = render_composit_stats;
ntree->test_break = re->test_break;
ntree->progress = re->progress;
- ntree->sdh = re->sdh;
+ ntree->sdh = re;
ntree->tbh = re->tbh;
ntree->prh = re->prh;
- /* in case it was never initialized */
- R.sdh = re->sdh;
- R.stats_draw = re->stats_draw;
- R.i.starttime = re->i.starttime;
- R.i.cfra = re->i.cfra;
-
if (update_newframe) {
/* If we have consistent depsgraph now would be a time to update them. */
}
- if (re->r.scemode & R_FULL_SAMPLE)
- do_merge_fullsample(re, ntree);
- else {
- RenderView *rv;
- for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
- }
+ RenderView *rv;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
}
ntree->stats_draw = NULL;
@@ -2632,8 +1602,6 @@ static void do_render_composite_fields_blur_3d(Render *re)
ntree->tbh = ntree->sdh = ntree->prh = NULL;
}
}
- else if (re->r.scemode & R_FULL_SAMPLE)
- do_merge_fullsample(re, NULL);
}
#ifdef WITH_FREESTYLE
@@ -2804,7 +1772,7 @@ static void do_render_seq(Render *re)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* main loop: doing sequence + fields + blur + 3d render + compositing */
+/* main loop: doing sequence + 3d render + compositing */
static void do_render_all_options(Render *re)
{
Object *camera;
@@ -2834,12 +1802,7 @@ static void do_render_all_options(Render *re)
re->display_update(re->duh, re->result, NULL);
}
else {
- re->pool = BKE_image_pool_new();
-
- do_render_composite_fields_blur_3d(re);
-
- BKE_image_pool_free(re->pool);
- re->pool = NULL;
+ do_render_composite(re);
}
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -3032,13 +1995,6 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
BKE_report(reports, RPT_ERROR, "Cannot save render buffers, check the temp default path");
return 0;
}
-
- /* no fullsample and edge */
- if ((scemode & R_FULL_SAMPLE) && (scene->r.mode & R_EDGE)) {
- BKE_report(reports, RPT_ERROR, "Full sample does not support edge enhance");
- return 0;
- }
-
}
if (scemode & R_DOCOMP) {
@@ -3085,15 +2041,6 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
#endif
}
-#ifdef WITH_FREESTYLE
- if (scene->r.mode & R_EDGE_FRS) {
- if (scene->r.mode & R_FIELDS) {
- BKE_report(reports, RPT_ERROR, "Fields not supported in Freestyle");
- return false;
- }
- }
-#endif
-
if (RE_seq_render_active(scene, &scene->r)) {
if (scene->r.mode & R_BORDER) {
BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
@@ -3112,16 +2059,9 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
static void validate_render_settings(Render *re)
{
- if (re->r.scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) {
- /* no osa + fullsample won't work... */
- if (re->r.osa == 0)
- re->r.scemode &= ~R_FULL_SAMPLE;
- }
-
if (RE_engine_is_external(re)) {
/* not supported yet */
re->r.scemode &= ~(R_FULL_SAMPLE);
- re->r.mode &= ~(R_FIELDS | R_MBLUR);
}
}
@@ -3183,7 +2123,6 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->main = bmain;
re->scene = scene;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
re->camera_override = camera_override;
re->lay = lay_override ? lay_override : scene->lay;
re->layer_override = lay_override;
@@ -3296,7 +2235,7 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render
re->result_ok= 0;
if (render_initialize_from_main(re, &scene->r, bmain, scene, NULL, NULL, scene->lay, 0, 0)) {
if (render)
- do_render_fields_blur_3d(re);
+ do_render_3d(re);
}
re->result_ok = 1;
}
@@ -3310,7 +2249,28 @@ void RE_RenderFreestyleExternal(Render *re)
for (rv = re->result->views.first; rv; rv = rv->next) {
RE_SetActiveRenderView(re, rv->name);
- RE_Database_CameraOnly(re, re->main, re->scene, re->lay, 1);
+
+ /* scene needs to be set to get camera */
+ Object *camera = RE_GetCamera(re);
+
+ /* if no camera, viewmat should have been set! */
+ if (camera) {
+ /* called before but need to call again in case of lens animation from the
+ * above call to BKE_scene_graph_update_for_newframe, fixes bug. [#22702].
+ * following calls don't depend on 'RE_SetCamera' */
+ float mat[4][4];
+
+ RE_SetCamera(re, camera);
+ RE_GetCameraModelMatrix(re, camera, mat);
+ invert_m4(mat);
+ RE_SetView(re, mat);
+
+ /* force correct matrix for scaled cameras */
+ DEG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
+ }
+
+ printf("add freestyle\n");
+
add_freestyle(re, 1);
}
}
@@ -3838,20 +2798,14 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
RE_InitState(re, NULL, &sce->r, &sce->view_layers, sce->active_view_layer, NULL, winx, winy, NULL);
- re->pool = BKE_image_pool_new();
-
re->main = bmain;
re->scene = sce;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
re->lay = sce->lay;
camera = RE_GetCamera(re);
RE_SetCamera(re, camera);
do_render_3d(re);
-
- BKE_image_pool_free(re->pool);
- re->pool = NULL;
}
/* note; repeated win/disprect calc... solve that nicer, also in compo */
@@ -3891,7 +2845,6 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
re = RE_NewSceneRender(scene);
RE_InitState(re, NULL, &scene->r, &scene->view_layers, scene->active_view_layer, NULL, winx, winy, &disprect);
re->scene = scene;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
success = render_result_exr_file_cache_read(re);
@@ -3968,67 +2921,6 @@ void RE_result_load_from_file(RenderResult *result, ReportList *reports, const c
}
}
-const float default_envmap_layout[] = { 0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1 };
-
-bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, const char *relpath, const char imtype, float layout[12])
-{
- ImageFormatData imf;
- ImBuf *ibuf = NULL;
- int ok;
- int dx;
- int maxX = 0, maxY = 0, i = 0;
- char filepath[FILE_MAX];
-
- if (env->cube[1] == NULL) {
- BKE_report(reports, RPT_ERROR, "There is no generated environment map available to save");
- return 0;
- }
-
- imf = scene->r.im_format;
- imf.imtype = imtype;
-
- dx = env->cube[1]->x;
-
- if (env->type == ENV_CUBE) {
- for (i = 0; i < 12; i += 2) {
- maxX = max_ii(maxX, (int)layout[i] + 1);
- maxY = max_ii(maxY, (int)layout[i + 1] + 1);
- }
-
- ibuf = IMB_allocImBuf(maxX * dx, maxY * dx, 24, IB_rectfloat);
-
- for (i = 0; i < 12; i += 2)
- if (layout[i] > -1 && layout[i + 1] > -1)
- IMB_rectcpy(ibuf, env->cube[i / 2], layout[i] * dx, layout[i + 1] * dx, 0, 0, dx, dx);
- }
- else if (env->type == ENV_PLANE) {
- ibuf = IMB_allocImBuf(dx, dx, 24, IB_rectfloat);
- IMB_rectcpy(ibuf, env->cube[1], 0, 0, 0, 0, dx, dx);
- }
- else {
- BKE_report(reports, RPT_ERROR, "Invalid environment map type");
- return 0;
- }
-
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf);
-
- /* to save, we first get absolute path */
- BLI_strncpy(filepath, relpath, sizeof(filepath));
- BLI_path_abs(filepath, G.main->name);
-
- ok = BKE_imbuf_write(ibuf, filepath, &imf);
-
- IMB_freeImBuf(ibuf);
-
- if (ok) {
- return true;
- }
- else {
- BKE_report(reports, RPT_ERROR, "Error writing environment map");
- return false;
- }
-}
-
/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
deleted file mode 100644
index fc79786e5c7..00000000000
--- a/source/blender/render/intern/source/pixelblending.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): Full recode, 2004-2006 Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/pixelblending.c
- * \ingroup render
- *
- * Functions to blend pixels with or without alpha, in various formats
- * nzc - June 2000
- */
-
-
-#include <math.h>
-#include <string.h>
-
-/* global includes */
-
-/* own includes */
-#include "render_types.h"
-#include "pixelblending.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ------------------------------------------------------------------------- */
-/* Debug/behavior defines */
-/* if defined: alpha blending with floats clips color, as with shorts */
-/* #define RE_FLOAT_COLOR_CLIPPING */
-/* if defined: alpha values are clipped */
-/* For now, we just keep alpha clipping. We run into thresholding and */
-/* blending difficulties otherwise. Be careful here. */
-#define RE_ALPHA_CLIPPING
-
-
-
-/* Threshold for a 'full' pixel: pixels with alpha above this level are */
-/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */
-#define RE_FULL_COLOR_FLOAT 0.9998f
-/* Threshold for an 'empty' pixel: pixels with alpha above this level are */
-/* considered completely transparent. This is the decimal value */
-/* for 0x000F / 0xFFFF */
-#define RE_EMPTY_COLOR_FLOAT 0.0002f
-
-
-/* ------------------------------------------------------------------------- */
-
-void addAlphaOverFloat(float dest[4], const float source[4])
-{
- /* d = s + (1-alpha_s)d*/
- float mul;
-
- mul = 1.0f - source[3];
-
- dest[0] = (mul * dest[0]) + source[0];
- dest[1] = (mul * dest[1]) + source[1];
- dest[2] = (mul * dest[2]) + source[2];
- dest[3] = (mul * dest[3]) + source[3];
-
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-void addAlphaUnderFloat(float dest[4], const float source[4])
-{
- float mul;
-
- mul = 1.0f - dest[3];
-
- dest[0] += (mul * source[0]);
- dest[1] += (mul * source[1]);
- dest[2] += (mul * source[2]);
- dest[3] += (mul * source[3]);
-}
-
-
-/* ------------------------------------------------------------------------- */
-void addalphaAddfacFloat(float dest[4], const float source[4], char addfac)
-{
- float m; /* weiging factor of destination */
- float c; /* intermediate color */
-
- /* Addfac is a number between 0 and 1: rescale */
- /* final target is to diminish the influence of dest when addfac rises */
- m = 1.0f - (source[3] * ((255 - addfac) / 255.0f));
-
- /* blend colors*/
- c = (m * dest[0]) + source[0];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[0] = c;
-
- c = (m * dest[1]) + source[1];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[1] = c;
-
- c = (m * dest[2]) + source[2];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[2] = c;
-
- c = (m * dest[3]) + source[3];
-#ifdef RE_ALPHA_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[3] = c;
-
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/* filtered adding to scanlines */
-void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w)
-{
- /* calc the value of mask */
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- float *rb1, *rb2, *rb3;
- float val, r, g, b, al;
- unsigned int a, maskand, maskshift;
- int j;
-
- r = col[0];
- g = col[1];
- b = col[2];
- al = col[3];
-
- rb2 = rowbuf - 4;
- rb3 = rb2 - 4 * row_w;
- rb1 = rb2 + 4 * row_w;
-
- maskand = (mask & 255);
- maskshift = (mask >> 8);
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb1[0] += val * r;
- rb1[1] += val * g;
- rb1[2] += val * b;
- rb1[3] += val * al;
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb2[0] += val * r;
- rb2[1] += val * g;
- rb2[2] += val * b;
- rb2[3] += val * al;
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb3[0] += val * r;
- rb3[1] += val * g;
- rb3[2] += val * b;
- rb3[3] += val * al;
- }
-
- rb1 += 4;
- rb2 += 4;
- rb3 += 4;
- }
-}
-
-
-void mask_array(unsigned int mask, float filt[3][3])
-{
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- unsigned int maskand = (mask & 255);
- unsigned int maskshift = (mask >> 8);
- int a, j;
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- filt[2][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
-
- a += 3;
-
- filt[1][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
-
- a += 3;
-
- filt[0][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- }
-}
-
-
-/**
- * Index ordering, scanline based:
- *
- * <pre>
- * --- --- ---
- * | 2,0 | 2,1 | 2,2 |
- * --- --- ---
- * | 1,0 | 1,1 | 1,2 |
- * --- --- ---
- * | 0,0 | 0,1 | 0,2 |
- * --- --- ---
- * </pre>
- */
-
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask)
-{
- float *fpoin[3][3];
- float val, r, g, b, al, lfilt[3][3];
-
- r = col[0];
- g = col[1];
- b = col[2];
- al = col[3];
-
- memcpy(lfilt, filt, sizeof(lfilt));
-
- fpoin[0][1] = rowbuf - 4 * row_stride;
- fpoin[1][1] = rowbuf;
- fpoin[2][1] = rowbuf + 4 * row_stride;
-
- fpoin[0][0] = fpoin[0][1] - 4;
- fpoin[1][0] = fpoin[1][1] - 4;
- fpoin[2][0] = fpoin[2][1] - 4;
-
- fpoin[0][2] = fpoin[0][1] + 4;
- fpoin[1][2] = fpoin[1][1] + 4;
- fpoin[2][2] = fpoin[2][1] + 4;
-
- /* limit filtering to withing a mask for border rendering, so pixels don't
- * leak outside of the border */
- if (y <= mask->ymin) {
- fpoin[0][0] = fpoin[1][0];
- fpoin[0][1] = fpoin[1][1];
- fpoin[0][2] = fpoin[1][2];
- /* filter needs the opposite value yes! */
- lfilt[0][0] = filt[2][0];
- lfilt[0][1] = filt[2][1];
- lfilt[0][2] = filt[2][2];
- }
- else if (y >= mask->ymax - 1) {
- fpoin[2][0] = fpoin[1][0];
- fpoin[2][1] = fpoin[1][1];
- fpoin[2][2] = fpoin[1][2];
-
- lfilt[2][0] = filt[0][0];
- lfilt[2][1] = filt[0][1];
- lfilt[2][2] = filt[0][2];
- }
-
- if (x <= mask->xmin) {
- fpoin[2][0] = fpoin[2][1];
- fpoin[1][0] = fpoin[1][1];
- fpoin[0][0] = fpoin[0][1];
-
- lfilt[2][0] = filt[2][2];
- lfilt[1][0] = filt[1][2];
- lfilt[0][0] = filt[0][2];
- }
- else if (x >= mask->xmax - 1) {
- fpoin[2][2] = fpoin[2][1];
- fpoin[1][2] = fpoin[1][1];
- fpoin[0][2] = fpoin[0][1];
-
- lfilt[2][2] = filt[2][0];
- lfilt[1][2] = filt[1][0];
- lfilt[0][2] = filt[0][0];
- }
-
-
- /* loop unroll */
-#define MASKFILT(i, j) \
- val = lfilt[i][j]; \
- if (val != 0.0f) { \
- float *fp = fpoin[i][j]; \
- fp[0] += val * r; \
- fp[1] += val * g; \
- fp[2] += val * b; \
- fp[3] += val * al; \
- } (void)0
-
- MASKFILT(0, 0);
- MASKFILT(0, 1);
- MASKFILT(0, 2);
- MASKFILT(1, 0);
- MASKFILT(1, 1);
- MASKFILT(1, 2);
- MASKFILT(2, 0);
- MASKFILT(2, 1);
- MASKFILT(2, 2);
-
-#undef MASKFILT
-}
-
-void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
-{
- /* calc the value of mask */
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- float *rb1, *rb2, *rb3;
- float val;
- unsigned int a, maskand, maskshift;
- int i, j;
-
- rb2 = rowbuf - pixsize;
- rb3 = rb2 - pixsize * row_w;
- rb1 = rb2 + pixsize * row_w;
-
- maskand = (mask & 255);
- maskshift = (mask >> 8);
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb1[i] += val * in[i];
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb2[i] += val * in[i];
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb3[i] += val * in[i];
- }
-
- rb1 += pixsize;
- rb2 += pixsize;
- rb3 += pixsize;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-void addalphaAddFloat(float dest[4], const float source[4])
-{
-
- /* Makes me wonder whether this is required... */
- if (dest[3] < RE_EMPTY_COLOR_FLOAT) {
- dest[0] = source[0];
- dest[1] = source[1];
- dest[2] = source[2];
- dest[3] = source[3];
- return;
- }
-
- /* no clipping! */
- dest[0] = dest[0] + source[0];
- dest[1] = dest[1] + source[1];
- dest[2] = dest[2] + source[2];
- dest[3] = dest[3] + source[3];
-
-}
-
-
-/* ---------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
deleted file mode 100644
index ddbdb35bf51..00000000000
--- a/source/blender/render/intern/source/pixelshading.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/pixelshading.c
- * \ingroup render
- */
-
-
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-/* External modules: */
-
-#include "DNA_group_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-#include "DNA_image_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_lamp_types.h"
-
-#include "BKE_material.h"
-
-
-/* own module */
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "texture.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "pixelshading.h"
-#include "sunsky.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-extern const float hashvectf[];
-
-static void render_lighting_halo(HaloRen *har, float col_r[3])
-{
- GroupObject *go;
- LampRen *lar;
- float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
- float ir, ig, ib, shadfac, soft, lacol[3];
-
- ir= ig= ib= 0.0;
-
- copy_v3_v3(rco, har->co);
- dco[0]=dco[1]=dco[2]= 1.0f/har->rad;
-
- vn= har->no;
-
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
-
- /* test for lamplayer */
- if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue;
-
- /* lampdist cacluation */
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- copy_v3_v3(lv, lar->vec);
- lampdist= 1.0;
- }
- else {
- lv[0]= rco[0]-lar->co[0];
- lv[1]= rco[1]-lar->co[1];
- lv[2]= rco[2]-lar->co[2];
- ld = len_v3(lv);
- lv[0]/= ld;
- lv[1]/= ld;
- lv[2]/= ld;
-
- /* ld is re-used further on (texco's) */
-
- if (lar->mode & LA_QUAD) {
- t= 1.0;
- if (lar->ld1>0.0f)
- t= lar->dist/(lar->dist+lar->ld1*ld);
- if (lar->ld2>0.0f)
- t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
-
- lampdist= t;
- }
- else {
- lampdist= (lar->dist/(lar->dist+ld));
- }
-
- if (lar->mode & LA_SPHERE) {
- t= lar->dist - ld;
- if (t<0.0f) continue;
-
- t/= lar->dist;
- lampdist*= (t);
- }
-
- }
-
- lacol[0]= lar->r;
- lacol[1]= lar->g;
- lacol[2]= lar->b;
-
- if (lar->mode & LA_TEXTURE) {
- ShadeInput shi;
-
- /* Warning, This is not that nice, and possibly a bit slow,
- * however some variables were not initialized properly in, unless using shade_input_initialize(...),
- * we need to do a memset */
- memset(&shi, 0, sizeof(ShadeInput));
- /* end warning! - Campbell */
-
- copy_v3_v3(shi.co, rco);
- shi.osatex= 0;
- do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
- }
-
- if (lar->type==LA_SPOT) {
-
- if (lar->mode & LA_SQUARE) {
- if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
- float x, lvrot[3];
-
- /* rotate view to lampspace */
- copy_v3_v3(lvrot, lv);
- mul_m3_v3(lar->imat, lvrot);
-
- x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
- /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
-
- inpr = 1.0f / (sqrtf(1.0f + x * x));
- }
- else inpr= 0.0;
- }
- else {
- inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
- }
-
- t= lar->spotsi;
- if (inpr<t) continue;
- else {
- t= inpr-t;
- soft= 1.0;
- if (t<lar->spotbl && lar->spotbl!=0.0f) {
- /* soft area */
- i= t/lar->spotbl;
- t= i*i;
- soft= (3.0f*t-2.0f*t*i);
- inpr*= soft;
- }
- if (lar->mode & LA_ONLYSHADOW) {
- /* if (ma->mode & MA_SHADOW) { */
- /* dot product positive: front side face! */
- inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
- if (inp>0.0f) {
- /* testshadowbuf==0.0 : 100% shadow */
- shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
- if ( shadfac>0.0f ) {
- shadfac*= inp*soft*lar->energy;
- ir -= shadfac;
- ig -= shadfac;
- ib -= shadfac;
-
- continue;
- }
- }
- /* } */
- }
- lampdist*=inpr;
- }
- if (lar->mode & LA_ONLYSHADOW) continue;
-
- }
-
- /* dot product and reflectivity*/
-
- inp = 1.0f - fabsf(dot_v3v3(vn, lv));
-
- /* inp= cos(0.5*M_PI-acos(inp)); */
-
- i= inp;
-
- if (lar->type==LA_HEMI) {
- i= 0.5f*i+0.5f;
- }
- if (i>0.0f) {
- i*= lampdist;
- }
-
- /* shadow */
- if (i> -0.41f) { /* heuristic valua! */
- if (lar->shb) {
- shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
- if (shadfac==0.0f) continue;
- i*= shadfac;
- }
- }
-
- if (i>0.0f) {
- ir+= i*lacol[0];
- ig+= i*lacol[1];
- ib+= i*lacol[2];
- }
- }
-
- if (ir<0.0f) ir= 0.0f;
- if (ig<0.0f) ig= 0.0f;
- if (ib<0.0f) ib= 0.0f;
-
- col_r[0]*= ir;
- col_r[1]*= ig;
- col_r[2]*= ib;
-
-}
-
-
-/**
- * Converts a halo z-buffer value to distance from the camera's near plane
- * \param z The z-buffer value to convert
- * \return a distance from the camera's near plane in blender units
- */
-static float haloZtoDist(int z)
-{
- float zco = 0;
-
- if (z >= 0x7FFFFF)
- return 10e10;
- else {
- zco = (float)z/(float)0x7FFFFF;
- if (R.r.mode & R_ORTHO)
- return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
- else
- return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
- }
-}
-
-/**
- * \param col (float[4]) Store the rgb color here (with alpha)
- * The alpha is used to blend the color to the background
- * color_new = (1-alpha)*color_background + color
- * \param zz The current zbuffer value at the place of this pixel
- * \param dist Distance of the pixel from the center of the halo squared. Given in pixels
- * \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
- * \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
- */
-int shadeHaloFloat(HaloRen *har, float col[4], int zz,
- float dist, float xn, float yn, short flarec)
-{
- /* fill in col */
- float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
- int a;
-
- if (R.wrld.mode & WO_MIST) {
- if (har->type & HA_ONLYSKY) {
- alpha= har->alfa;
- }
- else {
- /* a bit patchy... */
- alpha= mistfactor(-har->co[2], har->co)*har->alfa;
- }
- }
- else alpha= har->alfa;
-
- if (alpha==0.0f)
- return 0;
-
- /* soften the halo if it intersects geometry */
- if (har->mat && har->mat->mode & MA_HALO_SOFT) {
- float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften;
-
- /* calculate halo depth */
- segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
- halo_depth= 2.0f*segment_length;
-
- if (halo_depth < FLT_EPSILON)
- return 0;
-
- /* calculate how much of this depth is visible */
- distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
- /* visible_depth = halo_depth; */ /* UNUSED */
- if (distance_from_z < segment_length) {
- soften= (segment_length + distance_from_z)/halo_depth;
-
- /* apply softening to alpha */
- if (soften < 1.0f)
- alpha *= soften;
- if (alpha <= 0.0f)
- return 0;
- }
- }
- else {
- /* not a soft halo. use the old softening code */
- /* halo being intersected? */
- if (har->zs> zz-har->zd) {
- t= ((float)(zz-har->zs))/(float)har->zd;
- alpha*= sqrtf(sqrtf(t));
- }
- }
-
- radist = sqrtf(dist);
-
- /* watch it: not used nicely: flarec is set at zero in pixstruct */
- if (flarec) har->pixels+= (int)(har->rad-radist);
-
- if (har->ringc) {
- const float *rc;
- float fac;
- int ofs;
-
- /* per ring an antialised circle */
- ofs= har->seed;
-
- for (a= har->ringc; a>0; a--, ofs+=2) {
-
- rc= hashvectf + (ofs % 768);
-
- fac = fabsf(rc[1] * (har->rad * fabsf(rc[0]) - radist));
-
- if (fac< 1.0f) {
- ringf+= (1.0f-fac);
- }
- }
- }
-
- if (har->type & HA_VECT) {
- dist= fabsf(har->cos * (yn) - har->sin * (xn)) / har->rad;
- if (dist>1.0f) dist= 1.0f;
- if (har->tex) {
- zn= har->sin*xn - har->cos*yn;
- yn= har->cos*xn + har->sin*yn;
- xn= zn;
- }
- }
- else dist= dist/har->radsq;
-
- if (har->type & HA_FLARECIRC) {
- dist = 0.5f + fabsf(dist - 0.5f);
- }
-
- if (har->hard>=30) {
- dist = sqrtf(dist);
- if (har->hard>=40) {
- dist = sinf(dist*(float)M_PI_2);
- if (har->hard>=50) {
- dist = sqrtf(dist);
- }
- }
- }
- else if (har->hard<20) dist*=dist;
-
- if (dist < 1.0f)
- dist= (1.0f-dist);
- else
- dist= 0.0f;
-
- if (har->linec) {
- const float *rc;
- float fac;
- int ofs;
-
- /* per starpoint an antialiased line */
- ofs= har->seed;
-
- for (a= har->linec; a>0; a--, ofs+=3) {
-
- rc= hashvectf + (ofs % 768);
-
- fac = fabsf((xn) * rc[0] + (yn) * rc[1]);
-
- if (fac< 1.0f )
- linef+= (1.0f-fac);
- }
-
- linef*= dist;
- }
-
- if (har->starpoints) {
- float ster, angle;
- /* rotation */
- angle = atan2f(yn, xn);
- angle *= (1.0f+0.25f*har->starpoints);
-
- co= cosf(angle);
- si= sinf(angle);
-
- angle= (co*xn+si*yn)*(co*yn-si*xn);
-
- ster = fabsf(angle);
- if (ster>1.0f) {
- ster= (har->rad)/(ster);
-
- if (ster<1.0f) dist*= sqrtf(ster);
- }
- }
-
- /* disputable optimize... (ton) */
- if (dist<=0.00001f)
- return 0;
-
- dist*= alpha;
- ringf*= dist;
- linef*= alpha;
-
- /* The color is either the rgb spec-ed by the user, or extracted from */
- /* the texture */
- if (har->tex) {
- col[0]= har->r;
- col[1]= har->g;
- col[2]= har->b;
- col[3]= dist;
-
- do_halo_tex(har, xn, yn, col);
-
- col[0]*= col[3];
- col[1]*= col[3];
- col[2]*= col[3];
-
- }
- else {
- col[0]= dist*har->r;
- col[1]= dist*har->g;
- col[2]= dist*har->b;
- if (har->type & HA_XALPHA) col[3]= dist*dist;
- else col[3]= dist;
- }
-
- if (har->mat) {
- if (har->mat->mode & MA_HALO_SHADE) {
- /* we test for lights because of preview... */
- if (R.lights.first) render_lighting_halo(har, col);
- }
-
- /* Next, we do the line and ring factor modifications. */
- if (linef!=0.0f) {
- Material *ma= har->mat;
-
- col[0]+= linef * ma->specr;
- col[1]+= linef * ma->specg;
- col[2]+= linef * ma->specb;
-
- if (har->type & HA_XALPHA) col[3]+= linef*linef;
- else col[3]+= linef;
- }
- if (ringf!=0.0f) {
- Material *ma= har->mat;
-
- col[0]+= ringf * ma->mirr;
- col[1]+= ringf * ma->mirg;
- col[2]+= ringf * ma->mirb;
-
- if (har->type & HA_XALPHA) col[3]+= ringf*ringf;
- else col[3]+= ringf;
- }
- }
-
- /* alpha requires clip, gives black dots */
- if (col[3] > 1.0f)
- col[3]= 1.0f;
-
- return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/* Only view vector is important here. Result goes to col_r[3] */
-void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
-{
- float zen[3], hor[3], blend, blendm;
- int skyflag;
-
- /* flag indicating if we render the top hemisphere */
- skyflag = WO_ZENUP;
-
- /* Some view vector stuff. */
- if (R.wrld.skytype & WO_SKYREAL) {
-
- blend = dot_v3v3(view, R.grvec);
-
- if (blend<0.0f) skyflag= 0;
-
- blend = fabsf(blend);
- }
- else if (R.wrld.skytype & WO_SKYPAPER) {
- blend= 0.5f + 0.5f * view[1];
- }
- else {
- /* the fraction of how far we are above the bottom of the screen */
- blend = fabsf(0.5f + view[1]);
- }
-
- copy_v3_v3(hor, &R.wrld.horr);
- copy_v3_v3(zen, &R.wrld.zenr);
-
- /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
- /* SKYBLEND is active, the texture and color blend are added. */
- if (R.wrld.skytype & WO_SKYTEX) {
- float lo[3];
- copy_v3_v3(lo, view);
- if (R.wrld.skytype & WO_SKYREAL) {
-
- mul_m3_v3(R.imat, lo);
-
- SWAP(float, lo[1], lo[2]);
-
- }
- do_sky_tex(rco, view, lo, dxyview, hor, zen, &blend, skyflag, thread);
- }
-
- if (blend>1.0f) blend= 1.0f;
- blendm= 1.0f-blend;
-
- /* No clipping, no conversion! */
- if (R.wrld.skytype & WO_SKYBLEND) {
- col_r[0] = (blendm*hor[0] + blend*zen[0]);
- col_r[1] = (blendm*hor[1] + blend*zen[1]);
- col_r[2] = (blendm*hor[2] + blend*zen[2]);
- }
- else {
- /* Done when a texture was grabbed. */
- col_r[0]= hor[0];
- col_r[1]= hor[1];
- col_r[2]= hor[2];
- }
-}
-
-/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
-void shadeSunView(float col_r[3], const float view[3])
-{
- GroupObject *go;
- LampRen *lar;
- float sview[3];
- bool do_init = true;
-
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) {
- float sun_collector[3];
- float colorxyz[3];
-
- if (do_init) {
-
- normalize_v3_v3(sview, view);
- mul_m3_v3(R.imat, sview);
- if (sview[2] < 0.0f)
- sview[2] = 0.0f;
- normalize_v3(sview);
- do_init = false;
- }
-
- GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
- xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
- lar->sunsky->sky_colorspace);
-
- ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
- }
- }
-}
-
-
-/*
- * Stuff the sky color into the collector.
- */
-void shadeSkyPixel(float collector[4], float fx, float fy, short thread)
-{
- float view[3], dxyview[2];
-
- /*
- * The rules for sky:
- * 1. Draw an image, if a background image was provided. Stop
- * 2. get texture and color blend, and combine these.
- */
-
- float fac;
-
- if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
- /* 1. solid color */
- copy_v3_v3(collector, &R.wrld.horr);
-
- collector[3] = 0.0f;
- }
- else {
- /* 2. */
-
- /* This one true because of the context of this routine */
- if (R.wrld.skytype & WO_SKYPAPER) {
- view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
- view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
- view[2]= 0.0;
-
- dxyview[0]= 1.0f/(float)R.winx;
- dxyview[1]= 1.0f/(float)R.winy;
- }
- else {
- calc_view_vector(view, fx, fy);
- fac= normalize_v3(view);
-
- if (R.wrld.skytype & WO_SKYTEX) {
- dxyview[0]= -R.viewdx/fac;
- dxyview[1]= -R.viewdy/fac;
- }
- }
-
- /* get sky color in the collector */
- shadeSkyView(collector, NULL, view, dxyview, thread);
- collector[3] = 0.0f;
- }
-
- calc_view_vector(view, fx, fy);
- shadeSunView(collector, view);
-}
-
-/* aerial perspective */
-void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance)
-{
- float view[3];
-
- calc_view_vector(view, fx, fy);
- normalize_v3(view);
- /*mul_m3_v3(R.imat, view);*/
- AtmospherePixleShader(sunsky, view, distance, collector);
-}
-
-/* eof */
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 6d0cd52544b..86f31f79c49 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -63,15 +63,9 @@
#include "render_types.h"
#include "texture.h"
-#include "pointdensity.h"
#include "RE_render_ext.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "RE_shader_ext.h"
static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -80,15 +74,13 @@ static int point_data_used(PointDensity *pd)
int pd_bitflag = 0;
if (pd->source == TEX_PD_PSYS) {
- if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
- (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
+ if ((pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
(pd->color_source == TEX_PD_COLOR_PARTVEL) ||
(pd->color_source == TEX_PD_COLOR_PARTSPEED))
{
pd_bitflag |= POINT_DATA_VEL;
}
- if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
- (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
+ if ((pd->color_source == TEX_PD_COLOR_PARTAGE) ||
(pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
{
pd_bitflag |= POINT_DATA_LIFE;
@@ -466,10 +458,10 @@ static void pointdensity_cache_object(Depsgraph *depsgraph, Scene *scene,
}
-static void cache_pointdensity_ex(Depsgraph *depsgraph,
- Scene *scene,
- PointDensity *pd,
- const bool use_render_params)
+static void cache_pointdensity(Depsgraph *depsgraph,
+ Scene *scene,
+ PointDensity *pd,
+ const bool use_render_params)
{
if (pd == NULL) {
return;
@@ -507,15 +499,7 @@ static void cache_pointdensity_ex(Depsgraph *depsgraph,
}
}
-void cache_pointdensity(Depsgraph *depsgraph, Render *re, PointDensity *pd)
-{
- cache_pointdensity_ex(depsgraph,
- re->scene,
- pd,
- true);
-}
-
-void free_pointdensity(PointDensity *pd)
+static void free_pointdensity(PointDensity *pd)
{
if (pd == NULL) {
return;
@@ -533,41 +517,6 @@ void free_pointdensity(PointDensity *pd)
pd->totpoints = 0;
}
-void make_pointdensities(Depsgraph *depsgraph, Render *re)
-{
- Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW) {
- return;
- }
-
- re->i.infostr = IFACE_("Caching Point Densities");
- re->stats_draw(re->sdh, &re->i);
-
- for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_POINTDENSITY) {
- cache_pointdensity(depsgraph, re, tex->pd);
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-void free_pointdensities(Render *re)
-{
- Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW)
- return;
-
- for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_POINTDENSITY) {
- free_pointdensity(tex->pd);
- }
- }
-}
-
typedef struct PointDensityRangeData {
float *density;
float squared_radius;
@@ -678,7 +627,7 @@ static int pointdensity(PointDensity *pd,
{
int retval = TEX_INT;
PointDensityRangeData pdr;
- float density = 0.0f, age = 0.0f, time = 0.0f;
+ float density = 0.0f, age = 0.0f;
float vec[3] = {0.0f, 0.0f, 0.0f}, col[3] = {0.0f, 0.0f, 0.0f}, co[3];
float turb, noise_fac;
int num = 0;
@@ -712,21 +661,8 @@ static int pointdensity(PointDensity *pd,
}
if (pd->flag & TEX_PD_TURBULENCE) {
-
- if (pd->noise_influence == TEX_PD_NOISE_AGE) {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
- pd->noise_depth, 0, pd->noise_basis);
- }
- else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
- time = R.r.cfra / (float)R.r.efra;
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
- pd->noise_depth, 0, pd->noise_basis);
- //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
- }
- else {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
- pd->noise_depth, 0, pd->noise_basis);
- }
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
+ pd->noise_depth, 0, pd->noise_basis);
turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
@@ -838,26 +774,6 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
return retval;
}
-int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
-{
- PointDensity *pd = tex->pd;
- float age = 0.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f};
- float col[3] = {0.0f, 0.0f, 0.0f};
- int retval = pointdensity(pd, texvec, texres, vec, &age, col);
-
- retval |= pointdensity_color(pd, texres, age, vec, col);
- BRICONTRGB;
-
- return retval;
-
-#if 0
- if (texres->nor!=NULL) {
- texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
- }
-#endif
-}
-
static void sample_dummy_point_density(int resolution, float *values)
{
memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
@@ -927,7 +843,7 @@ void RE_point_density_cache(
/* Same matricies/resolution as dupli_render_particle_set(). */
BLI_mutex_lock(&sample_mutex);
- cache_pointdensity_ex(depsgraph, scene, pd, use_render_params);
+ cache_pointdensity(depsgraph, scene, pd, use_render_params);
BLI_mutex_unlock(&sample_mutex);
}
@@ -1017,11 +933,15 @@ static void point_density_sample_func(
texvec[1] += dim[1] * (float)y / (float)resolution;
texvec[2] += dim[2] * (float)z / (float)resolution;
- pointdensity(pd, texvec, &texres, vec, &age, col);
- pointdensity_color(pd, &texres, age, vec, col);
+ if (pointdensity(pd, texvec, &texres, vec, &age, col)) {
+ pointdensity_color(pd, &texres, age, vec, col);
- copy_v3_v3(&values[index*4 + 0], &texres.tr);
- values[index*4 + 3] = texres.tin;
+ copy_v3_v3(&values[index*4 + 0], &texres.tr);
+ values[index*4 + 3] = texres.tin;
+ }
+ else {
+ zero_v4(&values[index*4]);
+ }
}
}
}
@@ -1081,3 +1001,8 @@ void RE_point_density_free(struct PointDensity *pd)
{
free_pointdensity(pd);
}
+
+void RE_point_density_fix_linking(void)
+{
+}
+
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
deleted file mode 100644
index 7bac7f29c5a..00000000000
--- a/source/blender/render/intern/source/rayshade.c
+++ /dev/null
@@ -1,2474 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/rayshade.c
- * \ingroup render
- */
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <float.h>
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-#include "DNA_lamp_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_system.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_node.h"
-
-#include "render_result.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "pixelshading.h"
-#include "shading.h"
-#include "volumetric.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "raycounter.h"
-
-#define RAY_TRA 1
-#define RAY_INSIDE 2
-
-#define DEPTH_SHADOW_TRA 10
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static int test_break(void *data)
-{
- Render *re = (Render *)data;
- return re->test_break(re->tbh);
-}
-
-static void RE_rayobject_config_control(RayObject *r, Render *re)
-{
- if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->control.data = re;
- r->control.test_break = test_break;
- }
-}
-
-RayObject *RE_rayobject_create(int type, int size, int octree_resolution)
-{
- RayObject * res = NULL;
-
- if (type == R_RAYSTRUCTURE_AUTO) {
- /* TODO */
- //if (detect_simd())
-#ifdef __SSE__
- type = BLI_cpu_support_sse2()? R_RAYSTRUCTURE_SIMD_SVBVH: R_RAYSTRUCTURE_VBVH;
-#else
- type = R_RAYSTRUCTURE_VBVH;
-#endif
- }
-
-#ifndef __SSE__
- if (type == R_RAYSTRUCTURE_SIMD_SVBVH || type == R_RAYSTRUCTURE_SIMD_QBVH) {
- puts("Warning: Using VBVH (SSE was disabled at compile time)");
- type = R_RAYSTRUCTURE_VBVH;
- }
-#endif
-
-
- if (type == R_RAYSTRUCTURE_OCTREE) //TODO dynamic ocres
- res = RE_rayobject_octree_create(octree_resolution, size);
- else if (type == R_RAYSTRUCTURE_VBVH)
- res = RE_rayobject_vbvh_create(size);
- else if (type == R_RAYSTRUCTURE_SIMD_SVBVH)
- res = RE_rayobject_svbvh_create(size);
- else if (type == R_RAYSTRUCTURE_SIMD_QBVH)
- res = RE_rayobject_qbvh_create(size);
- else
- res = RE_rayobject_vbvh_create(size); //Fallback
-
- return res;
-}
-
-static RayObject* rayobject_create(Render *re, int type, int size)
-{
- RayObject * res = NULL;
-
- res = RE_rayobject_create(type, size, re->r.ocres);
-
- if (res)
- RE_rayobject_config_control(res, re);
-
- return res;
-}
-
-#ifdef RE_RAYCOUNTER
-RayCounter re_rc_counter[BLENDER_MAX_THREADS];
-#endif
-
-
-void freeraytree(Render *re)
-{
- ObjectInstanceRen *obi;
-
- if (re->raytree) {
- RE_rayobject_free(re->raytree);
- re->raytree = NULL;
- }
- if (re->rayfaces) {
- MEM_freeN(re->rayfaces);
- re->rayfaces = NULL;
- }
- if (re->rayprimitives) {
- MEM_freeN(re->rayprimitives);
- re->rayprimitives = NULL;
- }
-
- for (obi=re->instancetable.first; obi; obi=obi->next) {
- ObjectRen *obr = obi->obr;
- if (obr->raytree) {
- RE_rayobject_free(obr->raytree);
- obr->raytree = NULL;
- }
- if (obr->rayfaces) {
- MEM_freeN(obr->rayfaces);
- obr->rayfaces = NULL;
- }
- if (obi->raytree) {
- RE_rayobject_free(obi->raytree);
- obi->raytree = NULL;
- }
- }
-
-#ifdef RE_RAYCOUNTER
- {
- const int num_threads = re->r.threads;
- RayCounter sum;
- memset(&sum, 0, sizeof(sum));
- int i;
- for (i=0; i<num_threads; i++)
- RE_RC_MERGE(&sum, re_rc_counter+i);
- RE_RC_INFO(&sum);
- }
-#endif
-}
-
-static bool is_raytraceable_vlr(Render *re, VlakRen *vlr)
-{
- /* note: volumetric must be tracable, wire must not */
- if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
- if (vlr->mat->material_type != MA_TYPE_WIRE)
- return 1;
- return 0;
-}
-
-static bool is_raytraceable(Render *re, ObjectInstanceRen *obi)
-{
- int v;
- ObjectRen *obr = obi->obr;
-
- if (re->excludeob && obr->ob == re->excludeob)
- return 0;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
-
- if (is_raytraceable_vlr(re, vlr))
- return 1;
- }
-
- return 0;
-}
-
-
-RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
-{
- /*TODO
- * out-of-memory safeproof
- * break render
- * update render stats */
- ObjectRen *obr = obi->obr;
-
- if (obr->raytree == NULL) {
- RayObject *raytree;
- RayFace *face = NULL;
- VlakPrimitive *vlakprimitive = NULL;
- int v;
-
- //Count faces
- int faces = 0;
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr))
- faces++;
- }
-
- if (faces == 0)
- return NULL;
-
- //Create Ray cast accelaration structure
- raytree = rayobject_create( re, re->r.raytrace_structure, faces );
- if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) )
- vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives");
- else
- face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces");
-
- obr->rayobi = obi;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
- RE_rayobject_add(raytree, RE_vlakprimitive_from_vlak(vlakprimitive, obi, vlr));
- vlakprimitive++;
- }
- else {
- RE_rayface_from_vlak(face, obi, vlr);
- RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
- face++;
- }
- }
- }
- RE_rayobject_done(raytree);
-
- /* in case of cancel during build, raytree is not usable */
- if (test_break(re))
- RE_rayobject_free(raytree);
- else
- obr->raytree= raytree;
- }
-
- if (obr->raytree) {
- if ((obi->flag & R_TRANSFORMED) && obi->raytree == NULL) {
- obi->transform_primitives = 0;
- obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi );
- }
- }
-
- if (obi->raytree) return obi->raytree;
- return obi->obr->raytree;
-}
-
-static bool has_special_rayobject(Render *re, ObjectInstanceRen *obi)
-{
- if ( (obi->flag & R_TRANSFORMED) && (re->r.raytrace_options & R_RAYTRACE_USE_INSTANCES) ) {
- ObjectRen *obr = obi->obr;
- int v, faces = 0;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- faces++;
- if (faces > 4)
- return 1;
- }
- }
- }
- return 0;
-}
-/*
- * create a single raytrace structure with all faces
- */
-static void makeraytree_single(Render *re)
-{
- ObjectInstanceRen *obi;
- RayObject *raytree;
- RayFace *face = NULL;
- VlakPrimitive *vlakprimitive = NULL;
- int faces = 0, special = 0;
-
- for (obi = re->instancetable.first; obi; obi = obi->next) {
- if (is_raytraceable(re, obi)) {
- ObjectRen *obr = obi->obr;
-
- if (has_special_rayobject(re, obi)) {
- special++;
- }
- else {
- int v;
- for (v = 0;v < obr->totvlak; v++) {
- VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- faces++;
- }
- }
- }
- }
- }
-
- if (faces + special == 0) {
- re->raytree = RE_rayobject_empty_create();
- return;
- }
-
- //Create raytree
- raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special );
-
- if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) {
- vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives");
- }
- else {
- face = re->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces");
- }
-
- for (obi=re->instancetable.first; obi; obi=obi->next)
- if (is_raytraceable(re, obi)) {
- if (test_break(re))
- break;
-
- if (has_special_rayobject(re, obi)) {
- RayObject *obj = makeraytree_object(re, obi);
-
- if (test_break(re))
- break;
-
- if (obj)
- RE_rayobject_add(re->raytree, obj);
- }
- else {
- int v;
- ObjectRen *obr = obi->obr;
-
- if (obi->flag & R_TRANSFORMED) {
- obi->transform_primitives = 1;
- }
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
- RayObject *obj = RE_vlakprimitive_from_vlak( vlakprimitive, obi, vlr );
- RE_rayobject_add(raytree, obj);
- vlakprimitive++;
- }
- else {
- RE_rayface_from_vlak(face, obi, vlr);
- if ((obi->flag & R_TRANSFORMED)) {
- mul_m4_v3(obi->mat, face->v1);
- mul_m4_v3(obi->mat, face->v2);
- mul_m4_v3(obi->mat, face->v3);
- if (RE_rayface_isQuad(face))
- mul_m4_v3(obi->mat, face->v4);
- }
-
- RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
- face++;
- }
- }
- }
- }
- }
-
- if (!test_break(re)) {
- re->i.infostr = IFACE_("Raytree.. building");
- re->stats_draw(re->sdh, &re->i);
-
- RE_rayobject_done(raytree);
- }
-}
-
-void makeraytree(Render *re)
-{
- float min[3], max[3], sub[3];
- int i;
-
- re->i.infostr = IFACE_("Raytree.. preparing");
- re->stats_draw(re->sdh, &re->i);
-
- /* disable options not yet supported by octree,
- * they might actually never be supported (unless people really need it) */
- if (re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE)
- re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS);
-
- makeraytree_single(re);
-
- if (test_break(re)) {
- freeraytree(re);
-
- re->i.infostr = IFACE_("Raytree building canceled");
- re->stats_draw(re->sdh, &re->i);
- }
- else {
- /* Calculate raytree max_size
- * This is ONLY needed to kept a bogus behavior of SUN and HEMI lights */
- INIT_MINMAX(min, max);
- RE_rayobject_merge_bb(re->raytree, min, max);
- if (min[0] > max[0]) { /* empty raytree */
- zero_v3(min);
- zero_v3(max);
- }
- for (i=0; i<3; i++) {
- /* TODO: explain why add top both min and max??? */
- min[i] += 0.01f;
- max[i] += 0.01f;
- sub[i] = max[i]-min[i];
- }
-
- re->maxdist = len_v3(sub);
-
- re->i.infostr = IFACE_("Raytree finished");
- re->stats_draw(re->sdh, &re->i);
- }
-
-#ifdef RE_RAYCOUNTER
- memset(re_rc_counter, 0, sizeof(re_rc_counter));
-#endif
-}
-
-/* if (shi->osatex) */
-static void shade_ray_set_derivative(ShadeInput *shi)
-{
- float detsh, t00, t10, t01, t11;
- int axis1, axis2;
-
- /* find most stable axis to project */
- axis_dominant_v3(&axis1, &axis2, shi->facenor);
-
- /* compute u,v and derivatives */
- if (shi->obi->flag & R_TRANSFORMED) {
- float v1[3], v2[3], v3[3];
-
- mul_v3_m3v3(v1, shi->obi->nmat, shi->v1->co);
- mul_v3_m3v3(v2, shi->obi->nmat, shi->v2->co);
- mul_v3_m3v3(v3, shi->obi->nmat, shi->v3->co);
-
- /* same as below */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
- }
- else {
- const float *v1= shi->v1->co;
- const float *v2= shi->v2->co;
- const float *v3= shi->v3->co;
-
- /* same as above */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
- }
-
- detsh= 1.0f/(t00*t11-t10*t01);
- t00*= detsh; t01*=detsh;
- t10*=detsh; t11*=detsh;
-
- shi->dx_u= shi->dxco[axis1]*t11- shi->dxco[axis2]*t10;
- shi->dx_v= shi->dxco[axis2]*t00- shi->dxco[axis1]*t01;
- shi->dy_u= shi->dyco[axis1]*t11- shi->dyco[axis2]*t10;
- shi->dy_v= shi->dyco[axis2]*t00- shi->dyco[axis1]*t01;
-
-}
-
-/* main ray shader */
-void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
-{
- ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob;
- VlakRen *vlr = (VlakRen *)is->hit.face;
-
- /* set up view vector */
- copy_v3_v3(shi->view, is->dir);
-
- /* render co */
- shi->co[0]= is->start[0]+is->dist*(shi->view[0]);
- shi->co[1]= is->start[1]+is->dist*(shi->view[1]);
- shi->co[2]= is->start[2]+is->dist*(shi->view[2]);
-
- normalize_v3(shi->view);
-
- shi->obi= obi;
- shi->obr= obi->obr;
- shi->vlr= vlr;
- shi->mat= vlr->mat;
- shade_input_init_material(shi);
-
- if (is->isect==2)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- shi->u= is->u;
- shi->v= is->v;
- shi->dx_u= shi->dx_v= shi->dy_u= shi->dy_v= 0.0f;
-
- if (shi->osatex)
- shade_ray_set_derivative(shi);
- shade_input_set_normals(shi);
-
- shade_input_set_shade_texco(shi);
- if (shi->mat->material_type == MA_TYPE_VOLUME) {
- if (ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) {
- shade_volume_shadow(shi, shr, is);
- }
- else {
- shade_volume_outside(shi, shr);
- }
- }
- else if (is->mode==RE_RAY_SHADOW_TRA) {
- /* temp hack to prevent recursion */
- if (shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
- }
- else
- shade_color(shi, shr);
- }
- else {
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
- }
- else {
- shade_material_loop(shi, shr);
- }
-
- /* raytrace likes to separate the spec color */
- sub_v3_v3v3(shr->diff, shr->combined, shr->spec);
- copy_v3_v3(shr->diffshad, shr->diff);
- }
-
-}
-
-static int refraction(float refract[3], const float n[3], const float view[3], float index)
-{
- float dot, fac;
-
- copy_v3_v3(refract, view);
-
- dot = dot_v3v3(view, n);
-
- if (dot>0.0f) {
- index = 1.0f/index;
- fac= 1.0f - (1.0f - dot*dot)*index*index;
- if (fac <= 0.0f) return 0;
- fac= -dot*index + sqrtf(fac);
- }
- else {
- fac= 1.0f - (1.0f - dot*dot)*index*index;
- if (fac <= 0.0f) return 0;
- fac= -dot*index - sqrtf(fac);
- }
-
- refract[0]= index*view[0] + fac*n[0];
- refract[1]= index*view[1] + fac*n[1];
- refract[2]= index*view[2] + fac*n[2];
-
- return 1;
-}
-
-static void reflection_simple(float ref[3], float n[3], const float view[3])
-{
- const float f1= -2.0f * dot_v3v3(n, view);
- madd_v3_v3v3fl(ref, view, n, f1);
-}
-
-/* orn = original face normal */
-static void reflection(float ref[3], float n[3], const float view[3], const float orn[3])
-{
- float f1;
-
- reflection_simple(ref, n, view);
-
- /* test phong normals, then we should prevent vector going to the back */
- f1= dot_v3v3(ref, orn);
- if (f1>0.0f) {
- f1+= 0.01f;
- ref[0]-= f1*orn[0];
- ref[1]-= f1*orn[1];
- ref[2]-= f1*orn[2];
- }
-}
-
-#if 0
-static void color_combine(float *result, float fac1, float fac2, float col1[3], float col2[3])
-{
- float col1t[3], col2t[3];
-
- col1t[0]= sqrt(col1[0]);
- col1t[1]= sqrt(col1[1]);
- col1t[2]= sqrt(col1[2]);
- col2t[0]= sqrt(col2[0]);
- col2t[1]= sqrt(col2[1]);
- col2t[2]= sqrt(col2[2]);
-
- result[0]= (fac1*col1t[0] + fac2*col2t[0]);
- result[0]*= result[0];
- result[1]= (fac1*col1t[1] + fac2*col2t[1]);
- result[1]*= result[1];
- result[2]= (fac1*col1t[2] + fac2*col2t[2]);
- result[2]*= result[2];
-}
-#endif
-
-static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
-{
- float d;
- if (0 == (shi->mat->mode & MA_TRANSP))
- return -1;
-
- if (shi->mat->tx_limit <= 0.0f) {
- d= 1.0f;
- }
- else {
- float p;
-
- /* shi.co[] calculated by shade_ray() */
- const float dx= shi->co[0] - is->start[0];
- const float dy= shi->co[1] - is->start[1];
- const float dz= shi->co[2] - is->start[2];
- d = sqrtf(dx * dx + dy * dy + dz * dz);
- if (d > shi->mat->tx_limit)
- d= shi->mat->tx_limit;
-
- p = shi->mat->tx_falloff;
- if (p < 0.0f) p= 0.0f;
- else if (p > 10.0f) p= 10.0f;
-
- shr->alpha *= powf(d, p);
- if (shr->alpha > 1.0f)
- shr->alpha= 1.0f;
- }
-
- return d;
-}
-
-static void ray_fadeout_endcolor(float col[3], ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, const float vec[3])
-{
- /* un-intersected rays get either rendered material color or sky color */
- if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) {
- copy_v3_v3(col, shr->combined);
- }
- else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) {
- copy_v3_v3(shi->view, vec);
- normalize_v3(shi->view);
-
- shadeSkyView(col, isec->start, shi->view, NULL, shi->thread);
- shadeSunView(col, shi->view);
- }
-}
-
-static void ray_fadeout(Isect *is, ShadeInput *shi, float col[3], const float blendcol[3], float dist_mir)
-{
- /* if fading out, linear blend against fade color */
- float blendfac;
-
- blendfac = 1.0f - len_v3v3(shi->co, is->start)/dist_mir;
-
- col[0] = col[0]*blendfac + (1.0f - blendfac)*blendcol[0];
- col[1] = col[1]*blendfac + (1.0f - blendfac)*blendcol[1];
- col[2] = col[2]*blendfac + (1.0f - blendfac)*blendcol[2];
-}
-
-/* the main recursive tracer itself
- * note: 'col' must be initialized */
-static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, const float start[3], const float dir[3], float col[4], ObjectInstanceRen *obi, VlakRen *vlr, int traflag)
-{
- ShadeInput shi = {NULL};
- Isect isec;
- float dist_mir = origshi->mat->dist_mir;
-
- /* with high depth the number of rays can explode due to the path splitting
- * in two each time, giving 2^depth rays. we need to be able to cancel such
- * a render to avoid hanging, a better solution would be random picking
- * between directions and russian roulette termination */
- if (R.test_break(R.tbh)) {
- zero_v4(col);
- return;
- }
-
- copy_v3_v3(isec.start, start);
- copy_v3_v3(isec.dir, dir);
- isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
- isec.mode= RE_RAY_MIRROR;
- isec.check = RE_CHECK_VLR_RENDER;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.orig.ob = obi;
- isec.orig.face = vlr;
- RE_RC_INIT(isec, shi);
-
- /* database is in original view, obi->imat transforms current position back to original */
- RE_instance_rotate_ray(origshi->obi, &isec);
-
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- ShadeResult shr= {{0}};
- float d= 1.0f;
-
- RE_instance_rotate_ray_restore(origshi->obi, &isec);
-
- /* for as long we don't have proper dx/dy transform for rays we copy over original */
- copy_v3_v3(shi.dxco, origshi->dxco);
- copy_v3_v3(shi.dyco, origshi->dyco);
-
- shi.mask= origshi->mask;
- shi.osatex= origshi->osatex;
- shi.depth= origshi->depth + 1; /* only used to indicate tracing */
- shi.thread= origshi->thread;
- //shi.sample= 0; // memset above, so don't need this
- shi.xs= origshi->xs;
- shi.ys= origshi->ys;
- shi.do_manage= origshi->do_manage;
- shi.lay= origshi->lay;
- shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
- shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
- //shi.do_preview = false; // memset above, so don't need this
-
- shade_ray(&isec, &shi, &shr);
- /* ray has traveled inside the material, so shade by transmission */
- if (traflag & RAY_INSIDE)
- d= shade_by_transmission(&isec, &shi, &shr);
-
- if (depth>0) {
- float fr, fg, fb, f1;
-
- if ((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f && (shi.mat->mode_l & (MA_ZTRANSP | MA_RAYTRANSP))) {
- float nf, f, refract[3], tracol[4];
-
- tracol[0]= shi.r;
- tracol[1]= shi.g;
- tracol[2]= shi.b;
- tracol[3]= col[3]; /* we pass on and accumulate alpha */
-
- if ((shi.mat->mode & MA_TRANSP) && (shi.mat->mode & MA_RAYTRANSP)) {
- /* don't overwrite traflag, it's value is used in mirror reflection */
- int new_traflag = traflag;
-
- if (new_traflag & RAY_INSIDE) {
- /* inside the material, so use inverse normal */
- float norm[3];
- norm[0]= - shi.vn[0];
- norm[1]= - shi.vn[1];
- norm[2]= - shi.vn[2];
-
- if (refraction(refract, norm, shi.view, shi.ang)) {
- /* ray comes out from the material into air */
- new_traflag &= ~RAY_INSIDE;
- }
- else {
- /* total internal reflection (ray stays inside the material) */
- reflection(refract, norm, shi.view, shi.vn);
- }
- }
- else {
- if (refraction(refract, shi.vn, shi.view, shi.ang)) {
- /* ray goes in to the material from air */
- new_traflag |= RAY_INSIDE;
- }
- else {
- /* total external reflection (ray doesn't enter the material) */
- reflection(refract, shi.vn, shi.view, shi.vn);
- }
- }
- traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, new_traflag);
- }
- else
- traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
-
- f= shr.alpha; f1= 1.0f-f;
- nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f;
- fr= 1.0f+ nf*(shi.r-1.0f);
- fg= 1.0f+ nf*(shi.g-1.0f);
- fb= 1.0f+ nf*(shi.b-1.0f);
- shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0];
- shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1];
- shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2];
-
- shr.spec[0] *=f;
- shr.spec[1] *=f;
- shr.spec[2] *=f;
-
- col[3]= f1*tracol[3] + f;
- }
- else {
- col[3]= 1.0f;
- }
-
- float f;
- if (shi.mat->mode_l & MA_RAYMIRROR) {
- f= shi.ray_mirror;
- if (f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir);
- }
- else f= 0.0f;
-
- if (f!=0.0f) {
- float mircol[4];
- float ref[3];
-
- reflection_simple(ref, shi.vn, shi.view);
- traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.obi, shi.vlr, traflag);
-
- f1= 1.0f-f;
-
- /* combine */
- //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff);
- //col[0]+= shr.spec[0];
- //col[1]+= shr.spec[1];
- //col[2]+= shr.spec[2];
-
- fr= shi.mirr;
- fg= shi.mirg;
- fb= shi.mirb;
-
- col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0];
- col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1];
- col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2];
- }
- else {
- col[0]= shr.diff[0] + shr.spec[0];
- col[1]= shr.diff[1] + shr.spec[1];
- col[2]= shr.diff[2] + shr.spec[2];
- }
-
- if (dist_mir > 0.0f) {
- float blendcol[3];
-
- /* max ray distance set, but found an intersection, so fade this color
- * out towards the sky/material color for a smooth transition */
- ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir);
- ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
- }
- }
- else {
- col[0]= shr.diff[0] + shr.spec[0];
- col[1]= shr.diff[1] + shr.spec[1];
- col[2]= shr.diff[2] + shr.spec[2];
- }
-
- }
- else {
- ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir);
- }
- RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
-}
-
-/* **************** jitter blocks ********** */
-
-/* calc distributed planar energy */
-
-static void DP_energy(float *table, float vec[2], int tot, float xsize, float ysize)
-{
- int x, y, a;
- float *fp, force[3], result[3];
- float dx, dy, dist, min;
-
- min= MIN2(xsize, ysize);
- min*= min;
- result[0]= result[1]= 0.0f;
-
- for (y= -1; y<2; y++) {
- dy= ysize*y;
- for (x= -1; x<2; x++) {
- dx= xsize*x;
- fp= table;
- for (a=0; a<tot; a++, fp+= 2) {
- force[0]= vec[0] - fp[0]-dx;
- force[1]= vec[1] - fp[1]-dy;
- dist= force[0]*force[0] + force[1]*force[1];
- if (dist < min && dist>0.0f) {
- result[0]+= force[0]/dist;
- result[1]+= force[1]/dist;
- }
- }
- }
- }
- vec[0] += 0.1f*min*result[0]/(float)tot;
- vec[1] += 0.1f*min*result[1]/(float)tot;
- /* cyclic clamping */
- vec[0]= vec[0] - xsize*floorf(vec[0]/xsize + 0.5f);
- vec[1]= vec[1] - ysize*floorf(vec[1]/ysize + 0.5f);
-}
-
-/* random offset of 1 in 2 */
-static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy)
-{
- float dsizex= sizex*ofsx;
- float dsizey= sizey*ofsy;
- float hsizex= 0.5f*sizex, hsizey= 0.5f*sizey;
- int x;
-
- for (x=tot; x>0; x--, jitter1+=2, jitter2+=2) {
- jitter2[0]= jitter1[0] + dsizex;
- jitter2[1]= jitter1[1] + dsizey;
- if (jitter2[0] > hsizex) jitter2[0]-= sizex;
- if (jitter2[1] > hsizey) jitter2[1]-= sizey;
- }
-}
-
-/* called from convertBlenderScene.c */
-/* we do this in advance to get consistent random, not alter the render seed, and be threadsafe */
-void init_jitter_plane(LampRen *lar)
-{
- float *fp;
- int x, tot= lar->ray_totsamp;
-
- /* test if already initialized */
- if (lar->jitter) return;
-
- /* at least 4, or max threads+1 tables */
- if (BLENDER_MAX_THREADS < 4) x= 4;
- else x= BLENDER_MAX_THREADS+1;
- fp= lar->jitter= MEM_callocN(x*tot*2*sizeof(float), "lamp jitter tab");
-
- /* if 1 sample, we leave table to be zero's */
- if (tot>1) {
- /* set per-lamp fixed seed */
- RNG *rng = BLI_rng_new_srandom(tot);
- int iter=12;
-
- /* fill table with random locations, area_size large */
- for (x=0; x<tot; x++, fp+=2) {
- fp[0]= (BLI_rng_get_float(rng)-0.5f)*lar->area_size;
- fp[1]= (BLI_rng_get_float(rng)-0.5f)*lar->area_sizey;
- }
-
- while (iter--) {
- fp= lar->jitter;
- for (x=tot; x>0; x--, fp+=2) {
- DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
- }
- }
-
- BLI_rng_free(rng);
- }
- /* create the dithered tables (could just check lamp type!) */
- jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f);
- jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f);
- jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f);
-}
-
-/* table around origin, -0.5*size to 0.5*size */
-static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys)
-{
- int tot;
-
- tot= lar->ray_totsamp;
-
- if (lar->ray_samp_type & LA_SAMP_JITTER) {
- /* made it threadsafe */
-
- if (lar->xold[thread]!=xs || lar->yold[thread]!=ys) {
- jitter_plane_offset(lar->jitter, lar->jitter+2*(thread+1)*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(thread), BLI_thread_frand(thread));
- lar->xold[thread]= xs;
- lar->yold[thread]= ys;
- }
- return lar->jitter+2*(thread+1)*tot;
- }
- if (lar->ray_samp_type & LA_SAMP_DITHER) {
- return lar->jitter + 2*tot*((xs & 1)+2*(ys & 1));
- }
-
- return lar->jitter;
-}
-
-
-/* **************** QMC sampling *************** */
-
-static void UNUSED_FUNCTION(halton_sample)(double *ht_invprimes, double *ht_nums, double *v)
-{
- /* incremental halton sequence generator, from:
- * "Instant Radiosity", Keller A. */
- unsigned int i;
-
- for (i = 0; i < 2; i++) {
- double r = fabs((1.0 - ht_nums[i]) - 1e-10);
-
- if (ht_invprimes[i] >= r) {
- double lasth;
- double h = ht_invprimes[i];
-
- do {
- lasth = h;
- h *= ht_invprimes[i];
- } while (h >= r);
-
- ht_nums[i] += ((lasth + h) - 1.0);
- }
- else
- ht_nums[i] += ht_invprimes[i];
-
- v[i] = (float)ht_nums[i];
- }
-}
-
-static struct QMCSampler *QMC_initSampler(int type, int tot)
-{
- QMCSampler *qsa = MEM_callocN(sizeof(QMCSampler), "qmc sampler");
- qsa->samp2d = MEM_callocN(2*sizeof(double)*tot, "qmc sample table");
-
- qsa->tot = tot;
- qsa->type = type;
-
- if (qsa->type==SAMP_TYPE_HAMMERSLEY)
- BLI_hammersley_2D_sequence(qsa->tot, qsa->samp2d);
-
- return qsa;
-}
-
-static void QMC_initPixel(QMCSampler *qsa, int thread)
-{
- if (qsa->type==SAMP_TYPE_HAMMERSLEY) {
- /* hammersley sequence is fixed, already created in QMCSampler init.
- * per pixel, gets a random offset. We create separate offsets per thread, for write-safety */
- qsa->offs[thread][0] = 0.5f * BLI_thread_frand(thread);
- qsa->offs[thread][1] = 0.5f * BLI_thread_frand(thread);
- }
- else { /* SAMP_TYPE_HALTON */
-
- /* generate a new randomized halton sequence per pixel
- * to alleviate qmc artifacts and make it reproducible
- * between threads/frames */
- double ht_offset[2];
- unsigned int ht_primes[2] = {2, 3};
-
- ht_offset[0] = BLI_thread_frand(thread);
- ht_offset[1] = BLI_thread_frand(thread);
-
- BLI_halton_2D_sequence(ht_primes, ht_offset, qsa->tot, qsa->samp2d);
- }
-}
-
-static void QMC_freeSampler(QMCSampler *qsa)
-{
- MEM_freeN(qsa->samp2d);
- MEM_freeN(qsa);
-}
-
-static void QMC_getSample(double *s, QMCSampler *qsa, int thread, int num)
-{
- if (qsa->type == SAMP_TYPE_HAMMERSLEY) {
- s[0] = fmod(qsa->samp2d[2*num+0] + qsa->offs[thread][0], 1.0f);
- s[1] = fmod(qsa->samp2d[2*num+1] + qsa->offs[thread][1], 1.0f);
- }
- else { /* SAMP_TYPE_HALTON */
- s[0] = qsa->samp2d[2*num+0];
- s[1] = qsa->samp2d[2*num+1];
- }
-}
-
-/* phong weighted disc using 'blur' for exponent, centred on 0,0 */
-static void QMC_samplePhong(float vec[3], QMCSampler *qsa, int thread, int num, float blur)
-{
- double s[2];
- float phi, pz, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2*M_PI;
- pz = pow(s[1], blur);
- sqr = sqrtf(1.0f - pz * pz);
-
- vec[0] = (float)(cosf(phi)*sqr);
- vec[1] = (float)(sinf(phi)*sqr);
- vec[2] = 0.0f;
-}
-
-/* rect of edge lengths sizex, sizey, centred on 0.0,0.0 i.e. ranging from -sizex/2 to +sizey/2 */
-static void QMC_sampleRect(float vec[3], QMCSampler *qsa, int thread, int num, float sizex, float sizey)
-{
- double s[2];
-
- QMC_getSample(s, qsa, thread, num);
-
- vec[0] = (float)(s[0] - 0.5) * sizex;
- vec[1] = (float)(s[1] - 0.5) * sizey;
- vec[2] = 0.0f;
-}
-
-/* disc of radius 'radius', centred on 0,0 */
-static void QMC_sampleDisc(float vec[3], QMCSampler *qsa, int thread, int num, float radius)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2*M_PI;
- sqr = sqrt(s[1]);
-
- vec[0] = cosf(phi)*sqr* radius/2.0f;
- vec[1] = sinf(phi)*sqr* radius/2.0f;
- vec[2] = 0.0f;
-}
-
-/* uniform hemisphere sampling */
-static void QMC_sampleHemi(float vec[3], QMCSampler *qsa, int thread, int num)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2.0*M_PI;
- sqr = sqrt(s[1]);
-
- vec[0] = cosf(phi)*sqr;
- vec[1] = sinf(phi)*sqr;
- vec[2] = (float)(1.0 - s[1]*s[1]);
-}
-
-#if 0 /* currently not used */
-/* cosine weighted hemisphere sampling */
-static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int num)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2.f*M_PI;
- sqr = s[1]*sqrt(2-s[1]*s[1]);
-
- vec[0] = cos(phi)*sqr;
- vec[1] = sin(phi)*sqr;
- vec[2] = 1.f - s[1]*s[1];
-
-}
-#endif
-
-/* called from convertBlenderScene.c */
-void init_render_qmcsampler(Render *re)
-{
- const int num_threads = re->r.threads;
- re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase");
- re->num_qmc_samplers = num_threads;
-}
-
-static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
-{
- QMCSampler *qsa;
-
- /* create qmc samplers as needed, since recursion makes it hard to
- * predict how many are needed */
-
- for (qsa=re->qmcsamplers[thread].first; qsa; qsa=qsa->next) {
- if (qsa->type == type && qsa->tot == tot && !qsa->used) {
- qsa->used = true;
- return qsa;
- }
- }
-
- qsa= QMC_initSampler(type, tot);
- qsa->used = true;
- BLI_addtail(&re->qmcsamplers[thread], qsa);
-
- return qsa;
-}
-
-static void release_thread_qmcsampler(Render *UNUSED(re), int UNUSED(thread), QMCSampler *qsa)
-{
- qsa->used= 0;
-}
-
-void free_render_qmcsampler(Render *re)
-{
- if (re->qmcsamplers) {
- QMCSampler *qsa, *next;
- int a;
- for (a = 0; a < re->num_qmc_samplers; a++) {
- for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) {
- next= qsa->next;
- QMC_freeSampler(qsa);
- }
-
- re->qmcsamplers[a].first= re->qmcsamplers[a].last= NULL;
- }
-
- MEM_freeN(re->qmcsamplers);
- re->qmcsamplers= NULL;
- }
-}
-
-static int adaptive_sample_variance(int samples, const float col[3], const float colsq[3], float thresh)
-{
- float var[3], mean[3];
-
- /* scale threshold just to give a bit more precision in input rather than dealing with
- * tiny tiny numbers in the UI */
- thresh /= 2;
-
- mean[0] = col[0] / (float)samples;
- mean[1] = col[1] / (float)samples;
- mean[2] = col[2] / (float)samples;
-
- var[0] = (colsq[0] / (float)samples) - (mean[0]*mean[0]);
- var[1] = (colsq[1] / (float)samples) - (mean[1]*mean[1]);
- var[2] = (colsq[2] / (float)samples) - (mean[2]*mean[2]);
-
- if ((var[0] * 0.4f < thresh) && (var[1] * 0.3f < thresh) && (var[2] * 0.6f < thresh))
- return 1;
- else
- return 0;
-}
-
-static int adaptive_sample_contrast_val(int samples, float prev, float val, float thresh)
-{
- /* if the last sample's contribution to the total value was below a small threshold
- * (i.e. the samples taken are very similar), then taking more samples that are probably
- * going to be the same is wasting effort */
- if (fabsf(prev / (float)(samples - 1) - val / (float)samples ) < thresh) {
- return 1;
- }
- else
- return 0;
-}
-
-static float get_avg_speed(ShadeInput *shi)
-{
- float pre_x, pre_y, post_x, post_y, speedavg;
-
- pre_x = (shi->winspeed[0] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[0];
- pre_y = (shi->winspeed[1] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[1];
- post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2];
- post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3];
-
- speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0f;
-
- return speedavg;
-}
-
-/* ***************** main calls ************** */
-
-
-static void trace_refract(float col[4], ShadeInput *shi, ShadeResult *shr)
-{
- QMCSampler *qsa=NULL;
- int samp_type;
- int traflag=0;
-
- float samp3d[3], orthx[3], orthy[3];
- float v_refract[3], v_refract_new[3];
- float sampcol[4], colsq[4];
-
- float blur = pow3f(1.0f - shi->mat->gloss_tra);
- short max_samples = shi->mat->samp_gloss_tra;
- float adapt_thresh = shi->mat->adapt_thresh_tra;
-
- int samples=0;
-
- colsq[0] = colsq[1] = colsq[2] = 0.0;
- col[0] = col[1] = col[2] = 0.0;
- col[3]= shr->alpha;
-
- if (blur > 0.0f) {
- if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
- else samp_type = SAMP_TYPE_HAMMERSLEY;
-
- /* all samples are generated per pixel */
- qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
- QMC_initPixel(qsa, shi->thread);
- }
- else
- max_samples = 1;
-
-
- while (samples < max_samples) {
- if (refraction(v_refract, shi->vn, shi->view, shi->ang)) {
- traflag |= RAY_INSIDE;
- }
- else {
- /* total external reflection can happen for materials with IOR < 1.0 */
- if ((shi->vlr->flag & R_SMOOTH))
- reflection(v_refract, shi->vn, shi->view, shi->facenor);
- else
- reflection_simple(v_refract, shi->vn, shi->view);
-
- /* can't blur total external reflection */
- max_samples = 1;
- }
-
- if (max_samples > 1) {
- /* get a quasi-random vector from a phong-weighted disc */
- QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
-
- ortho_basis_v3v3_v3(orthx, orthy, v_refract);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]);
-
- /* and perturb the refraction vector in it */
- add_v3_v3v3(v_refract_new, v_refract, orthx);
- add_v3_v3(v_refract_new, orthy);
-
- normalize_v3(v_refract_new);
- }
- else {
- /* no blurriness, use the original normal */
- copy_v3_v3(v_refract_new, v_refract);
- }
-
- sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
-
- traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, traflag);
-
- col[0] += sampcol[0];
- col[1] += sampcol[1];
- col[2] += sampcol[2];
- col[3] += sampcol[3];
-
- /* for variance calc */
- colsq[0] += sampcol[0]*sampcol[0];
- colsq[1] += sampcol[1]*sampcol[1];
- colsq[2] += sampcol[2]*sampcol[2];
-
- samples++;
-
- /* adaptive sampling */
- if (adapt_thresh < 1.0f && samples > max_samples/2) {
- if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
- break;
-
- /* if the pixel so far is very dark, we can get away with less samples */
- if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
- max_samples--;
- }
- }
-
- col[0] /= (float)samples;
- col[1] /= (float)samples;
- col[2] /= (float)samples;
- col[3] /= (float)samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-static void trace_reflect(float col[3], ShadeInput *shi, ShadeResult *shr, float fresnelfac)
-{
- QMCSampler *qsa=NULL;
- int samp_type;
-
- float samp3d[3], orthx[3], orthy[3];
- float v_nor_new[3], v_reflect[3];
- float sampcol[4], colsq[4];
-
- float blur = pow3f(1.0f - shi->mat->gloss_mir);
- short max_samples = shi->mat->samp_gloss_mir;
- float adapt_thresh = shi->mat->adapt_thresh_mir;
- float aniso = 1.0f - shi->mat->aniso_gloss_mir;
-
- int samples=0;
-
- col[0] = col[1] = col[2] = 0.0;
- colsq[0] = colsq[1] = colsq[2] = 0.0;
-
- if (blur > 0.0f) {
- if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
- else samp_type = SAMP_TYPE_HAMMERSLEY;
-
- /* all samples are generated per pixel */
- qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
- QMC_initPixel(qsa, shi->thread);
- }
- else
- max_samples = 1;
-
- while (samples < max_samples) {
-
- if (max_samples > 1) {
- /* get a quasi-random vector from a phong-weighted disc */
- QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
-
- /* find the normal's perpendicular plane, blurring along tangents
- * if tangent shading enabled */
- if (shi->mat->mode & (MA_TANGENT_V)) {
- cross_v3_v3v3(orthx, shi->vn, shi->tang); // bitangent
- copy_v3_v3(orthy, shi->tang);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]*aniso);
- }
- else {
- ortho_basis_v3v3_v3(orthx, orthy, shi->vn);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]);
- }
-
- /* and perturb the normal in it */
- add_v3_v3v3(v_nor_new, shi->vn, orthx);
- add_v3_v3(v_nor_new, orthy);
- normalize_v3(v_nor_new);
- }
- else {
- /* no blurriness, use the original normal */
- copy_v3_v3(v_nor_new, shi->vn);
- }
-
- if ((shi->vlr->flag & R_SMOOTH))
- reflection(v_reflect, v_nor_new, shi->view, shi->facenor);
- else
- reflection_simple(v_reflect, v_nor_new, shi->view);
-
- sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
-
- traceray(shi, shr, shi->mat->ray_depth, shi->co, v_reflect, sampcol, shi->obi, shi->vlr, 0);
-
-
- col[0] += sampcol[0];
- col[1] += sampcol[1];
- col[2] += sampcol[2];
-
- /* for variance calc */
- colsq[0] += sampcol[0]*sampcol[0];
- colsq[1] += sampcol[1]*sampcol[1];
- colsq[2] += sampcol[2]*sampcol[2];
-
- samples++;
-
- /* adaptive sampling */
- if (adapt_thresh > 0.0f && samples > max_samples/3) {
- if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
- break;
-
- /* if the pixel so far is very dark, we can get away with less samples */
- if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
- max_samples--;
-
- /* reduce samples when reflection is dim due to low ray mirror blend value or fresnel factor
- * and when reflection is blurry */
- if (fresnelfac < 0.1f * (blur+1)) {
- max_samples--;
-
- /* even more for very dim */
- if (fresnelfac < 0.05f * (blur+1))
- max_samples--;
- }
- }
- }
-
- col[0] /= (float)samples;
- col[1] /= (float)samples;
- col[2] /= (float)samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-/* extern call from render loop */
-void ray_trace(ShadeInput *shi, ShadeResult *shr)
-{
- float f1, fr, fg, fb;
- float mircol[4], tracol[4];
- float diff[3];
- int do_tra, do_mir;
-
- do_tra = ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f && (shi->depth <= shi->mat->ray_depth_tra));
- do_mir = ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror != 0.0f && (shi->depth <= shi->mat->ray_depth));
-
- /* raytrace mirror and refract like to separate the spec color */
- if (shi->combinedflag & SCE_PASS_SPEC)
- sub_v3_v3v3(diff, shr->combined, shr->spec);
- else
- copy_v3_v3(diff, shr->combined);
-
- if (do_tra) {
- float olddiff[3], f;
-
- trace_refract(tracol, shi, shr);
-
- f= shr->alpha; f1= 1.0f-f;
- fr= 1.0f+ shi->mat->filter*(shi->r-1.0f);
- fg= 1.0f+ shi->mat->filter*(shi->g-1.0f);
- fb= 1.0f+ shi->mat->filter*(shi->b-1.0f);
-
- /* for refract pass */
- copy_v3_v3(olddiff, diff);
-
- diff[0]= f*diff[0] + f1*fr*tracol[0];
- diff[1]= f*diff[1] + f1*fg*tracol[1];
- diff[2]= f*diff[2] + f1*fb*tracol[2];
-
- if (shi->passflag & SCE_PASS_REFRACT)
- sub_v3_v3v3(shr->refr, diff, olddiff);
-
- if (!(shi->combinedflag & SCE_PASS_REFRACT))
- sub_v3_v3v3(diff, diff, shr->refr);
-
- shr->alpha = min_ff(1.0f, tracol[3]);
- }
-
- if (do_mir) {
- const float i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir);
- if (i!=0.0f) {
-
- trace_reflect(mircol, shi, shr, i);
-
- fr= i*shi->mirr;
- fg= i*shi->mirg;
- fb= i*shi->mirb;
-
- if (shi->passflag & SCE_PASS_REFLECT) {
- /* mirror pass is not blocked out with spec */
- shr->refl[0]= fr*mircol[0] - fr*diff[0];
- shr->refl[1]= fg*mircol[1] - fg*diff[1];
- shr->refl[2]= fb*mircol[2] - fb*diff[2];
- }
-
- if (shi->combinedflag & SCE_PASS_REFLECT) {
- /* values in shr->spec can be greater than 1.0.
- * In this case the mircol uses a zero blending factor, so ignoring it is ok.
- * Fixes bug #18837 - when the spec is higher then 1.0,
- * diff can become a negative color - Campbell */
-
- f1= 1.0f-i;
-
- diff[0] *= f1;
- diff[1] *= f1;
- diff[2] *= f1;
-
- if (shr->spec[0]<1.0f) diff[0] += mircol[0] * (fr*(1.0f-shr->spec[0]));
- if (shr->spec[1]<1.0f) diff[1] += mircol[1] * (fg*(1.0f-shr->spec[1]));
- if (shr->spec[2]<1.0f) diff[2] += mircol[2] * (fb*(1.0f-shr->spec[2]));
- }
- }
- }
- /* put back together */
- if (shi->combinedflag & SCE_PASS_SPEC)
- add_v3_v3v3(shr->combined, diff, shr->spec);
- else
- copy_v3_v3(shr->combined, diff);
-}
-
-/* color 'shadfac' passes through 'col' with alpha and filter */
-/* filter is only applied on alpha defined transparent part */
-static void addAlphaLight(float shadfac[4], const float col[3], float alpha, float filter)
-{
- float fr, fg, fb;
-
- fr= 1.0f+ filter*(col[0]-1.0f);
- fg= 1.0f+ filter*(col[1]-1.0f);
- fb= 1.0f+ filter*(col[2]-1.0f);
-
- shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0];
- shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1];
- shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2];
-
- shadfac[3]= (1.0f-alpha)*shadfac[3];
-}
-
-static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4])
-{
- /* ray to lamp, find first face that intersects, check alpha properties,
- * if it has col[3]>0.0f continue. so exit when alpha is full */
- const float initial_dist = is->dist;
-
- if (RE_rayobject_raycast(R.raytree, is)) {
- /* Warning regarding initializing to zero's, This is not that nice,
- * and possibly a bit slow for every ray, however some variables were
- * not initialized properly in, unless using
- * shade_input_initialize(...), we need to zero them. */
- ShadeInput shi= {NULL};
- /* end warning! - Campbell */
-
- ShadeResult shr;
-
- /* we got a face */
-
- shi.depth= origshi->depth + 1; /* only used to indicate tracing */
- shi.mask= origshi->mask;
- shi.thread= origshi->thread;
- shi.passflag= SCE_PASS_COMBINED;
- shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
-
- shi.xs= origshi->xs;
- shi.ys= origshi->ys;
- shi.do_manage= origshi->do_manage;
- shi.lay= origshi->lay;
- shi.nodes= origshi->nodes;
-
- RE_instance_rotate_ray_restore(origshi->obi, is);
-
- shade_ray(is, &shi, &shr);
- if (shi.mat->material_type == MA_TYPE_SURFACE) {
- const float d = (shi.mat->mode & MA_RAYTRANSP) ?
- ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) :
- 0.0f;
- /* mix colors based on shadfac (rgb + amount of light factor) */
- addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
- }
- else if (shi.mat->material_type == MA_TYPE_VOLUME) {
- const float a = col[3];
-
- col[0] = a*col[0] + shr.alpha*shr.combined[0];
- col[1] = a*col[1] + shr.alpha*shr.combined[1];
- col[2] = a*col[2] + shr.alpha*shr.combined[2];
-
- col[3] = (1.0f - shr.alpha)*a;
- }
-
- if (depth>0 && col[3]>0.0f) {
-
- /* adapt isect struct */
- copy_v3_v3(is->start, shi.co);
- is->dist = initial_dist-is->dist;
- is->orig.ob = shi.obi;
- is->orig.face = shi.vlr;
-
- ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col);
- }
-
- RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
- }
-}
-
-
-/* aolight: function to create random unit sphere vectors for total random sampling */
-
-/* calc distributed spherical energy */
-static void DS_energy(float *sphere, int tot, float vec[3])
-{
- float *fp, fac, force[3], res[3];
- int a;
-
- res[0]= res[1]= res[2]= 0.0f;
-
- for (a=0, fp=sphere; a<tot; a++, fp+=3) {
- sub_v3_v3v3(force, vec, fp);
- fac = dot_v3v3(force, force);
- if (fac!=0.0f) {
- fac= 1.0f/fac;
- res[0]+= fac*force[0];
- res[1]+= fac*force[1];
- res[2]+= fac*force[2];
- }
- }
-
- mul_v3_fl(res, 0.5);
- add_v3_v3(vec, res);
- normalize_v3(vec);
-
-}
-
-/* called from convertBlenderScene.c */
-/* creates an equally distributed spherical sample pattern */
-/* and allocates threadsafe memory */
-void init_ao_sphere(Render *re, World *wrld)
-{
- /* fixed random */
- const int num_threads = re->r.threads;
- RNG *rng;
- float *fp;
- int a, tot, iter= 16;
-
- /* we make twice the amount of samples, because only a hemisphere is used */
- tot= 2*wrld->aosamp*wrld->aosamp;
-
- wrld->aosphere= MEM_mallocN(3*tot*sizeof(float), "AO sphere");
- rng = BLI_rng_new_srandom(tot);
-
- /* init */
- fp= wrld->aosphere;
- for (a=0; a<tot; a++, fp+= 3) {
- BLI_rng_get_float_unit_v3(rng, fp);
- }
-
- while (iter--) {
- for (a=0, fp= wrld->aosphere; a<tot; a++, fp+= 3) {
- DS_energy(wrld->aosphere, tot, fp);
- }
- }
-
- /* tables */
- wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables");
-
- BLI_rng_free(rng);
-}
-
-/* give per thread a table, we have to compare xs ys because of way OSA works... */
-static float *threadsafe_table_sphere(int test, int thread, int xs, int ys, int tot)
-{
- static int xso[BLENDER_MAX_THREADS], yso[BLENDER_MAX_THREADS];
- static int firsttime= 1;
-
- if (firsttime) {
- memset(xso, 255, sizeof(xso));
- memset(yso, 255, sizeof(yso));
- firsttime= 0;
- }
-
- if (xs==xso[thread] && ys==yso[thread]) return R.wrld.aotables+ thread*tot*3;
- if (test) return NULL;
- xso[thread]= xs; yso[thread]= ys;
- return R.wrld.aotables+ thread*tot*3;
-}
-
-static float *sphere_sampler(int type, int resol, int thread, int xs, int ys, int reset)
-{
- int tot;
- float *vec;
-
- tot= 2*resol*resol;
-
- if (type & WO_AORNDSMP) {
- /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
- RNG *rng = BLI_rng_new(BLI_thread_rand(thread));
- float *sphere;
- int a;
-
- /* always returns table */
- sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
-
- vec= sphere;
- for (a=0; a<tot; a++, vec+=3) {
- BLI_rng_get_float_unit_v3(rng, vec);
- }
-
- BLI_rng_free(rng);
-
- return sphere;
- }
- else {
- float *sphere;
- float *vec1;
-
- /* returns table if xs and ys were equal to last call, and not resetting */
- sphere= (reset)? NULL: threadsafe_table_sphere(1, thread, xs, ys, tot);
- if (sphere==NULL) {
- float cosfi, sinfi, cost, sint;
- float ang;
- int a;
-
- sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
-
- /* random rotation */
- ang = BLI_thread_frand(thread);
- sinfi = sinf(ang); cosfi = cosf(ang);
- ang = BLI_thread_frand(thread);
- sint = sinf(ang); cost = cosf(ang);
-
- vec= R.wrld.aosphere;
- vec1= sphere;
- for (a=0; a<tot; a++, vec+=3, vec1+=3) {
- vec1[0]= cost*cosfi*vec[0] - sinfi*vec[1] + sint*cosfi*vec[2];
- vec1[1]= cost*sinfi*vec[0] + cosfi*vec[1] + sint*sinfi*vec[2];
- vec1[2]= -sint*vec[0] + cost*vec[2];
- }
- }
- return sphere;
- }
-}
-
-static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3])
-{
- Isect isec;
- RayHint point_hint;
- QMCSampler *qsa=NULL;
- float samp3d[3];
- float up[3], side[3], dir[3], nrm[3];
-
- float maxdist = R.wrld.aodist;
- float fac=0.0f, prev=0.0f;
- float adapt_thresh = R.wrld.ao_adapt_thresh;
- float adapt_speed_fac = R.wrld.ao_adapt_speed_fac;
-
- int samples=0;
- int max_samples = R.wrld.aosamp*R.wrld.aosamp;
-
- float dxyview[3], skyadded=0;
- int envcolor;
-
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
-
- isec.last_hit = NULL;
-
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
-
- copy_v3_v3(isec.start, shi->co);
-
- RE_instance_rotate_ray_start(shi->obi, &isec);
-
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
-
- zero_v3(ao);
- zero_v3(env);
-
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
-
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)R.wrld.aosamp;
- dxyview[1]= 1.0f/(float)R.wrld.aosamp;
- dxyview[2]= 0.0f;
- }
-
- if (shi->vlr->flag & R_SMOOTH) {
- copy_v3_v3(nrm, shi->vn);
- }
- else {
- copy_v3_v3(nrm, shi->facenor);
- }
-
- ortho_basis_v3v3_v3(up, side, nrm);
-
- /* sampling init */
- if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) {
- float speedfac;
-
- speedfac = get_avg_speed(shi) * adapt_speed_fac;
- CLAMP(speedfac, 1.0f, 1000.0f);
- max_samples /= speedfac;
- if (max_samples < 5) max_samples = 5;
-
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
- }
- else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-
- QMC_initPixel(qsa, shi->thread);
-
- while (samples < max_samples) {
-
- /* sampling, returns quasi-random vector in unit hemisphere */
- QMC_sampleHemi(samp3d, qsa, shi->thread, samples);
-
- dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
- dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
- dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
-
- normalize_v3(dir);
-
- isec.dir[0] = -dir[0];
- isec.dir[1] = -dir[1];
- isec.dir[2] = -dir[2];
- isec.dist = maxdist;
-
- RE_instance_rotate_ray_dir(shi->obi, &isec);
-
- prev = fac;
-
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) fac+= expf(-isec.dist*R.wrld.aodistfac);
- else fac+= 1.0f;
- }
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -dir[0];
- view[1]= -dir[1];
- view[2]= -dir[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float skyfac= 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
- env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
- env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
-
- samples++;
-
- if (qsa && qsa->type == SAMP_TYPE_HALTON) {
- /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
- if (adapt_thresh > 0.0f && (samples > max_samples/2) ) {
-
- if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) {
- break;
- }
- }
- }
- }
-
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples;
-
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded));
- else
- copy_v3_v3(env, ao);
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-/* extern call from shade_lamp_loop, ambient occlusion calculus */
-static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3])
-{
- Isect isec;
- RayHint point_hint;
- float *vec, *nrm, bias, sh=0.0f;
- float maxdist = R.wrld.aodist;
- float dxyview[3];
- int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp;
-
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_RENDER;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
-
- isec.last_hit = NULL;
-
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
-
- copy_v3_v3(isec.start, shi->co);
- RE_instance_rotate_ray_start(shi->obi, &isec);
-
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
-
- zero_v3(ao);
- zero_v3(env);
-
- /* bias prevents smoothed faces to appear flat */
- if (shi->vlr->flag & R_SMOOTH) {
- bias= R.wrld.aobias;
- nrm= shi->vn;
- }
- else {
- bias= 0.0f;
- nrm= shi->facenor;
- }
-
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
-
- if (resol>32) resol= 32;
-
- /* get sphere samples. for faces we get the same samples for sample x/y values,
- * for strand render we always require a new sampler because x/y are not set */
- vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys, shi->strand != NULL);
-
- /* warning: since we use full sphere now, and dotproduct is below, we do twice as much */
- tot= 2*resol*resol;
-
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)resol;
- dxyview[1]= 1.0f/(float)resol;
- dxyview[2]= 0.0f;
- }
-
- while (tot--) {
-
- if (dot_v3v3(vec, nrm) > bias) {
- /* only ao samples for mask */
- if (R.r.mode & R_OSA) {
- j++;
- if (j==R.osa) j= 0;
- if (!(shi->mask & (1<<j))) {
- vec+=3;
- continue;
- }
- }
-
- actual++;
-
- /* always set start/vec/dist */
- isec.dir[0] = -vec[0];
- isec.dir[1] = -vec[1];
- isec.dir[2] = -vec[2];
- isec.dist = maxdist;
-
- RE_instance_rotate_ray_dir(shi->obi, &isec);
-
- /* do the trace */
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac);
- else sh+= 1.0f;
- }
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -vec[0];
- view[1]= -vec[1];
- view[2]= -vec[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float fac = 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr;
- env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng;
- env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
- }
- /* samples */
- vec+= 3;
- }
-
- if (actual==0) sh= 1.0f;
- else sh = 1.0f - sh/((float)actual);
-
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= sh;
-
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, sh/((float)skyadded));
- else
- copy_v3_v3(env, ao);
-}
-
-void ray_ao(ShadeInput *shi, float ao[3], float env[3])
-{
- /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many
- * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult
- * to reuse code between these two functions. This is the easiest way I can think of to do it
- * --broken */
- if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON))
- ray_ao_qmc(shi, ao, env);
- else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- ray_ao_spheresamp(shi, ao, env);
-}
-
-static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco)
-{
- /* magic numbers for reordering sample positions to give better
- * results with adaptive sample, when it usually only takes 4 samples */
- int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7};
- int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9};
- int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15};
- int count = count_mask(shi->mask);
-
- /* for better antialising shadow samples are distributed over the subpixel
- * sample coordinates, this only works for raytracing depth 0 though */
- if (!shi->strand && shi->depth == 0 && count > 1 && count <= max) {
- float xs, ys, zs, view[3];
- int samp, ordsamp, tot= 0;
-
- for (samp=0; samp<R.osa; samp++) {
- if (R.osa == 8) ordsamp = order8[samp];
- else if (R.osa == 11) ordsamp = order11[samp];
- else if (R.osa == 16) ordsamp = order16[samp];
- else ordsamp = samp;
-
- if (shi->mask & (1<<ordsamp)) {
- /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
- xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f;
- ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f;
- zs= shi->scanco[2];
-
- shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL);
- tot++;
- }
- }
-
- *totjitco= tot;
- }
- else {
- copy_v3_v3(jitco[0], shi->co);
- *totjitco= 1;
- }
-}
-
-static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
-{
- QMCSampler *qsa=NULL;
- int samples=0;
- float samp3d[3];
-
- float fac=0.0f, vec[3], end[3];
- float colsq[4];
- float adapt_thresh = lar->adapt_thresh;
- int min_adapt_samples=4, max_samples = lar->ray_totsamp;
- float start[3];
- bool do_soft = true, full_osa = false;
- int i;
-
- float min[3], max[3];
- RayHint bb_hint;
-
- float jitco[RE_MAX_OSA][3];
- int totjitco;
-
- colsq[0] = colsq[1] = colsq[2] = 0.0;
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
- }
- else
- shadfac[3]= 1.0f;
-
- if (lar->ray_totsamp < 2) do_soft = false;
- if ((R.r.mode & R_OSA) && (R.osa > 0) && (shi->vlr->flag & R_FULL_OSA)) full_osa = true;
-
- if (full_osa) {
- if (do_soft) max_samples = max_samples/R.osa + 1;
- else max_samples = 1;
- }
- else {
- if (do_soft) max_samples = lar->ray_totsamp;
- else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5;
- else max_samples = 1;
- }
-
- ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco);
-
- /* sampling init */
- if (lar->ray_samp_method==LA_SAMP_HALTON)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
- else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-
- QMC_initPixel(qsa, shi->thread);
-
- INIT_MINMAX(min, max);
- for (i = 0; i < totjitco; i++) {
- minmax_v3v3_v3(min, max, jitco[i]);
- }
- if (shi->obi->flag & R_ENV_TRANSFORMED) {
- mul_m4_v3(shi->obi->imat, min);
- mul_m4_v3(shi->obi->imat, max);
- }
- RE_rayobject_hint_bb(R.raytree, &bb_hint, min, max);
-
- isec->hint = &bb_hint;
- isec->check = RE_CHECK_VLR_RENDER;
- isec->skip = RE_SKIP_VLR_NEIGHBOUR;
- copy_v3_v3(vec, lampco);
-
- while (samples < max_samples) {
-
- isec->orig.ob = shi->obi;
- isec->orig.face = shi->vlr;
-
- /* manually jitter the start shading co-ord per sample
- * based on the pre-generated OSA texture sampling offsets,
- * for anti-aliasing sharp shadow edges. */
- copy_v3_v3(start, jitco[samples % totjitco]);
-
- if (do_soft) {
- /* sphere shadow source */
- if (lar->type == LA_LOCAL) {
- float ru[3], rv[3], v[3], s[3];
-
- /* calc tangent plane vectors */
- sub_v3_v3v3(v, start, lampco);
- normalize_v3(v);
- ortho_basis_v3v3_v3(ru, rv, v);
-
- /* sampling, returns quasi-random vector in area_size disc */
- QMC_sampleDisc(samp3d, qsa, shi->thread, samples, lar->area_size);
-
- /* distribute disc samples across the tangent plane */
- s[0] = samp3d[0]*ru[0] + samp3d[1]*rv[0];
- s[1] = samp3d[0]*ru[1] + samp3d[1]*rv[1];
- s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2];
-
- copy_v3_v3(samp3d, s);
- }
- else {
- /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */
- QMC_sampleRect(samp3d, qsa, shi->thread, samples, lar->area_size, lar->area_sizey);
-
- /* align samples to lamp vector */
- mul_m3_v3(lar->mat, samp3d);
- }
- end[0] = vec[0]+samp3d[0];
- end[1] = vec[1]+samp3d[1];
- end[2] = vec[2]+samp3d[2];
- }
- else {
- copy_v3_v3(end, vec);
- }
-
- if (shi->strand) {
- /* bias away somewhat to avoid self intersection */
- float jitbias= 0.5f*(len_v3(shi->dxco) + len_v3(shi->dyco));
- float v[3];
-
- sub_v3_v3v3(v, start, end);
- normalize_v3(v);
-
- start[0] -= jitbias*v[0];
- start[1] -= jitbias*v[1];
- start[2] -= jitbias*v[2];
- }
-
- copy_v3_v3(isec->start, start);
- sub_v3_v3v3(isec->dir, end, start);
- isec->dist = normalize_v3(isec->dir);
-
- RE_instance_rotate_ray(shi->obi, isec);
-
- /* trace the ray */
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
- shadfac[0] += col[0];
- shadfac[1] += col[1];
- shadfac[2] += col[2];
- shadfac[3] += col[3];
-
- /* for variance calc */
- colsq[0] += col[0]*col[0];
- colsq[1] += col[1]*col[1];
- colsq[2] += col[2]*col[2];
- }
- else {
- if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
- }
-
- samples++;
-
- if (lar->ray_samp_method == LA_SAMP_HALTON) {
-
- /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
- if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0f) && (samples > max_samples / 3)) {
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- if ((shadfac[3] / samples > (1.0f-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
- break;
- else if (adaptive_sample_variance(samples, shadfac, colsq, adapt_thresh))
- break;
- }
- else {
- if ((fac / samples > (1.0f-adapt_thresh)) || (fac / samples < adapt_thresh))
- break;
- }
- }
- }
- }
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0] /= samples;
- shadfac[1] /= samples;
- shadfac[2] /= samples;
- shadfac[3] /= samples;
- }
- else
- shadfac[3]= 1.0f-fac/samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
-{
- /* area soft shadow */
- const float *jitlamp;
- float fac=0.0f, div=0.0f, vec[3];
- int a, j= -1, mask;
- RayHint point_hint;
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
- }
- else shadfac[3]= 1.0f;
-
- fac= 0.0f;
- jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys);
-
- a= lar->ray_totsamp;
-
- /* this correction to make sure we always take at least 1 sample */
- mask= shi->mask;
- if (a==4) mask |= (mask>>4)|(mask>>8);
- else if (a==9) mask |= (mask>>9);
-
- copy_v3_v3(isec->start, shi->co);
- RE_instance_rotate_ray_start(shi->obi, isec);
-
- isec->orig.ob = shi->obi;
- isec->orig.face = shi->vlr;
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, isec->start);
- isec->hint = &point_hint;
-
- while (a--) {
-
- if (R.r.mode & R_OSA) {
- j++;
- if (j>=R.osa) j= 0;
- if (!(mask & (1<<j))) {
- jitlamp+= 2;
- continue;
- }
- }
-
- vec[0]= jitlamp[0];
- vec[1]= jitlamp[1];
- vec[2]= 0.0f;
- mul_m3_v3(lar->mat, vec);
-
- /* set start and vec */
- isec->dir[0] = vec[0]+lampco[0]-shi->co[0];
- isec->dir[1] = vec[1]+lampco[1]-shi->co[1];
- isec->dir[2] = vec[2]+lampco[2]-shi->co[2];
-
- RE_instance_rotate_ray_dir(shi->obi, isec);
-
- isec->dist = 1.0f;
- isec->check = RE_CHECK_VLR_RENDER;
- isec->skip = RE_SKIP_VLR_NEIGHBOUR;
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
- shadfac[0] += col[0];
- shadfac[1] += col[1];
- shadfac[2] += col[2];
- shadfac[3] += col[3];
- }
- else if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
-
- div+= 1.0f;
- jitlamp+= 2;
- }
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0] /= div;
- shadfac[1] /= div;
- shadfac[2] /= div;
- shadfac[3] /= div;
- }
- else {
- /* sqrt makes nice umbra effect */
- if (lar->ray_samp_type & LA_SAMP_UMBRA)
- shadfac[3] = sqrtf(1.0f - fac / div);
- else
- shadfac[3] = 1.0f - fac / div;
- }
-}
-/* extern call from shade_lamp_loop */
-void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4])
-{
- Isect isec;
- float lampco[3];
-
- /* setup isec */
- RE_RC_INIT(isec, *shi);
- if (shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
- else isec.mode= RE_RAY_SHADOW;
- isec.hint = NULL;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
- isec.lay= lar->lay;
- else
- isec.lay= -1;
-
- /* only when not mir tracing, first hit optimm */
- if (shi->depth==0) {
- isec.last_hit = lar->last_hit[shi->thread];
- }
- else {
- isec.last_hit = NULL;
- }
-
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- /* jitter and QMC sampling add a displace vector to the lamp position
- * that's incorrect because a SUN lamp does not has an exact position
- * and the displace should be done at the ray vector instead of the
- * lamp position.
- * This is easily verified by noticing that shadows of SUN lights change
- * with the scene BB.
- *
- * This was detected during SoC 2009 - Raytrace Optimization, but to keep
- * consistency with older render code it wasn't removed.
- *
- * If the render code goes through some recode/serious bug-fix then this
- * is something to consider!
- */
- lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
- lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
- lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];
- }
- else {
- copy_v3_v3(lampco, lar->co);
- }
-
- if (ELEM(lar->ray_samp_method, LA_SAMP_HALTON, LA_SAMP_HAMMERSLEY)) {
-
- ray_shadow_qmc(shi, lar, lampco, shadfac, &isec);
-
- }
- else {
- if (lar->ray_totsamp<2) {
-
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
-
- shadfac[3]= 1.0f; /* 1.0=full light */
-
- /* set up isec.dir */
- copy_v3_v3(isec.start, shi->co);
- sub_v3_v3v3(isec.dir, lampco, isec.start);
- isec.dist = normalize_v3(isec.dir);
-
- RE_instance_rotate_ray(shi->obi, &isec);
-
- if (isec.mode==RE_RAY_SHADOW_TRA) {
- /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col);
- copy_v4_v4(shadfac, col);
- }
- else if (RE_rayobject_raycast(R.raytree, &isec))
- shadfac[3]= 0.0f;
- }
- else {
- ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
- }
- }
-
- /* for first hit optim, set last interesected shadow face */
- if (shi->depth==0) {
- lar->last_hit[shi->thread] = isec.last_hit;
- }
-
-}
-
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 5abef431f3d..ba12eac3efa 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -408,7 +408,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
}
FOREACH_VIEW_LAYER_TO_RENDER_END;
- /* sss, previewrender and envmap don't do layers, so we make a default one */
+ /* previewrender doesn't do layers, so we make a default one */
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
@@ -505,23 +505,6 @@ void render_result_add_pass(RenderResult *rr, const char *name, int channels, co
}
}
-/* allocate osa new results for samples */
-RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
-{
- int a;
-
- if (re->osa == 0)
- return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
-
- for (a = 0; a < re->osa; a++) {
- RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
- BLI_addtail(lb, rr);
- rr->sample_nr = a;
- }
-
- return lb->first;
-}
-
static int passtype_from_name(const char *name)
{
const char delim[] = {'.', '\0'};
@@ -1090,8 +1073,8 @@ void render_result_save_empty_result_tiles(Render *re)
for (rl = rr->layers.first; rl; rl = rl->next) {
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status != PART_STATUS_MERGED) {
- int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
- int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
+ int party = pa->disprect.ymin - re->disprect.ymin;
+ int partx = pa->disprect.xmin - re->disprect.xmin;
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname, true);
}
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 929fc3cc9c3..79d13ecab5b 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -65,23 +65,11 @@
#include "MEM_guardedalloc.h"
-#include "envmap.h"
-#include "pointdensity.h"
-#include "voxeldata.h"
#include "render_types.h"
-#include "shading.h"
#include "texture.h"
-#include "texture_ocean.h"
-
-#include "renderdatabase.h" /* needed for UV */
#include "RE_render_ext.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "RE_shader_ext.h"
static RNG_THREAD_ARRAY *random_tex_array;
@@ -97,63 +85,6 @@ void RE_texture_rng_exit(void)
}
-static void init_render_texture(Render *re, Tex *tex)
-{
- /* imap test */
- if (tex->ima && BKE_image_is_animated(tex->ima)) {
- BKE_image_user_frame_calc(&tex->iuser, re ? re->r.cfra : 0, re ? re->flag & R_SEC_FIELD:0);
- }
-
- else if (tex->type==TEX_ENVMAP) {
- /* just in case */
- tex->imaflag |= TEX_INTERPOL | TEX_MIPMAP;
- tex->extend= TEX_CLIP;
-
- if (tex->env) {
- if (tex->env->type==ENV_PLANE)
- tex->extend= TEX_EXTEND;
-
- /* only free envmap when rendermode was set to render envmaps, for previewrender */
- if (G.is_rendering && re) {
- if (re->r.mode & R_ENVMAP)
- if (tex->env->stype==ENV_ANIM)
- BKE_texture_envmap_free_data(tex->env);
- }
- }
- }
-
- if (tex->nodetree && tex->use_nodes) {
- ntreeTexBeginExecTree(tex->nodetree); /* has internal flag to detect it only does it once */
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void init_render_textures(Render *re)
-{
- Tex *tex;
-
- tex= re->main->tex.first;
- while (tex) {
- if (tex->id.us) init_render_texture(re, tex);
- tex= tex->id.next;
- }
-}
-
-static void end_render_texture(Tex *tex)
-{
- if (tex && tex->use_nodes && tex->nodetree && tex->nodetree->execdata)
- ntreeTexEndExecTree(tex->nodetree->execdata);
-}
-
-void end_render_textures(Render *re)
-{
- Tex *tex;
- for (tex= re->main->tex.first; tex; tex= tex->id.next)
- if (tex->id.us)
- end_render_texture(tex);
-}
-
/* ------------------------------------------------------------------------- */
@@ -755,7 +686,6 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
else {
copy_v3_v3(nor, n);
}
- mul_mat3_m4_v3(R.viewinv, nor);
x1 = fabsf(nor[0]);
y1 = fabsf(nor[1]);
@@ -781,115 +711,20 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
/* ------------------------------------------------------------------------- */
-/* mtex argument only for projection switches */
-static int cubemap(
- const MTex *mtex, VlakRen *vlr, const float n[3], float x, float y, float z, float *adr1, float *adr2)
-{
- int proj[4]={0, ME_PROJXY, ME_PROJXZ, ME_PROJYZ}, ret= 0;
-
- if (vlr) {
- int index;
-
- /* Mesh vertices have such flags, for others we calculate it once based on orco */
- if ((vlr->puno & (ME_PROJXY|ME_PROJXZ|ME_PROJYZ))==0) {
- /* test for v1, vlr can be faked for baking */
- if (vlr->v1 && vlr->v1->orco) {
- float nor[3];
- normal_tri_v3(nor, vlr->v1->orco, vlr->v2->orco, vlr->v3->orco);
-
- if (fabsf(nor[0]) < fabsf(nor[2]) && fabsf(nor[1]) < fabsf(nor[2])) vlr->puno |= ME_PROJXY;
- else if (fabsf(nor[0]) < fabsf(nor[1]) && fabsf(nor[2]) < fabsf(nor[1])) vlr->puno |= ME_PROJXZ;
- else vlr->puno |= ME_PROJYZ;
- }
- else return cubemap_glob(n, x, y, z, adr1, adr2);
- }
-
- if (mtex) {
- /* the mtex->proj{xyz} have type char. maybe this should be wider? */
- /* casting to int ensures that the index type is right. */
- index = (int) mtex->projx;
- proj[index]= ME_PROJXY;
-
- index = (int) mtex->projy;
- proj[index]= ME_PROJXZ;
-
- index = (int) mtex->projz;
- proj[index]= ME_PROJYZ;
- }
-
- if (vlr->puno & proj[1]) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (y + 1.0f) / 2.0f;
- }
- else if (vlr->puno & proj[2]) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 1;
- }
- else {
- *adr1 = (y + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 2;
- }
- }
- else {
- return cubemap_glob(n, x, y, z, adr1, adr2);
- }
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int cubemap_ob(Object *ob, const float n[3], float x, float y, float z, float *adr1, float *adr2)
-{
- float x1, y1, z1, nor[3];
- int ret;
-
- if (n==NULL) return 0;
-
- copy_v3_v3(nor, n);
- if (ob) mul_mat3_m4_v3(ob->imat, nor);
-
- x1 = fabsf(nor[0]);
- y1 = fabsf(nor[1]);
- z1 = fabsf(nor[2]);
-
- if (z1>=x1 && z1>=y1) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (y + 1.0f) / 2.0f;
- ret= 0;
- }
- else if (y1>=x1 && y1>=z1) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 1;
- }
- else {
- *adr1 = (y + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 2;
- }
- return ret;
-}
-
/* ------------------------------------------------------------------------- */
static void do_2d_mapping(
- const MTex *mtex, float texvec[3], VlakRen *vlr, const float n[3], float dxt[3], float dyt[3])
+ const MTex *mtex, float texvec[3], const float n[3], float dxt[3], float dyt[3])
{
Tex *tex;
- Object *ob= NULL;
float fx, fy, fac1, area[8];
- int ok, proj, areaflag= 0, wrap, texco;
+ int ok, proj, areaflag= 0, wrap;
/* mtex variables localized, only cubemap doesn't cooperate yet... */
wrap= mtex->mapping;
tex= mtex->tex;
- ob= mtex->object;
- texco= mtex->texco;
- if (R.osa==0) {
+ if (!(dxt && dyt)) {
if (wrap==MTEX_FLAT) {
fx = (texvec[0] + 1.0f) / 2.0f;
@@ -898,9 +733,7 @@ static void do_2d_mapping(
else if (wrap == MTEX_TUBE) map_to_tube( &fx, &fy, texvec[0], texvec[1], texvec[2]);
else if (wrap == MTEX_SPHERE) map_to_sphere(&fx, &fy, texvec[0], texvec[1], texvec[2]);
else {
- if (texco == TEXCO_OBJECT) cubemap_ob(ob, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else if (texco == TEXCO_GLOB) cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else cubemap(mtex, vlr, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
+ cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
}
/* repeat */
@@ -996,9 +829,7 @@ static void do_2d_mapping(
}
else {
- if (texco==TEXCO_OBJECT) proj = cubemap_ob(ob, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else if (texco==TEXCO_GLOB) proj = cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else proj = cubemap(mtex, vlr, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
+ proj = cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
if (proj==1) {
SWAP(float, dxt[1], dxt[2]);
@@ -1124,8 +955,9 @@ static int multitex(Tex *tex,
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
if (use_nodes && tex->use_nodes && tex->nodetree) {
+ const float cfra = 1.0f; /* This was only set for Blender Internal render before. */
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
- tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
+ tex, which_output, cfra, texnode_preview, NULL);
}
else {
switch (tex->type) {
@@ -1160,9 +992,6 @@ static int multitex(Tex *tex,
BKE_image_tag_time(tex->ima);
}
break;
- case TEX_ENVMAP:
- retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool, skip_load_image);
- break;
case TEX_MUSGRAVE:
/* newnoise: musgrave types */
@@ -1205,15 +1034,6 @@ static int multitex(Tex *tex,
retval = mg_distNoiseTex(tex, tmpvec, texres);
break;
- case TEX_POINTDENSITY:
- retval = pointdensitytex(tex, texvec, texres);
- break;
- case TEX_VOXELDATA:
- retval = voxeldatatex(tex, texvec, texres);
- break;
- case TEX_OCEAN:
- retval = ocean_texture(tex, texvec, texres);
- break;
}
}
@@ -1238,7 +1058,6 @@ static int multitex_nodes_intern(Tex *tex,
TexResult *texres,
const short thread,
short which_output,
- ShadeInput *shi,
MTex *mtex, struct
ImagePool *pool,
const bool scene_color_manage,
@@ -1259,7 +1078,7 @@ static int multitex_nodes_intern(Tex *tex,
if (mtex) {
/* we have mtex, use it for 2d mapping images only */
- do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
rgbnor = multitex(tex,
texvec,
dxt, dyt,
@@ -1272,7 +1091,7 @@ static int multitex_nodes_intern(Tex *tex,
texnode_preview,
use_nodes);
- if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
+ if (mtex->mapto & (MAP_COL)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
@@ -1307,7 +1126,7 @@ static int multitex_nodes_intern(Tex *tex,
zero_v3(dyt_l);
}
- do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l);
+ do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
rgbnor = multitex(tex,
texvec_l,
dxt_l, dyt_l,
@@ -1357,41 +1176,15 @@ static int multitex_nodes_intern(Tex *tex,
* Use it from render pipeline only!
*/
int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres,
- const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool)
+ const short thread, short which_output, MTex *mtex, struct ImagePool *pool)
{
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
- thread, which_output, shi, mtex, pool, R.scene_color_manage,
- (R.r.scemode & R_NO_IMAGE_LOAD) != 0,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ thread, which_output, mtex, pool, true,
+ false,
+ false,
true);
}
-/* this is called for surface shading */
-static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
-{
- Tex *tex = mtex->tex;
- /* TODO(sergey): Texture preview should become an argument? */
- if (tex->use_nodes && tex->nodetree) {
- /* stupid exception here .. but we have to pass shi and mtex to
- * textures nodes for 2d mapping and color management for images */
- return ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, shi->osatex, shi->thread,
- tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex);
- }
- else {
- return multitex(mtex->tex,
- texvec,
- dxt, dyt,
- shi->osatex,
- texres,
- shi->thread,
- mtex->which_output,
- pool,
- skip_load_image,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
- true);
- }
-}
-
/* Warning, if the texres's values are not declared zero, check the return value to be sure
* the color values are set before using the r/g/b values, otherwise you may use uninitialized values - Campbell
*
@@ -1414,7 +1207,7 @@ int multitex_ext(Tex *tex,
texres,
thread,
0,
- NULL, NULL,
+ NULL,
pool,
scene_color_manage,
skip_load_image,
@@ -1435,7 +1228,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
texres,
0,
0,
- NULL, NULL,
+ NULL,
pool,
scene_color_manage,
skip_load_image,
@@ -1652,1949 +1445,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
return in;
}
-static void texco_mapping(ShadeInput *shi, Tex *tex, MTex *mtex,
- const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3])
-{
- /* new: first swap coords, then map, then trans/scale */
- if (tex->type == TEX_IMAGE) {
- /* placement */
- texvec[0] = mtex->projx ? co[mtex->projx - 1] : 0.f;
- texvec[1] = mtex->projy ? co[mtex->projy - 1] : 0.f;
- texvec[2] = mtex->projz ? co[mtex->projz - 1] : 0.f;
-
- if (shi->osatex) {
- if (mtex->projx) {
- dxt[0] = dx[mtex->projx - 1];
- dyt[0] = dy[mtex->projx - 1];
- }
- else dxt[0] = dyt[0] = 0.f;
- if (mtex->projy) {
- dxt[1] = dx[mtex->projy - 1];
- dyt[1] = dy[mtex->projy - 1];
- }
- else dxt[1] = dyt[1] = 0.f;
- if (mtex->projz) {
- dxt[2] = dx[mtex->projz - 1];
- dyt[2] = dy[mtex->projz - 1];
- }
- else dxt[2] = dyt[2] = 0.f;
- }
- do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
-
- /* translate and scale */
- texvec[0] = mtex->size[0]*(texvec[0] - 0.5f) + mtex->ofs[0] + 0.5f;
- texvec[1] = mtex->size[1]*(texvec[1] - 0.5f) + mtex->ofs[1] + 0.5f;
- if (shi->osatex) {
- dxt[0] = mtex->size[0] * dxt[0];
- dxt[1] = mtex->size[1] * dxt[1];
- dyt[0] = mtex->size[0] * dyt[0];
- dyt[1] = mtex->size[1] * dyt[1];
- }
-
- /* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
- /* TXF: bug was here, only modify texvec when repeat mode set, old code affected other modes too.
- * New texfilters solve mirroring differently so that it also works correctly when
- * textures are scaled (sizeXYZ) as well as repeated. See also modification in do_2d_mapping().
- * (since currently only done in osa mode, results will look incorrect without osa TODO) */
- if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_XMIR)) {
- if (tex->texfilter == TXF_BOX)
- texvec[0] -= floorf(texvec[0]); /* this line equivalent to old code, same below */
- else if (texvec[0] < 0.f || texvec[0] > 1.f) {
- const float tx = 0.5f*texvec[0];
- texvec[0] = 2.f*(tx - floorf(tx));
- if (texvec[0] > 1.f) texvec[0] = 2.f - texvec[0];
- }
- }
- if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_YMIR)) {
- if (tex->texfilter == TXF_BOX)
- texvec[1] -= floorf(texvec[1]);
- else if (texvec[1] < 0.f || texvec[1] > 1.f) {
- const float ty = 0.5f*texvec[1];
- texvec[1] = 2.f*(ty - floorf(ty));
- if (texvec[1] > 1.f) texvec[1] = 2.f - texvec[1];
- }
- }
-
- }
- else { /* procedural */
- /* placement */
- texvec[0] = mtex->size[0]*(mtex->projx ? (co[mtex->projx - 1] + mtex->ofs[0]) : mtex->ofs[0]);
- texvec[1] = mtex->size[1]*(mtex->projy ? (co[mtex->projy - 1] + mtex->ofs[1]) : mtex->ofs[1]);
- texvec[2] = mtex->size[2]*(mtex->projz ? (co[mtex->projz - 1] + mtex->ofs[2]) : mtex->ofs[2]);
-
- if (shi->osatex) {
- if (mtex->projx) {
- dxt[0] = mtex->size[0]*dx[mtex->projx - 1];
- dyt[0] = mtex->size[0]*dy[mtex->projx - 1];
- }
- else dxt[0] = dyt[0] = 0.f;
- if (mtex->projy) {
- dxt[1] = mtex->size[1]*dx[mtex->projy - 1];
- dyt[1] = mtex->size[1]*dy[mtex->projy - 1];
- }
- else dxt[1] = dyt[1] = 0.f;
- if (mtex->projz) {
- dxt[2] = mtex->size[2]*dx[mtex->projz - 1];
- dyt[2] = mtex->size[2]*dy[mtex->projz - 1];
- }
- else dxt[2]= dyt[2] = 0.f;
- }
-
- if (mtex->tex->type == TEX_ENVMAP) {
- EnvMap *env = tex->env;
- if (!env->object) {
- // env->object is a view point for envmap rendering
- // if it's not set, return the result depending on the world_space_shading flag
- if (BKE_scene_use_world_space_shading(R.scene)) {
- mul_mat3_m4_v3(R.viewinv, texvec);
- if (shi->osatex) {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
- }
- }
- }
- }
-}
-
-/* Bump code from 2.5 development cycle, has a number of bugs, but here for compatibility */
-
-typedef struct CompatibleBump {
- float nu[3], nv[3], nn[3];
- float dudnu, dudnv, dvdnu, dvdnv;
- bool nunvdone;
-} CompatibleBump;
-
-static void compatible_bump_init(CompatibleBump *compat_bump)
-{
- memset(compat_bump, 0, sizeof(*compat_bump));
-
- compat_bump->dudnu = 1.0f;
- compat_bump->dvdnv = 1.0f;
-}
-
-static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, int i)
-{
- /* uvmapping only, calculation of normal tangent u/v partial derivatives
- * (should not be here, dudnu, dudnv, dvdnu & dvdnv should probably be part of ShadeInputUV struct,
- * nu/nv in ShadeInput and this calculation should then move to shadeinput.c,
- * shade_input_set_shade_texco() func.) */
-
- /* NOTE: test for shi->obr->ob here,
- * since vlr/obr/obi can be 'fake' when called from fastshade(), another reason to move it.. */
-
- /* NOTE: shi->v1 is NULL when called from displace_render_vert,
- * assigning verts in this case is not trivial because the shi quad face side is not know. */
- if ((mtex->texflag & MTEX_COMPAT_BUMP) && shi->obr && shi->obr->ob && shi->v1) {
- if (mtex->mapto & (MAP_NORM|MAP_WARP) && !((mtex->tex->type==TEX_IMAGE) && (mtex->tex->imaflag & TEX_NORMALMAP))) {
- MTFace* tf = RE_vlakren_get_tface(shi->obr, shi->vlr, i, NULL, 0);
- int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
-
- vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
-
- /* compute ortho basis around normal */
- if (!compat_bump->nunvdone) {
- /* render normal is negated */
- compat_bump->nn[0] = -shi->vn[0];
- compat_bump->nn[1] = -shi->vn[1];
- compat_bump->nn[2] = -shi->vn[2];
- ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn);
- compat_bump->nunvdone = true;
- }
-
- if (tf) {
- const float *uv1 = tf->uv[j1], *uv2 = tf->uv[j2], *uv3 = tf->uv[j3];
- const float an[3] = {fabsf(compat_bump->nn[0]), fabsf(compat_bump->nn[1]), fabsf(compat_bump->nn[2])};
- const int a1 = (an[0] > an[1] && an[0] > an[2]) ? 1 : 0;
- const int a2 = (an[2] > an[0] && an[2] > an[1]) ? 1 : 2;
- const float dp1_a1 = shi->v1->co[a1] - shi->v3->co[a1];
- const float dp1_a2 = shi->v1->co[a2] - shi->v3->co[a2];
- const float dp2_a1 = shi->v2->co[a1] - shi->v3->co[a1];
- const float dp2_a2 = shi->v2->co[a2] - shi->v3->co[a2];
- const float du1 = uv1[0] - uv3[0], du2 = uv2[0] - uv3[0];
- const float dv1 = uv1[1] - uv3[1], dv2 = uv2[1] - uv3[1];
- const float dpdu_a1 = dv2*dp1_a1 - dv1*dp2_a1;
- const float dpdu_a2 = dv2*dp1_a2 - dv1*dp2_a2;
- const float dpdv_a1 = du1*dp2_a1 - du2*dp1_a1;
- const float dpdv_a2 = du1*dp2_a2 - du2*dp1_a2;
- float d = dpdu_a1*dpdv_a2 - dpdv_a1*dpdu_a2;
- float uvd = du1*dv2 - dv1*du2;
-
- if (uvd == 0.f) uvd = 1e-5f;
- if (d == 0.f) d = 1e-5f;
- d = uvd / d;
-
- compat_bump->dudnu = (dpdv_a2*compat_bump->nu[a1] - dpdv_a1*compat_bump->nu[a2])*d;
- compat_bump->dvdnu = (dpdu_a1*compat_bump->nu[a2] - dpdu_a2*compat_bump->nu[a1])*d;
- compat_bump->dudnv = (dpdv_a2*compat_bump->nv[a1] - dpdv_a1*compat_bump->nv[a2])*d;
- compat_bump->dvdnv = (dpdu_a1*compat_bump->nv[a2] - dpdu_a2*compat_bump->nv[a1])*d;
- }
- }
- }
-}
-
-static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
- float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3],
- struct ImagePool *pool, const bool skip_load_image)
-{
- TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
- float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv;
- const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
- const float bf = -0.04f*Tnor*mtex->norfac;
- int rgbnor;
- /* disable internal bump eval */
- float *nvec = texres->nor;
- texres->nor = NULL;
- /* du & dv estimates, constant value defaults */
- du = dv = 0.01f;
-
- /* compute ortho basis around normal */
- if (!compat_bump->nunvdone) {
- /* render normal is negated */
- negate_v3_v3(compat_bump->nn, shi->vn);
- ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn);
- compat_bump->nunvdone = true;
- }
-
- /* two methods, either constant based on main image resolution,
- * (which also works without osa, though of course not always good (or even very bad) results),
- * or based on tex derivative max values (osa only). Not sure which is best... */
-
- if (!shi->osatex && (tex->type == TEX_IMAGE) && tex->ima) {
- /* in case we have no proper derivatives, fall back to
- * computing du/dv it based on image size */
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
- if (ibuf) {
- du = 1.f/(float)ibuf->x;
- dv = 1.f/(float)ibuf->y;
- }
- BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
- }
- else if (shi->osatex) {
- /* we have derivatives, can compute proper du/dv */
- if (tex->type == TEX_IMAGE) { /* 2d image, use u & v max. of dx/dy 2d vecs */
- const float adx[2] = {fabsf(dx[0]), fabsf(dx[1])};
- const float ady[2] = {fabsf(dy[0]), fabsf(dy[1])};
- du = MAX2(adx[0], ady[0]);
- dv = MAX2(adx[1], ady[1]);
- }
- else { /* 3d procedural, estimate from all dx/dy elems */
- const float adx[3] = {fabsf(dx[0]), fabsf(dx[1]), fabsf(dx[2])};
- const float ady[3] = {fabsf(dy[0]), fabsf(dy[1]), fabsf(dy[2])};
- du = max_fff(adx[0], adx[1], adx[2]);
- dv = max_fff(ady[0], ady[1], ady[2]);
- }
- }
-
- /* center, main return value */
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
- cd = fromrgb ? (texres->tr + texres->tg + texres->tb) / 3.0f : texres->tin;
-
- if (mtex->texco == TEXCO_UV) {
- /* for the uv case, use the same value for both du/dv,
- * since individually scaling the normal derivatives makes them useless... */
- du = min_ff(du, dv);
- idu = (du < 1e-5f) ? bf : (bf/du);
-
- /* +u val */
- tco[0] = co[0] + compat_bump->dudnu*du;
- tco[1] = co[1] + compat_bump->dvdnu*du;
- tco[2] = 0.f;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
-
- /* +v val */
- tco[0] = co[0] + compat_bump->dudnv*du;
- tco[1] = co[1] + compat_bump->dvdnv*du;
- tco[2] = 0.f;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
- }
- else {
- float tu[3], tv[3];
-
- copy_v3_v3(tu, compat_bump->nu);
- copy_v3_v3(tv, compat_bump->nv);
-
- idu = (du < 1e-5f) ? bf : (bf/du);
- idv = (dv < 1e-5f) ? bf : (bf/dv);
-
- if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) {
- mul_mat3_m4_v3(shi->obr->ob->imat_ren, tu);
- mul_mat3_m4_v3(shi->obr->ob->imat_ren, tv);
- normalize_v3(tu);
- normalize_v3(tv);
- }
- else if (mtex->texco == TEXCO_GLOB) {
- mul_mat3_m4_v3(R.viewinv, tu);
- mul_mat3_m4_v3(R.viewinv, tv);
- }
- else if (mtex->texco == TEXCO_OBJECT && mtex->object) {
- mul_mat3_m4_v3(mtex->object->imat_ren, tu);
- mul_mat3_m4_v3(mtex->object->imat_ren, tv);
- normalize_v3(tu);
- normalize_v3(tv);
- }
-
- /* +u val */
- tco[0] = co[0] + tu[0]*du;
- tco[1] = co[1] + tu[1]*du;
- tco[2] = co[2] + tu[2]*du;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
-
- /* +v val */
- tco[0] = co[0] + tv[0]*dv;
- tco[1] = co[1] + tv[1]*dv;
- tco[2] = co[2] + tv[2]*dv;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
- }
-
- /* bumped normal */
- compat_bump->nu[0] += ud*compat_bump->nn[0];
- compat_bump->nu[1] += ud*compat_bump->nn[1];
- compat_bump->nu[2] += ud*compat_bump->nn[2];
- compat_bump->nv[0] += vd*compat_bump->nn[0];
- compat_bump->nv[1] += vd*compat_bump->nn[1];
- compat_bump->nv[2] += vd*compat_bump->nn[2];
- cross_v3_v3v3(nvec, compat_bump->nu, compat_bump->nv);
-
- nvec[0] = -nvec[0];
- nvec[1] = -nvec[1];
- nvec[2] = -nvec[2];
- texres->nor = nvec;
-
- rgbnor |= TEX_NOR;
- return rgbnor;
-}
-
-/* Improved bump code from later in 2.5 development cycle */
-
-typedef struct NTapBump {
- int init_done;
- int iPrevBumpSpace; /* 0: uninitialized, 1: objectspace, 2: texturespace, 4: viewspace */
- /* bumpmapping */
- float vNorg[3]; /* backup copy of shi->vn */
- float vNacc[3]; /* original surface normal minus the surface gradient of every bump map which is encountered */
- float vR1[3], vR2[3]; /* cross products (sigma_y, original_normal), (original_normal, sigma_x) */
- float sgn_det; /* sign of the determinant of the matrix {sigma_x, sigma_y, original_normal} */
- float fPrevMagnitude; /* copy of previous magnitude, used for multiple bumps in different spaces */
-} NTapBump;
-
-static void ntap_bump_init(NTapBump *ntap_bump)
-{
- memset(ntap_bump, 0, sizeof(*ntap_bump));
-}
-
-static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
- float Tnor, const float co[3], const float dx[3], const float dy[3],
- float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool,
- const bool skip_load_image)
-{
- TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
-
- const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
-
- /* The negate on Hscale is done because the
- * normal in the renderer points inward which corresponds
- * to inverting the bump map. The normals are generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- float Hscale = -Tnor*mtex->norfac;
-
- int dimx=512, dimy=512;
- const int imag_tspace_dimension_x = 1024; /* only used for texture space variant */
- float aspect = 1.0f;
-
- /* 2 channels for 2D texture and 3 for 3D textures. */
- const int nr_channels = (mtex->texco == TEXCO_UV)? 2 : 3;
- int c, rgbnor, iBumpSpace;
- float dHdx, dHdy;
- int found_deriv_map = (tex->type==TEX_IMAGE) && (tex->imaflag & TEX_DERIVATIVEMAP);
-
- /* disable internal bump eval in sampler, save pointer */
- float *nvec = texres->nor;
- texres->nor = NULL;
-
- if (found_deriv_map==0) {
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima)
- Hscale *= 13.0f; /* appears to be a sensible default value */
- }
- else
- Hscale *= 0.1f; /* factor 0.1 proved to look like the previous bump code */
- }
-
- if ( !ntap_bump->init_done ) {
- copy_v3_v3(ntap_bump->vNacc, shi->vn);
- copy_v3_v3(ntap_bump->vNorg, shi->vn);
- ntap_bump->fPrevMagnitude = 1.0f;
- ntap_bump->iPrevBumpSpace = 0;
-
- ntap_bump->init_done = true;
- }
-
- /* resolve image dimensions */
- if (found_deriv_map || (mtex->texflag&MTEX_BUMP_TEXTURESPACE)!=0) {
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
- if (ibuf) {
- dimx = ibuf->x;
- dimy = ibuf->y;
- aspect = ((float) dimy) / dimx;
- }
- BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
- }
-
- if (found_deriv_map) {
- float dBdu, dBdv, auto_bump = 1.0f;
- float s = 1; /* negate this if flipped texture coordinate */
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
-
- if (shi->obr->ob->derivedFinal) {
- auto_bump = shi->obr->ob->derivedFinal->auto_bump_scale;
- }
-
- {
- float fVirtDim = sqrtf(fabsf((float) (dimx*dimy)*mtex->size[0]*mtex->size[1]));
- auto_bump /= MAX2(fVirtDim, FLT_EPSILON);
- }
-
- /* this variant using a derivative map is described here
- * http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html */
- dBdu = auto_bump*Hscale*dimx*(2*texres->tr-1);
- dBdv = auto_bump*Hscale*dimy*(2*texres->tg-1);
-
- dHdx = dBdu*dxt[0] + s * dBdv*dxt[1];
- dHdy = dBdu*dyt[0] + s * dBdv*dyt[1];
- }
- else if (!(mtex->texflag & MTEX_5TAP_BUMP)) {
- /* compute height derivatives with respect to output image pixel coordinates x and y */
- float STll[3], STlr[3], STul[3];
- float Hll, Hlr, Hul;
-
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
-
- for (c=0; c<nr_channels; c++) {
- /* dx contains the derivatives (du/dx, dv/dx)
- * dy contains the derivatives (du/dy, dv/dy) */
- STll[c] = texvec[c];
- STlr[c] = texvec[c]+dxt[c];
- STul[c] = texvec[c]+dyt[c];
- }
-
- /* clear unused derivatives */
- for (c=nr_channels; c<3; c++) {
- STll[c] = 0.0f;
- STlr[c] = 0.0f;
- STul[c] = 0.0f;
- }
-
- /* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image);
- Hll = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin;
-
- /* use ttexr for the other 2 taps */
- multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hlr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image);
- Hul = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- dHdx = Hscale*(Hlr - Hll);
- dHdy = Hscale*(Hul - Hll);
- }
- else {
- /* same as above, but doing 5 taps, increasing quality at cost of speed */
- float STc[3], STl[3], STr[3], STd[3], STu[3];
- float /* Hc, */ /* UNUSED */ Hl, Hr, Hd, Hu;
-
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
-
- for (c=0; c<nr_channels; c++) {
- STc[c] = texvec[c];
- STl[c] = texvec[c] - 0.5f*dxt[c];
- STr[c] = texvec[c] + 0.5f*dxt[c];
- STd[c] = texvec[c] - 0.5f*dyt[c];
- STu[c] = texvec[c] + 0.5f*dyt[c];
- }
-
- /* clear unused derivatives */
- for (c=nr_channels; c<3; c++) {
- STc[c] = 0.0f;
- STl[c] = 0.0f;
- STr[c] = 0.0f;
- STd[c] = 0.0f;
- STu[c] = 0.0f;
- }
-
- /* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image);
- /* Hc = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; */ /* UNUSED */
-
- /* use ttexr for the other taps */
- multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image);
- Hl = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image);
- Hd = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image);
- Hu = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- dHdx = Hscale*(Hr - Hl);
- dHdy = Hscale*(Hu - Hd);
- }
-
- /* restore pointer */
- texres->nor = nvec;
-
- /* replaced newbump with code based on listing 1 and 2 of
- * [Mik10] Mikkelsen M. S.: Bump Mapping Unparameterized Surfaces on the GPU.
- * -> http://jbit.net/~sparky/sfgrad_bump/mm_sfgrad_bump.pdf */
-
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
- iBumpSpace = 1;
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
- iBumpSpace = 2;
- else
- iBumpSpace = 4; /* ViewSpace */
-
- if ( ntap_bump->iPrevBumpSpace != iBumpSpace ) {
-
- /* initialize normal perturbation vectors */
- int xyz;
- float fDet, abs_fDet, fMagnitude;
- /* object2view and inverted matrix */
- float obj2view[3][3], view2obj[3][3], tmp[4][4];
- /* local copies of derivatives and normal */
- float dPdx[3], dPdy[3], vN[3];
- copy_v3_v3(dPdx, shi->dxco);
- copy_v3_v3(dPdy, shi->dyco);
- copy_v3_v3(vN, ntap_bump->vNorg);
-
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) {
- /* TODO: these calculations happen for every pixel!
- * -> move to shi->obi */
- mul_m4_m4m4(tmp, R.viewmat, shi->obr->ob->obmat);
- copy_m3_m4(obj2view, tmp); /* use only upper left 3x3 matrix */
- invert_m3_m3(view2obj, obj2view);
-
- /* generate the surface derivatives in object space */
- mul_m3_v3(view2obj, dPdx);
- mul_m3_v3(view2obj, dPdy);
- /* generate the unit normal in object space */
- mul_transposed_m3_v3(obj2view, vN);
- normalize_v3(vN);
- }
-
- cross_v3_v3v3(ntap_bump->vR1, dPdy, vN);
- cross_v3_v3v3(ntap_bump->vR2, vN, dPdx);
- fDet = dot_v3v3(dPdx, ntap_bump->vR1);
- ntap_bump->sgn_det = (fDet < 0)? -1.0f: 1.0f;
- abs_fDet = ntap_bump->sgn_det * fDet;
-
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima) {
- /* crazy hack solution that gives results similar to normal mapping - part 1 */
- normalize_v3(ntap_bump->vR1);
- normalize_v3(ntap_bump->vR2);
- abs_fDet = 1.0f;
- }
- }
-
- fMagnitude = abs_fDet;
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) {
- /* pre do transform of texres->nor by the inverse transposed of obj2view */
- mul_transposed_m3_v3(view2obj, vN);
- mul_transposed_m3_v3(view2obj, ntap_bump->vR1);
- mul_transposed_m3_v3(view2obj, ntap_bump->vR2);
-
- fMagnitude *= len_v3(vN);
- }
-
- if (ntap_bump->fPrevMagnitude > 0.0f)
- for (xyz=0; xyz<3; xyz++)
- ntap_bump->vNacc[xyz] *= fMagnitude / ntap_bump->fPrevMagnitude;
-
- ntap_bump->fPrevMagnitude = fMagnitude;
- ntap_bump->iPrevBumpSpace = iBumpSpace;
- }
-
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima) {
- /* crazy hack solution that gives results similar to normal mapping - part 2 */
- float vec[2];
- const float imag_tspace_dimension_y = aspect*imag_tspace_dimension_x;
-
- vec[0] = imag_tspace_dimension_x*dxt[0];
- vec[1] = imag_tspace_dimension_y*dxt[1];
- dHdx *= 1.0f/len_v2(vec);
- vec[0] = imag_tspace_dimension_x*dyt[0];
- vec[1] = imag_tspace_dimension_y*dyt[1];
- dHdy *= 1.0f/len_v2(vec);
- }
- }
-
- /* subtract the surface gradient from vNacc */
- for (c=0; c<3; c++) {
- float vSurfGrad_compi = ntap_bump->sgn_det * (dHdx * ntap_bump->vR1[c] + dHdy * ntap_bump->vR2[c]);
- ntap_bump->vNacc[c] -= vSurfGrad_compi;
- texres->nor[c] = ntap_bump->vNacc[c]; /* copy */
- }
-
- rgbnor |= TEX_NOR;
- return rgbnor;
-}
-
-void do_material_tex(ShadeInput *shi, Render *re)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- CompatibleBump compat_bump;
- NTapBump ntap_bump;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float *co = NULL, *dx = NULL, *dy = NULL;
- float fact, facm, factt, facmm, stencilTin=1.0;
- float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0;
- int tex_nr, rgbnor= 0;
- bool warp_done = false, use_compat_bump = false, use_ntap_bump = false;
- bool found_nmapping = false, found_deriv_map = false;
- bool iFirstTimeNMap = true;
-
- compatible_bump_init(&compat_bump);
- ntap_bump_init(&ntap_bump);
-
- if (re->r.scemode & R_NO_TEX) return;
- /* here: test flag if there's a tex (todo) */
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
-
- /* separate tex switching */
- if (shi->mat->septex & (1<<tex_nr)) continue;
-
- if (shi->mat->mtex[tex_nr]) {
- mtex= shi->mat->mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex == NULL) continue;
-
- found_deriv_map = (tex->type==TEX_IMAGE) && (tex->imaflag & TEX_DERIVATIVEMAP);
- use_compat_bump= (mtex->texflag & MTEX_COMPAT_BUMP) != 0;
- use_ntap_bump = ((mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP))!=0 || found_deriv_map!=0) ? true : false;
-
- /* XXX texture node trees don't work for this yet */
- if (tex->nodetree && tex->use_nodes) {
- use_compat_bump = false;
- use_ntap_bump = false;
- }
-
- /* case displacement mapping */
- if (shi->osatex == 0 && use_ntap_bump) {
- use_ntap_bump = false;
- use_compat_bump = true;
- }
-
- /* case ocean */
- if (tex->type == TEX_OCEAN) {
- use_ntap_bump = false;
- use_compat_bump = false;
- }
-
- /* which coords */
- if (mtex->texco==TEXCO_ORCO) {
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- co= shi->duplilo; dx= dxt; dy= dyt;
- dxt[0]= dxt[1]= dxt[2]= 0.0f;
- dyt[0]= dyt[1]= dyt[2]= 0.0f;
- }
- else {
- co= shi->lo; dx= shi->dxlo; dy= shi->dylo;
- }
- }
- else if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- co= tempvec;
- dx= dxt;
- dy= dyt;
- copy_v3_v3(tempvec, shi->co);
- if (mtex->texflag & MTEX_OB_DUPLI_ORIG)
- if (shi->obi && shi->obi->duplitexmat)
- mul_m4_v3(shi->obi->duplitexmat, tempvec);
- mul_m4_v3(ob->imat_ren, tempvec);
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxco);
- copy_v3_v3(dyt, shi->dyco);
- mul_mat3_m4_v3(ob->imat_ren, dxt);
- mul_mat3_m4_v3(ob->imat_ren, dyt);
- }
- }
- else {
- /* if object doesn't exist, do not use orcos (not initialized) */
- co= shi->co;
- dx= shi->dxco; dy= shi->dyco;
- }
- }
- else if (mtex->texco==TEXCO_REFL) {
- calc_R_ref(shi);
- co= shi->ref; dx= shi->dxref; dy= shi->dyref;
- }
- else if (mtex->texco==TEXCO_NORM) {
- co= shi->orn; dx= shi->dxno; dy= shi->dyno;
- }
- else if (mtex->texco==TEXCO_TANGENT) {
- co= shi->tang; dx= shi->dxno; dy= shi->dyno;
- }
- else if (mtex->texco==TEXCO_GLOB) {
- co= shi->gl; dx= shi->dxgl; dy= shi->dygl;
- }
- else if (mtex->texco==TEXCO_UV) {
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- co= shi->dupliuv; dx= dxt; dy= dyt;
- dxt[0]= dxt[1]= dxt[2]= 0.0f;
- dyt[0]= dyt[1]= dyt[2]= 0.0f;
- }
- else {
- ShadeInputUV *suv= &shi->uv[shi->actuv];
- int i = shi->actuv;
-
- if (mtex->uvname[0] != 0) {
- for (i = 0; i < shi->totuv; i++) {
- if (STREQ(shi->uv[i].name, mtex->uvname)) {
- suv= &shi->uv[i];
- break;
- }
- }
- }
-
- co= suv->uv;
- dx= suv->dxuv;
- dy= suv->dyuv;
-
- compatible_bump_uv_derivs(&compat_bump, shi, mtex, i);
- }
- }
- else if (mtex->texco==TEXCO_WINDOW) {
- co= shi->winco; dx= shi->dxwin; dy= shi->dywin;
- }
- else if (mtex->texco==TEXCO_STRAND) {
- co= tempvec; dx= dxt; dy= dyt;
- co[0]= shi->strandco;
- co[1]= co[2]= 0.0f;
- dx[0]= shi->dxstrand;
- dx[1]= dx[2]= 0.0f;
- dy[0]= shi->dystrand;
- dy[1]= dy[2]= 0.0f;
- }
- else if (mtex->texco==TEXCO_STRESS) {
- co= tempvec; dx= dxt; dy= dyt;
- co[0]= shi->stress;
- co[1]= co[2]= 0.0f;
- dx[0]= 0.0f;
- dx[1]= dx[2]= 0.0f;
- dy[0]= 0.0f;
- dy[1]= dy[2]= 0.0f;
- }
- else {
- continue; /* can happen when texco defines disappear and it renders old files */
- }
-
- /* the pointer defines if bumping happens */
- if (mtex->mapto & (MAP_NORM|MAP_WARP)) {
- texres.nor= norvec;
- norvec[0]= norvec[1]= norvec[2]= 0.0;
- }
- else texres.nor= NULL;
-
- if (warp_done) {
- add_v3_v3v3(tempvec, co, warpvec);
- co= tempvec;
- }
-
- /* XXX texture node trees don't work for this yet */
- if (texres.nor && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) {
- if (use_compat_bump) {
- rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex,
- &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool, skip_load_image);
- }
- else if (use_ntap_bump) {
- rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex,
- &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool, skip_load_image);
- }
- else {
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
- }
- }
- else {
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
- }
-
- /* texture output */
-
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgbnor -= TEX_RGB;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- Tnor*= stencilTin;
- }
-
- if (texres.nor) {
- if ((rgbnor & TEX_NOR)==0) {
- /* make our own normal */
- if (rgbnor & TEX_RGB) {
- copy_v3_v3(texres.nor, &texres.tr);
- }
- else {
- float co_nor= 0.5f * cosf(texres.tin - 0.5f);
- float si = 0.5f * sinf(texres.tin - 0.5f);
- float f1, f2;
-
- f1= shi->vn[0];
- f2= shi->vn[1];
- texres.nor[0]= f1*co_nor+f2*si;
- f1= shi->vn[1];
- f2= shi->vn[2];
- texres.nor[1]= f1*co_nor+f2*si;
- texres.nor[2]= f2*co_nor-f1*si;
- }
- }
- /* warping, local space */
- if (mtex->mapto & MAP_WARP) {
- float *warpnor= texres.nor, warpnor_[3];
-
- if (use_ntap_bump) {
- copy_v3_v3(warpnor_, texres.nor);
- warpnor= warpnor_;
- normalize_v3(warpnor_);
- }
- warpvec[0]= mtex->warpfac*warpnor[0];
- warpvec[1]= mtex->warpfac*warpnor[1];
- warpvec[2]= mtex->warpfac*warpnor[2];
- warp_done = true;
- }
-#if 0
- if (mtex->texflag & MTEX_VIEWSPACE) {
- /* rotate to global coords */
- if (mtex->texco==TEXCO_ORCO || mtex->texco==TEXCO_UV) {
- if (shi->vlr && shi->obr && shi->obr->ob) {
- float len= normalize_v3(texres.nor);
- /* can be optimized... (ton) */
- mul_mat3_m4_v3(shi->obr->ob->obmat, texres.nor);
- mul_mat3_m4_v3(re->viewmat, texres.nor);
- normalize_v3_length(texres.nor, len);
- }
- }
- }
-#endif
- }
-
- /* mapping */
- if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) {
- float tcol[3];
-
- /* stencil maps on the texture control slider, not texture intensity value */
- copy_v3_v3(tcol, &texres.tr);
-
- if ((rgbnor & TEX_RGB) == 0) {
- copy_v3_v3(tcol, &mtex->r);
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin = stencilTin;
- }
- else {
- texres.tin = texres.ta;
- }
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, re->pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL &&
- ibuf->rect_float == NULL &&
- (rgbnor & TEX_RGB) &&
- R.scene_color_manage)
- {
- IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace);
- }
-
- BKE_image_pool_release_ibuf(ima, ibuf, re->pool);
- }
-
- if (mtex->mapto & MAP_COL) {
- float colfac= mtex->colfac*stencilTin;
- texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
- }
- if (mtex->mapto & MAP_COLSPEC) {
- float colspecfac= mtex->colspecfac*stencilTin;
- texture_rgb_blend(&shi->specr, tcol, &shi->specr, texres.tin, colspecfac, mtex->blendtype);
- }
- if (mtex->mapto & MAP_COLMIR) {
- float mirrfac= mtex->mirrfac*stencilTin;
-
- /* exception for envmap only */
- if (tex->type==TEX_ENVMAP && mtex->blendtype==MTEX_BLEND) {
- fact= texres.tin*mirrfac;
- facm= 1.0f- fact;
- shi->refcol[0]= fact + facm*shi->refcol[0];
- shi->refcol[1]= fact*tcol[0] + facm*shi->refcol[1];
- shi->refcol[2]= fact*tcol[1] + facm*shi->refcol[2];
- shi->refcol[3]= fact*tcol[2] + facm*shi->refcol[3];
- }
- else {
- texture_rgb_blend(&shi->mirr, tcol, &shi->mirr, texres.tin, mirrfac, mtex->blendtype);
- }
- }
- }
- if ( (mtex->mapto & MAP_NORM) ) {
- if (texres.nor) {
- float norfac= mtex->norfac;
-
- /* we need to code blending modes for normals too once.. now 1 exception hardcoded */
-
- if ((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP)) {
-
- found_nmapping = 1;
-
- /* qdn: for normalmaps, to invert the normalmap vector,
- * it is better to negate x & y instead of subtracting the vector as was done before */
- if (norfac < 0.0f) {
- texres.nor[0] = -texres.nor[0];
- texres.nor[1] = -texres.nor[1];
- }
- fact = Tnor*fabsf(norfac);
- if (fact>1.f) fact = 1.f;
- facm = 1.f-fact;
- if (mtex->normapspace == MTEX_NSPACE_TANGENT) {
- /* qdn: tangent space */
- float B[3], tv[3];
- const float *no = iFirstTimeNMap ? shi->nmapnorm : shi->vn;
- iFirstTimeNMap = false;
- cross_v3_v3v3(B, no, shi->nmaptang); /* bitangent */
- mul_v3_fl(B, shi->nmaptang[3]);
- /* transform norvec from tangent space to object surface in camera space */
- tv[0] = texres.nor[0]*shi->nmaptang[0] + texres.nor[1]*B[0] + texres.nor[2]*no[0];
- tv[1] = texres.nor[0]*shi->nmaptang[1] + texres.nor[1]*B[1] + texres.nor[2]*no[1];
- tv[2] = texres.nor[0]*shi->nmaptang[2] + texres.nor[1]*B[2] + texres.nor[2]*no[2];
- shi->vn[0]= facm*no[0] + fact*tv[0];
- shi->vn[1]= facm*no[1] + fact*tv[1];
- shi->vn[2]= facm*no[2] + fact*tv[2];
- }
- else {
- float nor[3];
-
- copy_v3_v3(nor, texres.nor);
-
- if (mtex->normapspace == MTEX_NSPACE_CAMERA) {
- /* pass */
- }
- else if (mtex->normapspace == MTEX_NSPACE_WORLD) {
- mul_mat3_m4_v3(re->viewmat, nor);
- }
- else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
- if (shi->obr && shi->obr->ob)
- mul_mat3_m4_v3(shi->obr->ob->obmat, nor);
- mul_mat3_m4_v3(re->viewmat, nor);
- }
-
- normalize_v3(nor);
-
- /* qdn: worldspace */
- shi->vn[0]= facm*shi->vn[0] + fact*nor[0];
- shi->vn[1]= facm*shi->vn[1] + fact*nor[1];
- shi->vn[2]= facm*shi->vn[2] + fact*nor[2];
- }
- }
- else {
- /* XXX texture node trees don't work for this yet */
- if (use_compat_bump || use_ntap_bump) {
- shi->vn[0] = texres.nor[0];
- shi->vn[1] = texres.nor[1];
- shi->vn[2] = texres.nor[2];
- }
- else {
- float nor[3], dot;
-
- if (shi->mat->mode & MA_TANGENT_V) {
- shi->tang[0]+= Tnor*norfac*texres.nor[0];
- shi->tang[1]+= Tnor*norfac*texres.nor[1];
- shi->tang[2]+= Tnor*norfac*texres.nor[2];
- }
-
- /* prevent bump to become negative normal */
- nor[0]= Tnor*norfac*texres.nor[0];
- nor[1]= Tnor*norfac*texres.nor[1];
- nor[2]= Tnor*norfac*texres.nor[2];
-
- dot= 0.5f + 0.5f * dot_v3v3(nor, shi->vn);
-
- shi->vn[0]+= dot*nor[0];
- shi->vn[1]+= dot*nor[1];
- shi->vn[2]+= dot*nor[2];
- }
- }
- normalize_v3(shi->vn);
-
- /* this makes sure the bump is passed on to the next texture */
- shi->orn[0]= -shi->vn[0];
- shi->orn[1]= -shi->vn[1];
- shi->orn[2]= -shi->vn[2];
- }
- }
-
- if ( mtex->mapto & MAP_DISPLACE ) {
- /* Now that most textures offer both Nor and Intensity, allow */
- /* both to work, and let user select with slider. */
- if (texres.nor) {
- float norfac= mtex->norfac;
-
- shi->displace[0]+= 0.2f*Tnor*norfac*texres.nor[0];
- shi->displace[1]+= 0.2f*Tnor*norfac*texres.nor[1];
- shi->displace[2]+= 0.2f*Tnor*norfac*texres.nor[2];
- }
-
- if (rgbnor & TEX_RGB) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
-
- if (mtex->blendtype==MTEX_BLEND) {
- shi->displace[0]= factt*shi->vn[0] + facmm*shi->displace[0];
- shi->displace[1]= factt*shi->vn[1] + facmm*shi->displace[1];
- shi->displace[2]= factt*shi->vn[2] + facmm*shi->displace[2];
- }
- else if (mtex->blendtype==MTEX_MUL) {
- shi->displace[0]*= factt*shi->vn[0];
- shi->displace[1]*= factt*shi->vn[1];
- shi->displace[2]*= factt*shi->vn[2];
- }
- else { /* add or sub */
- if (mtex->blendtype==MTEX_SUB) factt= -factt;
- shi->displace[0]+= factt*shi->vn[0];
- shi->displace[1]+= factt*shi->vn[1];
- shi->displace[2]+= factt*shi->vn[2];
- }
- }
-
- if (mtex->mapto & MAP_VARS) {
- /* stencil maps on the texture control slider, not texture intensity value */
-
- if (rgbnor & TEX_RGB) {
- if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- if (mtex->mapto & MAP_REF) {
- float difffac= mtex->difffac*stencilTin;
-
- shi->refl= texture_value_blend(mtex->def_var, shi->refl, texres.tin, difffac, mtex->blendtype);
- if (shi->refl<0.0f) shi->refl= 0.0f;
- }
- if (mtex->mapto & MAP_SPEC) {
- float specfac= mtex->specfac*stencilTin;
-
- shi->spec= texture_value_blend(mtex->def_var, shi->spec, texres.tin, specfac, mtex->blendtype);
- if (shi->spec<0.0f) shi->spec= 0.0f;
- }
- if (mtex->mapto & MAP_EMIT) {
- float emitfac= mtex->emitfac*stencilTin;
-
- shi->emit= texture_value_blend(mtex->def_var, shi->emit, texres.tin, emitfac, mtex->blendtype);
- if (shi->emit<0.0f) shi->emit= 0.0f;
- }
- if (mtex->mapto & MAP_ALPHA) {
- float alphafac= mtex->alphafac*stencilTin;
-
- shi->alpha= texture_value_blend(mtex->def_var, shi->alpha, texres.tin, alphafac, mtex->blendtype);
- if (shi->alpha<0.0f) shi->alpha= 0.0f;
- else if (shi->alpha>1.0f) shi->alpha= 1.0f;
- }
- if (mtex->mapto & MAP_HAR) {
- float har; /* have to map to 0-1 */
- float hardfac= mtex->hardfac*stencilTin;
-
- har= ((float)shi->har)/128.0f;
- har= 128.0f*texture_value_blend(mtex->def_var, har, texres.tin, hardfac, mtex->blendtype);
-
- if (har<1.0f) shi->har= 1;
- else if (har>511) shi->har= 511;
- else shi->har= (int)har;
- }
- if (mtex->mapto & MAP_RAYMIRR) {
- float raymirrfac= mtex->raymirrfac*stencilTin;
-
- shi->ray_mirror= texture_value_blend(mtex->def_var, shi->ray_mirror, texres.tin, raymirrfac, mtex->blendtype);
- if (shi->ray_mirror<0.0f) shi->ray_mirror= 0.0f;
- else if (shi->ray_mirror>1.0f) shi->ray_mirror= 1.0f;
- }
- if (mtex->mapto & MAP_TRANSLU) {
- float translfac= mtex->translfac*stencilTin;
-
- shi->translucency= texture_value_blend(mtex->def_var, shi->translucency, texres.tin, translfac, mtex->blendtype);
- if (shi->translucency<0.0f) shi->translucency= 0.0f;
- else if (shi->translucency>1.0f) shi->translucency= 1.0f;
- }
- if (mtex->mapto & MAP_AMB) {
- float ambfac= mtex->ambfac*stencilTin;
-
- shi->amb= texture_value_blend(mtex->def_var, shi->amb, texres.tin, ambfac, mtex->blendtype);
- if (shi->amb<0.0f) shi->amb= 0.0f;
- else if (shi->amb>1.0f) shi->amb= 1.0f;
-
- shi->ambr= shi->amb*re->wrld.ambr;
- shi->ambg= shi->amb*re->wrld.ambg;
- shi->ambb= shi->amb*re->wrld.ambb;
- }
- }
- }
- }
- if ((use_compat_bump || use_ntap_bump || found_nmapping) && (shi->mat->mode & MA_TANGENT_V) != 0) {
- const float fnegdot = -dot_v3v3(shi->vn, shi->tang);
- /* apply Gram-Schmidt projection */
- madd_v3_v3fl(shi->tang, shi->vn, fnegdot);
- normalize_v3(shi->tang);
- }
-}
-
-
-void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_r[3], float *val, Render *re)
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- int tex_nr, rgbnor= 0;
- float co[3], texvec[3];
- float fact, stencilTin=1.0;
-
- if (re->r.scemode & R_NO_TEX) return;
- /* here: test flag if there's a tex (todo) */
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- /* separate tex switching */
- if (shi->mat->septex & (1<<tex_nr)) continue;
-
- if (shi->mat->mtex[tex_nr]) {
- mtex= shi->mat->mtex[tex_nr];
- tex= mtex->tex;
- if (tex == NULL) continue;
-
- /* only process if this texture is mapped
- * to one that we're interested in */
- if (!(mtex->mapto & mapto_flag)) continue;
-
- /* which coords */
- if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- copy_v3_v3(co, xyz);
- if (mtex->texflag & MTEX_OB_DUPLI_ORIG) {
- if (shi->obi && shi->obi->duplitexmat)
- mul_m4_v3(shi->obi->duplitexmat, co);
- }
- mul_m4_v3(ob->imat_ren, co);
-
- if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
- /* use bb vec[0] as min and bb vec[6] as max */
- co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
- co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
- co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
- }
- }
- }
- /* not really orco, but 'local' */
- else if (mtex->texco==TEXCO_ORCO) {
-
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- copy_v3_v3(co, shi->duplilo);
- }
- else {
- Object *ob= shi->obi->ob;
- copy_v3_v3(co, xyz);
- mul_m4_v3(ob->imat_ren, co);
-
- if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
- /* use bb vec[0] as min and bb vec[6] as max */
- co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
- co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
- co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
- }
- }
- }
- else if (mtex->texco==TEXCO_GLOB) {
- copy_v3_v3(co, xyz);
- mul_m4_v3(re->viewinv, co);
- }
- else {
- continue; /* can happen when texco defines disappear and it renders old files */
- }
-
- texres.nor= NULL;
-
- if (tex->type == TEX_IMAGE) {
- continue; /* not supported yet */
- //do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- }
- else {
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
- }
-
- rgbnor = multitex(tex,
- texvec,
- NULL, NULL,
- 0,
- &texres,
- shi->thread,
- mtex->which_output,
- re->pool,
- skip_load_image,
- texnode_preview,
- true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
-
- /* texture output */
-
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgbnor -= TEX_RGB;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
-
-
- if ((mapto_flag & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL))) {
- float tcol[3];
-
- /* stencil maps on the texture control slider, not texture intensity value */
-
- if ((rgbnor & TEX_RGB) == 0) {
- copy_v3_v3(tcol, &mtex->r);
- }
- else if (mtex->mapto & MAP_DENSITY) {
- copy_v3_v3(tcol, &texres.tr);
- if (texres.talpha) {
- texres.tin = stencilTin;
- }
- }
- else {
- copy_v3_v3(tcol, &texres.tr);
- if (texres.talpha) {
- texres.tin= texres.ta;
- }
- }
-
- /* used for emit */
- if ((mapto_flag & MAP_EMISSION_COL) && (mtex->mapto & MAP_EMISSION_COL)) {
- float colemitfac= mtex->colemitfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, colemitfac, mtex->blendtype);
- }
-
- if ((mapto_flag & MAP_REFLECTION_COL) && (mtex->mapto & MAP_REFLECTION_COL)) {
- float colreflfac= mtex->colreflfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, colreflfac, mtex->blendtype);
- }
-
- if ((mapto_flag & MAP_TRANSMISSION_COL) && (mtex->mapto & MAP_TRANSMISSION_COL)) {
- float coltransfac= mtex->coltransfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, coltransfac, mtex->blendtype);
- }
- }
-
- if ((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) {
- /* stencil maps on the texture control slider, not texture intensity value */
-
- /* convert RGB to intensity if intensity info isn't provided */
- if (rgbnor & TEX_RGB) {
- if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- if ((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) {
- float emitfac= mtex->emitfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, emitfac, mtex->blendtype);
- if (*val<0.0f) *val= 0.0f;
- }
- if ((mapto_flag & MAP_DENSITY) && (mtex->mapto & MAP_DENSITY)) {
- float densfac= mtex->densfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, densfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- if ((mapto_flag & MAP_SCATTERING) && (mtex->mapto & MAP_SCATTERING)) {
- float scatterfac= mtex->scatterfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, scatterfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- if ((mapto_flag & MAP_REFLECTION) && (mtex->mapto & MAP_REFLECTION)) {
- float reflfac= mtex->reflfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, reflfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- }
- }
- }
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
-{
- const bool skip_load_image = har->skip_load_image;
- const bool texnode_preview = har->texnode_preview;
- MTex *mtex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float texvec[3], dxt[3], dyt[3], fact, facm, dx;
- int rgb, osatex;
-
- if (R.r.scemode & R_NO_TEX) return;
-
- mtex= har->mat->mtex[0];
- if (har->mat->septex & (1<<0)) return;
- if (mtex->tex==NULL) return;
-
- /* no normal mapping */
- texres.nor= NULL;
-
- texvec[0]= xn/har->rad;
- texvec[1]= yn/har->rad;
- texvec[2]= 0.0;
-
- osatex= (har->mat->texco & TEXCO_OSA);
-
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(texvec[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(texvec[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(texvec[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- if (osatex) {
-
- dx= 1.0f/har->rad;
-
- if (mtex->projx) {
- dxt[0]= mtex->size[0]*dx;
- dyt[0]= mtex->size[0]*dx;
- }
- else dxt[0]= dyt[0]= 0.0;
-
- if (mtex->projy) {
- dxt[1]= mtex->size[1]*dx;
- dyt[1]= mtex->size[1]*dx;
- }
- else dxt[1]= dyt[1]= 0.0;
-
- if (mtex->projz) {
- dxt[2]= 0.0;
- dyt[2]= 0.0;
- }
- else dxt[2]= dyt[2]= 0.0;
-
- }
-
- if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
-
- rgb = multitex(mtex->tex,
- texvec,
- dxt, dyt,
- osatex,
- &texres,
- 0,
- mtex->which_output,
- har->pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
-
- /* mapping */
- if (mtex->mapto & MAP_COL) {
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin= 1.0;
- }
- else texres.tin= texres.ta;
-
- /* inverse gamma correction */
- if (mtex->tex->type==TEX_IMAGE) {
- Image *ima = mtex->tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &mtex->tex->iuser, har->pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, har->pool);
- }
-
- fact= texres.tin*mtex->colfac;
- facm= 1.0f-fact;
-
- if (mtex->blendtype==MTEX_MUL) {
- facm= 1.0f-mtex->colfac;
- }
-
- if (mtex->blendtype==MTEX_SUB) fact= -fact;
-
- if (mtex->blendtype==MTEX_BLEND) {
- col_r[0]= (fact*texres.tr + facm*har->r);
- col_r[1]= (fact*texres.tg + facm*har->g);
- col_r[2]= (fact*texres.tb + facm*har->b);
- }
- else if (mtex->blendtype==MTEX_MUL) {
- col_r[0]= (facm+fact*texres.tr)*har->r;
- col_r[1]= (facm+fact*texres.tg)*har->g;
- col_r[2]= (facm+fact*texres.tb)*har->b;
- }
- else {
- col_r[0]= (fact*texres.tr + har->r);
- col_r[1]= (fact*texres.tg + har->g);
- col_r[2]= (fact*texres.tb + har->b);
-
- CLAMP(col_r[0], 0.0f, 1.0f);
- CLAMP(col_r[1], 0.0f, 1.0f);
- CLAMP(col_r[2], 0.0f, 1.0f);
- }
- }
- if (mtex->mapto & MAP_ALPHA) {
- if (rgb) {
- if (texres.talpha) {
- texres.tin = texres.ta;
- }
- else {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
- }
-
- col_r[3]*= texres.tin;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-/* hor and zen are RGB vectors, blend is 1 float, should all be initialized */
-void do_sky_tex(
- const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
- float hor[3], float zen[3], float *blend, int skyflag, short thread)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float fact, stencilTin=1.0;
- float tempvec[3], texvec[3], dxt[3], dyt[3];
- int tex_nr, rgb= 0;
-
- if (R.r.scemode & R_NO_TEX) return;
- /* todo: add flag to test if there's a tex */
- texres.nor= NULL;
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- if (R.wrld.mtex[tex_nr]) {
- const float *co;
-
- mtex= R.wrld.mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex == NULL) continue;
- /* if (mtex->mapto==0) continue; */
-
- /* which coords */
- co= lo;
-
- /* dxt dyt just from 1 value */
- if (dxyview) {
- dxt[0]= dxt[1]= dxt[2]= dxyview[0];
- dyt[0]= dyt[1]= dyt[2]= dxyview[1];
- }
- else {
- dxt[0]= dxt[1]= dxt[2]= 0.0;
- dyt[0]= dyt[1]= dyt[2]= 0.0;
- }
-
- /* Grab the mapping settings for this texture */
- switch (mtex->texco) {
- case TEXCO_ANGMAP:
- /* only works with texture being "real" */
- /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less than -1.0 */
- if (lo[0] || lo[1]) { /* check for zero case [#24807] */
- fact= (1.0f/(float)M_PI)*saacos(lo[2])/(sqrtf(lo[0]*lo[0] + lo[1]*lo[1]));
- tempvec[0]= lo[0]*fact;
- tempvec[1]= lo[1]*fact;
- tempvec[2]= 0.0;
- }
- else {
- /* this value has no angle, the vector is directly along the view.
- * avoid divide by zero and use a dummy value. */
- tempvec[0]= 1.0f;
- tempvec[1]= 0.0;
- tempvec[2]= 0.0;
- }
- co= tempvec;
- break;
-
- case TEXCO_H_SPHEREMAP:
- case TEXCO_H_TUBEMAP:
- if (skyflag & WO_ZENUP) {
- if (mtex->texco==TEXCO_H_TUBEMAP) map_to_tube( tempvec, tempvec+1, lo[0], lo[2], lo[1]);
- else map_to_sphere(tempvec, tempvec+1, lo[0], lo[2], lo[1]);
- /* tube/spheremap maps for outside view, not inside */
- tempvec[0]= 1.0f-tempvec[0];
- /* only top half */
- tempvec[1]= 2.0f*tempvec[1]-1.0f;
- tempvec[2]= 0.0;
- /* and correction for do_2d_mapping */
- tempvec[0]= 2.0f*tempvec[0]-1.0f;
- tempvec[1]= 2.0f*tempvec[1]-1.0f;
- co= tempvec;
- }
- else {
- /* potentially dangerous... check with multitex! */
- continue;
- }
- break;
- case TEXCO_EQUIRECTMAP:
- tempvec[0]= -atan2f(lo[2], lo[0]) / (float)M_PI;
- tempvec[1]= atan2f(lo[1], hypot(lo[0], lo[2])) / (float)M_PI_2;
- tempvec[2]= 0.0f;
- co= tempvec;
- break;
- case TEXCO_OBJECT:
- if (mtex->object) {
- copy_v3_v3(tempvec, lo);
- mul_m4_v3(mtex->object->imat_ren, tempvec);
- co= tempvec;
- }
- break;
-
- case TEXCO_GLOB:
- if (rco) {
- copy_v3_v3(tempvec, rco);
- mul_m4_v3(R.viewinv, tempvec);
- co= tempvec;
- }
- else
- co= lo;
-
-// copy_v3_v3(shi->dxgl, shi->dxco);
-// mul_m3_v3(R.imat, shi->dxco);
-// copy_v3_v3(shi->dygl, shi->dyco);
-// mul_m3_v3(R.imat, shi->dyco);
- break;
- case TEXCO_VIEW:
- co = view;
- break;
- }
-
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- /* texture */
- if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
-
- rgb = multitex(mtex->tex,
- texvec,
- dxt, dyt,
- R.osa,
- &texres,
- thread,
- mtex->which_output,
- R.pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgb) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- if (rgb) texres.ta *= stencilTin;
- else texres.tin*= stencilTin;
- }
-
- /* color mapping */
- if (mtex->mapto & (WOMAP_HORIZ+WOMAP_ZENUP+WOMAP_ZENDOWN)) {
- float tcol[3];
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else texres.tin= texres.ta;
-
- tcol[0]= texres.tr; tcol[1]= texres.tg; tcol[2]= texres.tb;
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, R.pool);
- }
-
- if (mtex->mapto & WOMAP_HORIZ) {
- texture_rgb_blend(hor, tcol, hor, texres.tin, mtex->colfac, mtex->blendtype);
- }
- if (mtex->mapto & (WOMAP_ZENUP+WOMAP_ZENDOWN)) {
- float zenfac = 0.0f;
-
- if (R.wrld.skytype & WO_SKYREAL) {
- if ((skyflag & WO_ZENUP)) {
- if (mtex->mapto & WOMAP_ZENUP) zenfac= mtex->zenupfac;
- }
- else if (mtex->mapto & WOMAP_ZENDOWN) zenfac= mtex->zendownfac;
- }
- else {
- if (mtex->mapto & WOMAP_ZENUP) zenfac= mtex->zenupfac;
- else if (mtex->mapto & WOMAP_ZENDOWN) zenfac= mtex->zendownfac;
- }
-
- if (zenfac != 0.0f)
- texture_rgb_blend(zen, tcol, zen, texres.tin, zenfac, mtex->blendtype);
- }
- }
- if (mtex->mapto & WOMAP_BLEND) {
- if (rgb) texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
-
- *blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->blendfac, mtex->blendtype);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* col_r supposed to be initialized with la->r,g,b */
-
-void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r[3], int effect)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
- Object *ob;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float *co = NULL, *dx = NULL, *dy = NULL, fact, stencilTin=1.0;
- float texvec[3], dxt[3], dyt[3], tempvec[3];
- int i, tex_nr, rgb= 0;
-
- if (R.r.scemode & R_NO_TEX) return;
- tex_nr= 0;
-
- for (; tex_nr<MAX_MTEX; tex_nr++) {
-
- if (la->mtex[tex_nr]) {
- mtex= la->mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex==NULL) continue;
- texres.nor= NULL;
-
- /* which coords */
- if (mtex->texco==TEXCO_OBJECT) {
- ob= mtex->object;
- if (ob) {
- co= tempvec;
- dx= dxt;
- dy= dyt;
- copy_v3_v3(tempvec, shi->co);
- mul_m4_v3(ob->imat_ren, tempvec);
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxco);
- copy_v3_v3(dyt, shi->dyco);
- mul_mat3_m4_v3(ob->imat_ren, dxt);
- mul_mat3_m4_v3(ob->imat_ren, dyt);
- }
- }
- else {
- co= shi->co;
- dx= shi->dxco; dy= shi->dyco;
- }
- }
- else if (mtex->texco==TEXCO_GLOB) {
- co= shi->gl; dx= shi->dxco; dy= shi->dyco;
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
- }
- else if (mtex->texco==TEXCO_VIEW) {
-
- copy_v3_v3(tempvec, lavec);
- mul_m3_v3(la->imat, tempvec);
-
- if (la->type==LA_SPOT) {
- tempvec[0]*= la->spottexfac;
- tempvec[1]*= la->spottexfac;
- /* project from 3d to 2d */
- tempvec[0] /= -tempvec[2];
- tempvec[1] /= -tempvec[2];
- }
- co= tempvec;
-
- dx= dxt; dy= dyt;
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxlv);
- copy_v3_v3(dyt, shi->dylv);
- /* need some matrix conversion here? la->imat is a [3][3] matrix!!! **/
- mul_m3_v3(la->imat, dxt);
- mul_m3_v3(la->imat, dyt);
-
- mul_v3_fl(dxt, la->spottexfac);
- mul_v3_fl(dyt, la->spottexfac);
- }
- }
-
-
- /* placement */
- if (mtex->projx && co) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy && co) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz && co) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- if (shi->osatex) {
- if (!dx) {
- for (i=0;i<2;i++) {
- dxt[i] = dyt[i] = 0.0;
- }
- }
- else {
- if (mtex->projx) {
- dxt[0]= mtex->size[0]*dx[mtex->projx-1];
- dyt[0]= mtex->size[0]*dy[mtex->projx-1];
- }
- else {
- dxt[0]= 0.0;
- dyt[0]= 0.0;
- }
- if (mtex->projy) {
- dxt[1]= mtex->size[1]*dx[mtex->projy-1];
- dyt[1]= mtex->size[1]*dy[mtex->projy-1];
- }
- else {
- dxt[1]= 0.0;
- dyt[1]= 0.0;
- }
- if (mtex->projz) {
- dxt[2]= mtex->size[2]*dx[mtex->projz-1];
- dyt[2]= mtex->size[2]*dy[mtex->projz-1];
- }
- else {
- dxt[2]= 0.0;
- dyt[2]= 0.0;
- }
- }
- }
-
- /* texture */
- if (tex->type==TEX_IMAGE) {
- do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- }
-
- rgb = multitex(tex,
- texvec,
- dxt, dyt,
- shi->osatex,
- &texres,
- shi->thread,
- mtex->which_output,
- R.pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgb) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- if (rgb) texres.ta*= stencilTin;
- else texres.tin*= stencilTin;
- }
-
- /* mapping */
- if (((mtex->mapto & LAMAP_COL) && (effect & LA_TEXTURE))||((mtex->mapto & LAMAP_SHAD) && (effect & LA_SHAD_TEX))) {
- float col[3];
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin= stencilTin;
- }
- else texres.tin= texres.ta;
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, R.pool);
- }
-
- /* lamp colors were premultiplied with this */
- col[0]= texres.tr*la->energy;
- col[1]= texres.tg*la->energy;
- col[2]= texres.tb*la->energy;
-
- if (effect & LA_SHAD_TEX)
- texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->shadowfac, mtex->blendtype);
- else
- texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype);
- }
- }
- }
-}
-
/* ------------------------------------------------------------------------- */
int externtex(const MTex *mtex,
@@ -3626,7 +1476,7 @@ int externtex(const MTex *mtex,
/* texture */
if (tex->type==TEX_IMAGE) {
- do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
}
rgb = multitex(tex,
@@ -3658,327 +1508,3 @@ int externtex(const MTex *mtex,
return (rgb != 0);
}
-
-/* ------------------------------------------------------------------------- */
-
-void render_realtime_texture(ShadeInput *shi, Image *ima)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- TexResult texr;
- static Tex imatex[BLENDER_MAX_THREADS]; /* threadsafe */
- static int firsttime= 1;
- Tex *tex;
- float texvec[3], dx[2], dy[2];
- ShadeInputUV *suv= &shi->uv[shi->actuv];
- int a;
-
- if (R.r.scemode & R_NO_TEX) return;
-
- if (firsttime) {
- BLI_thread_lock(LOCK_IMAGE);
- if (firsttime) {
- const int num_threads = BLI_system_thread_count();
- for (a = 0; a < num_threads; a++) {
- memset(&imatex[a], 0, sizeof(Tex));
- BKE_texture_default(&imatex[a]);
- imatex[a].type= TEX_IMAGE;
- }
-
- firsttime= 0;
- }
- BLI_thread_unlock(LOCK_IMAGE);
- }
-
- tex= &imatex[shi->thread];
- tex->iuser.ok= ima->ok;
- tex->ima = ima;
-
- texvec[0]= 0.5f+0.5f*suv->uv[0];
- texvec[1]= 0.5f+0.5f*suv->uv[1];
- texvec[2] = 0.0f; /* initalize it because imagewrap looks at it. */
- if (shi->osatex) {
- dx[0]= 0.5f*suv->dxuv[0];
- dx[1]= 0.5f*suv->dxuv[1];
- dy[0]= 0.5f*suv->dyuv[0];
- dy[1]= 0.5f*suv->dyuv[1];
- }
-
- texr.nor= NULL;
-
- if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool, skip_load_image);
- else imagewrap(tex, ima, NULL, texvec, &texr, R.pool, skip_load_image);
-
- shi->vcol[0]*= texr.tr;
- shi->vcol[1]*= texr.tg;
- shi->vcol[2]*= texr.tb;
- shi->vcol[3]*= texr.ta;
-}
-
-/* A modified part of shadeinput.c -> shade_input_set_uv()
- * Used for sampling UV mapped texture color */
-static void textured_face_generate_uv(
- const float normal[3], const float hit[3],
- const float v1[3], const float v2[3], const float v3[3],
- float r_uv[2])
-{
-
- float detsh, t00, t10, t01, t11;
- int axis1, axis2;
-
- /* find most stable axis to project */
- axis_dominant_v3(&axis1, &axis2, normal);
-
- /* compute u,v and derivatives */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
-
- detsh= 1.0f/(t00*t11-t10*t01);
- t00*= detsh; t01*=detsh;
- t10*=detsh; t11*=detsh;
-
- r_uv[0] = (hit[axis1] - v3[axis1]) * t11 - (hit[axis2] - v3[axis2]) * t10;
- r_uv[1] = (hit[axis2] - v3[axis2]) * t00 - (hit[axis1] - v3[axis1]) * t01;
-
- /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
- CLAMP(r_uv[0], -2.0f, 1.0f);
- CLAMP(r_uv[1], -2.0f, 1.0f);
-}
-
-/* Generate an updated copy of material to use for color sampling. */
-Material *RE_sample_material_init(Depsgraph *depsgraph, Material *orig_mat, Scene *scene)
-{
- Tex *tex = NULL;
- Material *mat;
- int tex_nr;
-
- if (!orig_mat) return NULL;
-
- /* copy material */
- mat = BKE_material_localize(orig_mat);
-
- /* update material anims */
- BKE_animsys_evaluate_animdata(scene, &mat->id, mat->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
-
- /* strip material copy from unsupported flags */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
-
- if (mat->mtex[tex_nr]) {
- MTex *mtex = mat->mtex[tex_nr];
-
- /* just in case make all non-used mtexes empty*/
- Tex *cur_tex = mtex->tex;
- mtex->tex = NULL;
-
- if (mat->septex & (1<<tex_nr) || !cur_tex) continue;
-
- /* only keep compatible texflags */
- mtex->texflag = mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE | MTEX_ALPHAMIX);
-
- /* depending of material type, strip non-compatible mapping modes */
- if (mat->material_type == MA_TYPE_SURFACE) {
- if (!ELEM(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) {
- /* ignore this texture */
- mtex->texco = 0;
- continue;
- }
- /* strip all mapto flags except color and alpha */
- mtex->mapto = (mtex->mapto & MAP_COL) | (mtex->mapto & MAP_ALPHA);
- }
- else if (mat->material_type == MA_TYPE_VOLUME) {
- if (!ELEM(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) {
- /* ignore */
- mtex->texco = 0;
- continue;
- }
- /* strip all mapto flags except color and alpha */
- mtex->mapto = mtex->mapto & (MAP_TRANSMISSION_COL | MAP_REFLECTION_COL | MAP_DENSITY);
- }
-
- /* if mapped to an object, calculate inverse matrices */
- if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- invert_m4_m4(ob->imat, ob->obmat);
- copy_m4_m4(ob->imat_ren, ob->imat);
- }
- }
-
- /* copy texture */
- tex= mtex->tex = BKE_texture_localize(cur_tex);
-
- /* update texture anims */
- BKE_animsys_evaluate_animdata(scene, &tex->id, tex->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
-
- /* update texture cache if required */
- if (tex->type==TEX_VOXELDATA) {
- cache_voxeldata(tex, (int)scene->r.cfra);
- }
- if (tex->type==TEX_POINTDENSITY) {
- /* set dummy values for render and do cache */
- Render dummy_re = {NULL};
- dummy_re.scene = scene;
- unit_m4(dummy_re.viewinv);
- unit_m4(dummy_re.viewmat);
- unit_m4(dummy_re.winmat);
- dummy_re.winx = dummy_re.winy = 128;
- cache_pointdensity(depsgraph, &dummy_re, tex->pd);
- }
-
- /* update image sequences and movies */
- if (tex->ima && BKE_image_is_animated(tex->ima)) {
- BKE_image_user_check_frame_calc(&tex->iuser, (int)scene->r.cfra, 0);
- }
- }
- }
- return mat;
-}
-
-/* free all duplicate data allocated by RE_sample_material_init() */
-void RE_sample_material_free(Material *mat)
-{
- int tex_nr;
-
- /* free textures */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- if (mat->septex & (1<<tex_nr)) continue;
- if (mat->mtex[tex_nr]) {
- MTex *mtex= mat->mtex[tex_nr];
-
- if (mtex->tex) {
- /* don't update user counts as we are freeing a duplicate */
- BKE_texture_free(mtex->tex);
- MEM_freeN(mtex->tex);
- mtex->tex = NULL;
- }
- }
- }
-
- /* don't update user counts as we are freeing a duplicate */
- BKE_material_free(mat);
- MEM_freeN(mat);
-}
-
-/*
- * Get material diffuse color and alpha (including linked textures) in given coordinates
- *
- * color,alpha : input/output color values
- * volume_co : sample coordinate in global space. used by volumetric materials
- * surface_co : sample surface coordinate in global space. used by "surface" materials
- * tri_index : surface tri index
- * orcoDm : orco state derived mesh
- */
-void RE_sample_material_color(
- Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
- int tri_index, DerivedMesh *orcoDm, Object *ob)
-{
- int v1, v2, v3;
- MVert *mvert;
- MLoop *mloop;
- const MLoopTri *mlooptri;
- float normal[3];
- ShadeInput shi = {NULL};
- Render re = {NULL};
-
- /* Get face data */
- mvert = orcoDm->getVertArray(orcoDm);
- mloop = orcoDm->getLoopArray(orcoDm);
- mlooptri = orcoDm->getLoopTriArray(orcoDm);
-
- if (!mvert || !mlooptri || !mat) {
- return;
- }
-
- v1 = mloop[mlooptri[tri_index].tri[0]].v;
- v2 = mloop[mlooptri[tri_index].tri[1]].v;
- v3 = mloop[mlooptri[tri_index].tri[2]].v;
- normal_tri_v3(normal, mvert[v1].co, mvert[v2].co, mvert[v3].co);
-
- /* generate shadeinput with data required */
- shi.mat = mat;
-
- /* fill shadeinput data depending on material type */
- if (mat->material_type == MA_TYPE_SURFACE) {
- /* global coordinates */
- copy_v3_v3(shi.gl, surface_co);
- /* object space coordinates */
- copy_v3_v3(shi.co, surface_co);
- mul_m4_v3(ob->imat, shi.co);
- /* orco coordinates */
- {
- float uv[2];
- float l;
- /* Get generated UV */
- textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv);
- l= 1.0f+uv[0]+uv[1];
-
- /* calculate generated coordinate */
- shi.lo[0]= l*mvert[v3].co[0]-uv[0]*mvert[v1].co[0]-uv[1]*mvert[v2].co[0];
- shi.lo[1]= l*mvert[v3].co[1]-uv[0]*mvert[v1].co[1]-uv[1]*mvert[v2].co[1];
- shi.lo[2]= l*mvert[v3].co[2]-uv[0]*mvert[v1].co[2]-uv[1]*mvert[v2].co[2];
- }
- /* uv coordinates */
- {
- const int layers = CustomData_number_of_layers(&orcoDm->loopData, CD_MLOOPUV);
- const int layer_index = CustomData_get_layer_index(&orcoDm->loopData, CD_MLOOPUV);
- int i;
-
- /* for every uv map set coords and name */
- for (i=0; i<layers; i++) {
- if (layer_index >= 0) {
- const float *uv1, *uv2, *uv3;
- const CustomData *data = &orcoDm->loopData;
- const MLoopUV *mloopuv = data->layers[layer_index + i].data;
- float uv[2];
- float l;
-
- /* point layer name from actual layer data */
- shi.uv[i].name = data->layers[i].name;
- /* Get generated coordinates to calculate UV from */
- textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv);
- /* Get UV mapping coordinate */
- l= 1.0f+uv[0]+uv[1];
-
- uv1 = mloopuv[mlooptri[tri_index].tri[0]].uv;
- uv2 = mloopuv[mlooptri[tri_index].tri[1]].uv;
- uv3 = mloopuv[mlooptri[tri_index].tri[2]].uv;
-
- shi.uv[i].uv[0]= -1.0f + 2.0f*(l*uv3[0]-uv[0]*uv1[0]-uv[1]*uv2[0]);
- shi.uv[i].uv[1]= -1.0f + 2.0f*(l*uv3[1]-uv[0]*uv1[1]-uv[1]*uv2[1]);
- shi.uv[i].uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
- }
- }
- /* active uv map */
- shi.actuv = CustomData_get_active_layer_index(&orcoDm->loopData, CD_MLOOPUV) - layer_index;
- shi.totuv = layers;
- }
-
- /* apply initial values from material */
- shi.r = mat->r;
- shi.g = mat->g;
- shi.b = mat->b;
- shi.alpha = mat->alpha;
-
- /* do texture */
- do_material_tex(&shi, &re);
-
- /* apply result */
- color[0] = shi.r;
- color[1] = shi.g;
- color[2] = shi.b;
- *alpha = shi.alpha;
- }
- else if (mat->material_type == MA_TYPE_VOLUME) {
- ObjectInstanceRen obi = {NULL};
- obi.ob = ob;
- shi.obi = &obi;
- unit_m4(re.viewinv);
- copy_v3_v3(color, mat->vol.reflection_col);
- *alpha = mat->vol.density;
-
- /* do texture */
- do_volume_tex(&shi, volume_co, (MAP_TRANSMISSION_COL | MAP_REFLECTION_COL | MAP_DENSITY),
- color, alpha, &re);
- }
-}
-
-/* eof */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
deleted file mode 100644
index c9072105dd9..00000000000
--- a/source/blender/render/intern/source/rendercore.c
+++ /dev/null
@@ -1,2028 +0,0 @@
-/*
- * ***** 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: Hos, Robert Wenzlaff.
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/rendercore.c
- * \ingroup render
- */
-
-
-/* system includes */
-#include <stdio.h>
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <assert.h>
-
-/* External modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_image_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-#include "DNA_group_types.h"
-
-/* local include */
-#include "renderpipeline.h"
-#include "render_result.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "occlusion.h"
-#include "pixelblending.h"
-#include "pixelshading.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "sss.h"
-#include "zbuf.h"
-
-/* own include */
-#include "rendercore.h"
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* x and y are current pixels in rect to be rendered */
-/* do not normalize! */
-void calc_view_vector(float view[3], float x, float y)
-{
-
- view[2]= -ABS(R.clipsta);
-
- if (R.r.mode & R_ORTHO) {
- view[0]= view[1]= 0.0f;
- }
- else {
-
- if (R.r.mode & R_PANORAMA) {
- x-= R.panodxp;
- }
-
- /* move x and y to real viewplane coords */
- x = (x / (float)R.winx);
- view[0] = R.viewplane.xmin + x * BLI_rctf_size_x(&R.viewplane);
-
- y = (y / (float)R.winy);
- view[1] = R.viewplane.ymin + y * BLI_rctf_size_y(&R.viewplane);
-
-// if (R.flag & R_SEC_FIELD) {
-// if (R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor;
-// else view[1]= (y+R.ystart+1.0)*R.ycor;
-// }
-// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor;
-
- if (R.r.mode & R_PANORAMA) {
- float u= view[0] + R.panodxv; float v= view[2];
- view[0]= R.panoco*u + R.panosi*v;
- view[2]= -R.panosi*u + R.panoco*v;
- }
- }
-}
-
-void calc_renderco_ortho(float co[3], float x, float y, int z)
-{
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx= 2.0f/(R.winx*R.winmat[0][0]);
- float fy= 2.0f/(R.winy*R.winmat[1][1]);
- float zco;
-
- co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
- co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
-
- zco= ((float)z)/2147483647.0f;
- co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
-}
-
-void calc_renderco_zbuf(float co[3], const float view[3], int z)
-{
- float fac, zco;
-
- /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
- zco= ((float)z)/2147483647.0f;
- co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
-
- fac= co[2]/view[2];
- co[0]= fac*view[0];
- co[1]= fac*view[1];
-}
-
-/* also used in zbuf.c and shadbuf.c */
-int count_mask(unsigned short mask)
-{
- if (R.samples)
- return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]);
- return 0;
-}
-
-static int calchalo_z(HaloRen *har, int zz)
-{
-
- if (har->type & HA_ONLYSKY) {
- if (zz < 0x7FFFFFF0) zz= - 0x7FFFFF; /* edge render messes zvalues */
- }
- else {
- zz= (zz>>8);
- }
- return zz;
-}
-
-
-
-static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, int od, float dist, float xn, float yn, PixStr *ps)
-{
- float col[4], accol[4], fac;
- int amount, amountm, zz, flarec, sample, fullsample, mask=0;
-
- fullsample= (totsample > 1);
- amount= 0;
- accol[0] = accol[1] = accol[2] = accol[3]= 0.0f;
- col[0] = col[1] = col[2] = col[3]= 0.0f;
- flarec= har->flarec;
-
- while (ps) {
- amountm= count_mask(ps->mask);
- amount+= amountm;
-
- zz= calchalo_z(har, ps->z);
- if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
- if (shadeHaloFloat(har, col, zz, dist, xn, yn, flarec)) {
- flarec= 0;
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (ps->mask & (1 << sample)) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
- }
- else {
- fac= ((float)amountm)/(float)R.osa;
- accol[0]+= fac*col[0];
- accol[1]+= fac*col[1];
- accol[2]+= fac*col[2];
- accol[3]+= fac*col[3];
- }
- }
- }
-
- mask |= ps->mask;
- ps= ps->next;
- }
-
- /* now do the sky sub-pixels */
- amount= R.osa-amount;
- if (amount) {
- if (shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec)) {
- if (!fullsample) {
- fac= ((float)amount)/(float)R.osa;
- accol[0]+= fac*col[0];
- accol[1]+= fac*col[1];
- accol[2]+= fac*col[2];
- accol[3]+= fac*col[3];
- }
- }
- }
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (!(mask & (1 << sample))) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
- }
- else {
- col[0]= accol[0];
- col[1]= accol[1];
- col[2]= accol[2];
- col[3]= accol[3];
-
- for (sample=0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
-}
-
-static void halo_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- HaloRen *har;
- rcti disprect= pa->disprect, testrect= pa->disprect;
- float dist, xsq, ysq, xn, yn;
- float col[4];
- intptr_t *rd= NULL;
- int a, *rz, zz, y, sample, totsample, od;
- short minx, maxx, miny, maxy, x;
- unsigned int lay= (1 << 20) - 1;
-
- /* we don't render halos in the cropped area, gives errors in flare counter */
- if (pa->crop) {
- testrect.xmin+= pa->crop;
- testrect.xmax-= pa->crop;
- testrect.ymin+= pa->crop;
- testrect.ymax-= pa->crop;
- }
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (a=0; a<R.tothalo; a++) {
- har= R.sortedhalos[a];
-
- /* layer test, clip halo with y */
- if ((har->lay & lay) == 0) {
- /* pass */
- }
- else if (testrect.ymin > har->maxy) {
- /* pass */
- }
- else if (testrect.ymax < har->miny) {
- /* pass */
- }
- else {
-
- minx= floor(har->xs-har->rad);
- maxx= ceil(har->xs+har->rad);
-
- if (testrect.xmin > maxx) {
- /* pass */
- }
- else if (testrect.xmax < minx) {
- /* pass */
- }
- else {
-
- minx = max_ii(minx, testrect.xmin);
- maxx = min_ii(maxx, testrect.xmax);
-
- miny = max_ii(har->miny, testrect.ymin);
- maxy = min_ii(har->maxy, testrect.ymax);
-
- for (y=miny; y<maxy; y++) {
- int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin);
- rz= pa->rectz + rectofs;
- od= rectofs;
-
- if (pa->rectdaps)
- rd= pa->rectdaps + rectofs;
-
- yn= (y-har->ys)*R.ycor;
- ysq= yn*yn;
-
- for (x=minx; x<maxx; x++, rz++, od++) {
- xn= x- har->xs;
- xsq= xn*xn;
- dist= xsq+ysq;
- if (dist<har->radsq) {
- if (rd && *rd) {
- halo_pixelstruct(har, rlpp, totsample, od, dist, xn, yn, (PixStr *)*rd);
- }
- else {
- zz= calchalo_z(har, *rz);
- if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
- if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
- for (sample=0; sample<totsample; sample++) {
- float * rect= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(rect + od*4, col, har->add);
- }
- }
- }
- }
- }
- if (rd) rd++;
- }
- }
- }
- }
- if (R.test_break(R.tbh) ) break;
- }
-}
-
-static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- ShadeInput shi;
- float *pass;
- float fac, col[4];
- intptr_t *rd= pa->rectdaps;
- const int *rz= pa->rectz;
- int x, y, sample, totsample, fullsample, od;
-
- totsample= get_sample_layers(pa, rl, rlpp);
- fullsample= (totsample > 1);
-
- shade_input_initialize(&shi, pa, rl, 0); /* this zero's ShadeInput for us */
-
- for (od=0, y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, od++) {
-
- calc_view_vector(shi.view, x, y);
-
- if (rd && *rd) {
- PixStr *ps= (PixStr *)*rd;
- int count, totsamp= 0, mask= 0;
-
- while (ps) {
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z);
- else
- calc_renderco_zbuf(shi.co, shi.view, ps->z);
-
- totsamp+= count= count_mask(ps->mask);
- mask |= ps->mask;
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (ps->mask & (1 << sample)) {
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- fac= ((float)count)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= fac*col[0];
- pass[1]+= fac*col[1];
- pass[2]+= fac*col[2];
- pass[3]+= fac*col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
-
- ps= ps->next;
- }
-
- if (totsamp<R.osa) {
- shi.co[2]= 0.0f;
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (!(mask & (1 << sample))) {
-
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= fac*col[0];
- pass[1]+= fac*col[1];
- pass[2]+= fac*col[2];
- pass[3]+= fac*col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(shi.co, (float)x, (float)y, *rz);
- else
- calc_renderco_zbuf(shi.co, shi.view, *rz);
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- for (sample=0; sample<totsample; sample++) {
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
-
- if (rd) rd++;
- }
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-}
-
-
-/* ********************* MAINLOOPS ******************** */
-
-/* osa version */
-static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *fp, *col= NULL;
- int pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
- add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
- /* box filter only, gauss will screwup UV too much */
- if (shi->totuv) {
- float mult = (float)count_mask(curmask)/(float)R.osa;
- fp = rpass->rect + 3*offset;
- fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]);
- fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]);
- fp[2]+= mult;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- /* no filter */
- if (shi->vlr) {
- fp = rpass->rect + offset;
- if (*fp==0.0f)
- *fp = (float)shi->obr->ob->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- /* no filter */
- if (shi->vlr) {
- fp = rpass->rect + offset;
- if (*fp==0.0f)
- *fp = (float)shi->mat->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- /* */
- col = &shr->mist;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- /* add minimum speed in pixel, no filter */
- fp = rpass->rect + 4*offset;
- if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0] = shr->winspeed[0];
- fp[1] = shr->winspeed[1];
- }
- if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2] = shr->winspeed[2];
- fp[3] = shr->winspeed[3];
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
- /* */
- col = shr->rayhits;
- pixsize= 4;
- }
-
- if (col) {
- fp= rpass->rect + pixsize*offset;
- add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize);
- }
- }
-}
-
-/* non-osa version */
-static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr)
-{
- RenderPass *rpass;
- float *fp;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col= NULL, uvcol[3];
- int a, pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
- /* copy combined to use for preview */
- copy_v4_v4(rpass->rect + 4*offset, shr->combined);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
- if (shi->totuv) {
- uvcol[0] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[0];
- uvcol[1] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[1];
- uvcol[2] = 1.0f;
- col = uvcol;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- col = shr->winspeed;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- if (shi->vlr) {
- fp = rpass->rect + offset;
- *fp = (float)shi->obr->ob->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- if (shi->vlr) {
- fp = rpass->rect + offset;
- *fp = (float)shi->mat->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- fp = rpass->rect + offset;
- *fp = shr->mist;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
- col = shr->rayhits;
- pixsize = 4;
- }
-
- if (col) {
- fp = rpass->rect + pixsize*offset;
- for (a=0; a<pixsize; a++)
- fp[a] = col[a];
- }
- }
-}
-
-int get_sample_layers(RenderPart *pa, RenderLayer *rl, RenderLayer **rlpp)
-{
-
- if (pa->fullresult.first) {
- int sample, nr= BLI_findindex(&pa->result->layers, rl);
-
- for (sample=0; sample<R.osa; sample++) {
- RenderResult *rr= BLI_findlink(&pa->fullresult, sample);
-
- rlpp[sample]= BLI_findlink(&rr->layers, nr);
- }
- return R.osa;
- }
- else {
- rlpp[0]= rl;
- return 1;
- }
-}
-
-
-/* only do sky, is default in the solid layer (shade_tile) btw */
-static void sky_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- int x, y, od=0, totsample;
-
- if (R.r.alphamode!=R_ADDSKY)
- return;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od+=4) {
- float col[4];
- int sample;
- bool done = false;
-
- for (sample= 0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od;
-
- if (pass[3]<1.0f) {
-
- if (done==0) {
- shadeSkyPixel(col, x, y, pa->thread);
- done = true;
- }
-
- if (pass[3]==0.0f) {
- copy_v4_v4(pass, col);
- pass[3] = 1.0f;
- }
- else {
- addAlphaUnderFloat(pass, col);
- pass[3] = 1.0f;
- }
- }
- }
- }
-
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-}
-
-static void atm_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderPass *zpass;
- GroupObject *go;
- LampRen *lar;
- RenderLayer *rlpp[RE_MAX_OSA];
- int totsample;
- int x, y, od= 0;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- /* check that z pass is enabled */
- if (pa->rectz==NULL) return;
- for (zpass= rl->passes.first; zpass; zpass= zpass->next)
- if (STREQ(zpass->name, RE_PASSNAME_Z))
- break;
-
- if (zpass==NULL) return;
-
- /* check for at least one sun lamp that its atmosphere flag is enabled */
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_AP))
- break;
- }
- /* do nothign and return if there is no sun lamp */
- if (go==NULL)
- return;
-
- /* for each x,y and each sample, and each sun lamp*/
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od++) {
- int sample;
-
- for (sample=0; sample<totsample; sample++) {
- const float *zrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_Z, R.viewname) + od;
- float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname) + 4*od;
- float rgb[3] = {0};
- bool done = false;
-
- for (go=R.lights.first; go; go= go->next) {
-
-
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky) {
-
- /* if it's sky continue and don't apply atmosphere effect on it */
- if (*zrect >= 9.9e10f || rgbrect[3]==0.0f) {
- continue;
- }
-
- if ((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) {
- float tmp_rgb[3];
-
- /* skip if worldspace lamp vector is below horizon */
- if (go->ob->obmat[2][2] < 0.f) {
- continue;
- }
-
- copy_v3_v3(tmp_rgb, rgbrect);
- if (rgbrect[3]!=1.0f) { /* de-premul */
- mul_v3_fl(tmp_rgb, 1.0f/rgbrect[3]);
- }
- shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect);
- if (rgbrect[3]!=1.0f) { /* premul */
- mul_v3_fl(tmp_rgb, rgbrect[3]);
- }
-
- if (done==0) {
- copy_v3_v3(rgb, tmp_rgb);
- done = true;
- }
- else {
- rgb[0] = 0.5f*rgb[0] + 0.5f*tmp_rgb[0];
- rgb[1] = 0.5f*rgb[1] + 0.5f*tmp_rgb[1];
- rgb[2] = 0.5f*rgb[2] + 0.5f*tmp_rgb[2];
- }
- }
- }
- }
-
- /* if at least for one sun lamp aerial perspective was applied*/
- if (done) {
- copy_v3_v3(rgbrect, rgb);
- }
- }
- }
- }
-}
-
-static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderResult *rr= pa->result;
- ShadeSample ssamp;
- intptr_t *rd, *rectdaps= pa->rectdaps;
- int samp;
- int x, y, seed, crop=0, offs=0, od;
-
- if (R.test_break(R.tbh)) return;
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-
- /* we set per pixel a fixed seed, for random AO and shadow samples */
- seed= pa->rectx*pa->disprect.ymin;
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
-
- /* occlusion caching */
- if (R.occlusiontree)
- cache_occ_samples(&R, pa, &ssamp);
-
- /* filtered render, for now we assume only 1 filter size */
- if (pa->crop) {
- crop= 1;
- rectdaps+= pa->rectx + 1;
- offs= pa->rectx + 1;
- }
-
- /* scanline updates have to be 2 lines behind */
- rr->renrect.ymin = 0;
- rr->renrect.ymax = -2*crop;
- rr->renlay= rl;
-
- for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- rd= rectdaps;
- od= offs;
-
- for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, od++) {
- BLI_thread_srandom(pa->thread, seed++);
-
- if (*rd) {
- if (shade_samples(&ssamp, (PixStr *)(*rd), x, y)) {
-
- /* multisample buffers or filtered mask filling? */
- if (pa->fullresult.first) {
- int a;
- for (samp=0; samp<ssamp.tot; samp++) {
- int smask= ssamp.shi[samp].mask;
- for (a=0; a<R.osa; a++) {
- int mask= 1<<a;
- if (smask & mask)
- add_passes(ssamp.rlpp[a], od, &ssamp.shi[samp], &ssamp.shr[samp]);
- }
- }
- }
- else {
- for (samp=0; samp<ssamp.tot; samp++)
- add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, &ssamp.shi[samp], &ssamp.shr[samp]);
- }
- }
- }
- }
-
- rectdaps+= pa->rectx;
- offs+= pa->rectx;
-
- if (y&1) if (R.test_break(R.tbh)) break;
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
-
- if (R.occlusiontree)
- free_occ_samples(&R, pa);
-}
-
-/* ************* pixel struct ******** */
-
-
-static PixStrMain *addpsmain(ListBase *lb)
-{
- PixStrMain *psm;
-
- psm= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain), "pixstrMain");
- BLI_addtail(lb, psm);
-
- psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr), "pixstr");
- psm->counter= 0;
-
- return psm;
-}
-
-static void freeps(ListBase *lb)
-{
- PixStrMain *psm, *psmnext;
-
- for (psm= lb->first; psm; psm= psmnext) {
- psmnext= psm->next;
- if (psm->ps)
- MEM_freeN(psm->ps);
- MEM_freeN(psm);
- }
- BLI_listbase_clear(lb);
-}
-
-static void addps(ListBase *lb, intptr_t *rd, int obi, int facenr, int z, int maskz, unsigned short mask)
-{
- PixStrMain *psm;
- PixStr *ps, *last= NULL;
-
- if (*rd) {
- ps= (PixStr *)(*rd);
-
- while (ps) {
- if ( ps->obi == obi && ps->facenr == facenr ) {
- ps->mask |= mask;
- return;
- }
- last= ps;
- ps= ps->next;
- }
- }
-
- /* make new PS (pixel struct) */
- psm= lb->last;
-
- if (psm->counter==4095)
- psm= addpsmain(lb);
-
- ps= psm->ps + psm->counter++;
-
- if (last) last->next= ps;
- else *rd= (intptr_t)ps;
-
- ps->next= NULL;
- ps->obi= obi;
- ps->facenr= facenr;
- ps->z= z;
- ps->maskz= maskz;
- ps->mask = mask;
- ps->shadfac= 0;
-}
-
-static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
-{
- float addcol[4];
- int pix;
-
- if (arect==NULL)
- return;
-
- for (pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) {
- if (*arect != 0.0f) {
- addcol[0]= *arect * R.r.edgeR;
- addcol[1]= *arect * R.r.edgeG;
- addcol[2]= *arect * R.r.edgeB;
- addcol[3]= *arect;
- addAlphaOverFloat(rectf, addcol);
- }
- }
-}
-
-/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
-static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- int y, sample, totsample;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- /* not for full sample, there we clamp after compositing */
- if (totsample > 1)
- return;
-
- for (sample= 0; sample<totsample; sample++) {
- float *rectf = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
-
- for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
- rectf[0] = MAX2(rectf[0], 0.0f);
- rectf[1] = MAX2(rectf[1], 0.0f);
- rectf[2] = MAX2(rectf[2], 0.0f);
- CLAMP(rectf[3], 0.0f, 1.0f);
- }
- }
-}
-
-/* adds only alpha values */
-static void edge_enhance_tile(RenderPart *pa, float *rectf, int *rectz)
-{
- /* use zbuffer to define edges, add it to the image */
- int y, x, col, *rz, *rz1, *rz2, *rz3;
- int zval1, zval2, zval3;
- float *rf;
-
- /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */
- rz= rectz;
- if (rz==NULL) return;
-
- for (y=0; y<pa->recty; y++)
- for (x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4;
-
- rz1= rectz;
- rz2= rz1+pa->rectx;
- rz3= rz2+pa->rectx;
-
- rf= rectf+pa->rectx+1;
-
- for (y=0; y<pa->recty-2; y++) {
- for (x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) {
-
- /* prevent overflow with sky z values */
- zval1= rz1[0] + 2*rz1[1] + rz1[2];
- zval2= 2*rz2[0] + 2*rz2[2];
- zval3= rz3[0] + 2*rz3[1] + rz3[2];
-
- col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 );
- if (col<0) col= -col;
-
- col >>= 5;
- if (col > (1<<16)) col= (1<<16);
- else col= (R.r.edgeint*col)>>8;
-
- if (col>0) {
- float fcol;
-
- if (col>255) fcol= 1.0f;
- else fcol= (float)col/255.0f;
-
- if (R.osa)
- *rf+= fcol/(float)R.osa;
- else
- *rf= fcol;
- }
- }
- rz1+= 2;
- rz2+= 2;
- rz3+= 2;
- rf+= 2;
- }
-
- /* shift back zbuf values, we might need it still */
- rz= rectz;
- for (y=0; y<pa->recty; y++)
- for (x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4;
-
-}
-
-static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
-{
- /* for all pixels with max speed, set to zero */
- RenderLayer *rlpp[RE_MAX_OSA];
- float *fp;
- int a, sample, totsample;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (sample= 0; sample<totsample; sample++) {
- fp= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_VECTOR, R.viewname);
- if (fp==NULL) break;
-
- for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
- if (fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f;
- }
-}
-
-static unsigned short *make_solid_mask(RenderPart *pa)
-{
- intptr_t *rd= pa->rectdaps;
- unsigned short *solidmask, *sp;
- int x;
-
- if (rd==NULL) return NULL;
-
- sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask");
-
- for (x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) {
- if (*rd) {
- PixStr *ps= (PixStr *)*rd;
-
- *sp= ps->mask;
- for (ps= ps->next; ps; ps= ps->next)
- *sp |= ps->mask;
- }
- else
- *sp= 0;
- }
-
- return solidmask;
-}
-
-static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask)
-{
- unsigned short shared= dmask & smask;
- float mul= 1.0f - source[3];
-
- if (shared) { /* overlapping masks */
-
- /* masks differ, we make a mixture of 'add' and 'over' */
- if (shared!=dmask) {
- float shared_bits= (float)count_mask(shared); /* alpha over */
- float tot_bits= (float)count_mask(smask|dmask); /* alpha add */
-
- float add= (tot_bits - shared_bits)/tot_bits; /* add level */
- mul= add + (1.0f-add)*mul;
- }
- }
- else if (dmask && smask) {
- /* works for premul only, of course */
- dest[0]+= source[0];
- dest[1]+= source[1];
- dest[2]+= source[2];
- dest[3]+= source[3];
-
- return;
- }
-
- dest[0]= (mul*dest[0]) + source[0];
- dest[1]= (mul*dest[1]) + source[1];
- dest[2]= (mul*dest[2]) + source[2];
- dest[3]= (mul*dest[3]) + source[3];
-}
-
-typedef struct ZbufSolidData {
- RenderLayer *rl;
- ListBase *psmlist;
- float *edgerect;
-} ZbufSolidData;
-
-static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data)
-{
- ZbufSolidData *sdata = (ZbufSolidData *)data;
- ListBase *lb= sdata->psmlist;
- intptr_t *rd= pa->rectdaps;
- const int *ro= zspan->recto;
- const int *rp= zspan->rectp;
- const int *rz= zspan->rectz;
- const int *rm= zspan->rectmask;
- int x, y;
- int mask= 1<<sample;
-
- for (y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, rd++, rp++, ro++, rz++, rm++) {
- if (*rp) {
- addps(lb, rd, *ro, *rp, *rz, (zspan->rectmask)? *rm: 0, mask);
- }
- }
- }
-
- if (sdata->rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_tile(pa, sdata->edgerect, zspan->rectz);
-}
-
-/* main call for shading Delta Accum, for OSA */
-/* supposed to be fully threadable! */
-void zbufshadeDA_tile(RenderPart *pa)
-{
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- ListBase psmlist= {NULL, NULL};
- float *edgerect= NULL;
-
- /* allocate the necessary buffers */
- /* zbuffer inits these rects */
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
-
- if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
- pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
-
- /* initialize pixelstructs and edge buffer */
- addpsmain(&psmlist);
- pa->rectdaps= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "zbufDArectd");
-
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
-
- /* always fill visibility */
- for (pa->sample=0; pa->sample<R.osa; pa->sample+=4) {
- ZbufSolidData sdata;
-
- sdata.rl= rl;
- sdata.psmlist= &psmlist;
- sdata.edgerect= edgerect;
- zbuffer_solid(pa, rl, make_pixelstructs, &sdata);
- if (R.test_break(R.tbh)) break;
- }
-
- /* shades solid */
- if (rl->layflag & SCE_LAY_SOLID)
- shadeDA_tile(pa, rl);
-
- /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
- if (R.flag & R_LAMPHALO)
- if (rl->layflag & SCE_LAY_HALO)
- lamphalo_tile(pa, rl);
-
- /* halo before ztra, because ztra fills in zbuffer now */
- if (R.flag & R_HALO)
- if (rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl);
-
- /* transp layer */
- if (R.flag & R_ZTRA || R.totstrand) {
- if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
- if (pa->fullresult.first) {
- zbuffer_transp_shade(pa, rl, rect, &psmlist);
- }
- else {
- unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
-
- /* swap for live updates, and it is used in zbuf.c!!! */
- SWAP(float *, rl->acolrect, rect);
- ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist);
- SWAP(float *, rl->acolrect, rect);
-
- /* zbuffer transp only returns ztramask if there's solid rendered */
- if (ztramask)
- solidmask= make_solid_mask(pa);
-
- if (ztramask && solidmask) {
- unsigned short *sps= solidmask, *spz= ztramask;
- unsigned short fullmask= (1<<R.osa)-1;
- float *fcol= rect;
- float *acol= rl->acolrect;
- int x;
-
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
- if (*sps == fullmask)
- addAlphaOverFloat(fcol, acol);
- else
- addAlphaOverFloatMask(fcol, acol, *sps, *spz);
- }
- }
- else {
- float *fcol= rect;
- float *acol= rl->acolrect;
- int x;
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
- addAlphaOverFloat(fcol, acol);
- }
- }
- if (solidmask) MEM_freeN(solidmask);
- if (ztramask) MEM_freeN(ztramask);
- }
- }
- }
-
- /* sun/sky */
- if (rl->layflag & SCE_LAY_SKY)
- atm_tile(pa, rl);
-
- /* sky before edge */
- if (rl->layflag & SCE_LAY_SKY)
- sky_tile(pa, rl);
-
- /* extra layers */
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rect, edgerect);
-
- if (rl->passflag & SCE_PASS_VECTOR)
- reset_sky_speed(pa, rl);
-
- /* clamp alpha to 0..1 range, can go outside due to filter */
- clamp_alpha_rgb_range(pa, rl);
-
- /* free stuff within loop! */
- MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
- freeps(&psmlist);
-
- if (edgerect) MEM_freeN(edgerect);
- edgerect= NULL;
-
- if (pa->rectmask) {
- MEM_freeN(pa->rectmask);
- pa->rectmask= NULL;
- }
- }
-
- /* free all */
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->rectz); pa->rectz= NULL;
-
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/* non OSA case, full tile render */
-/* supposed to be fully threadable! */
-void zbufshade_tile(RenderPart *pa)
-{
- ShadeSample ssamp;
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- PixStr ps;
- float *edgerect= NULL;
-
- /* fake pixel struct, to comply to osa render */
- ps.next= NULL;
- ps.mask= 0xFFFF;
-
- /* zbuffer code clears/inits rects */
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
-
- for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
- pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
-
- zbuffer_solid(pa, rl, NULL, NULL);
-
- if (!R.test_break(R.tbh)) { /* NOTE: this if () is not consistent */
-
- /* edges only for solid part, ztransp doesn't support it yet anti-aliased */
- if (rl->layflag & SCE_LAY_EDGE) {
- if (R.r.mode & R_EDGE) {
- edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
- edge_enhance_tile(pa, edgerect, pa->rectz);
- }
- }
-
- /* initialize scanline updates for main thread */
- rr->renrect.ymin = 0;
- rr->renlay= rl;
-
- if (rl->layflag & SCE_LAY_SOLID) {
- const float *fcol = rect;
- const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz;
- int x, y, offs=0, seed;
-
- /* we set per pixel a fixed seed, for random AO and shadow samples */
- seed= pa->rectx*pa->disprect.ymin;
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-
- if (R.occlusiontree)
- cache_occ_samples(&R, pa, &ssamp);
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ro++, rz++, rp++, fcol+=4, offs++) {
- /* per pixel fixed seed */
- BLI_thread_srandom(pa->thread, seed++);
-
- if (*rp) {
- ps.obi= *ro;
- ps.facenr= *rp;
- ps.z= *rz;
- if (shade_samples(&ssamp, &ps, x, y)) {
- /* combined and passes */
- add_passes(rl, offs, ssamp.shi, ssamp.shr);
- }
- }
- }
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-
- if (R.occlusiontree)
- free_occ_samples(&R, pa);
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
- }
-
- /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
- if (R.flag & R_LAMPHALO)
- if (rl->layflag & SCE_LAY_HALO)
- lamphalo_tile(pa, rl);
-
- /* halo before ztra, because ztra fills in zbuffer now */
- if (R.flag & R_HALO)
- if (rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl);
-
- if (R.flag & R_ZTRA || R.totstrand) {
- if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
- float *fcol, *acol;
- int x;
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
-
- /* swap for live updates */
- SWAP(float *, rl->acolrect, rect);
- zbuffer_transp_shade(pa, rl, rect, NULL);
- SWAP(float *, rl->acolrect, rect);
-
- fcol= rect; acol= rl->acolrect;
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
- addAlphaOverFloat(fcol, acol);
- }
- }
- }
-
- /* sun/sky */
- if (rl->layflag & SCE_LAY_SKY)
- atm_tile(pa, rl);
-
- /* sky before edge */
- if (rl->layflag & SCE_LAY_SKY)
- sky_tile(pa, rl);
-
- if (!R.test_break(R.tbh)) {
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rect, edgerect);
- }
-
- if (rl->passflag & SCE_PASS_VECTOR)
- reset_sky_speed(pa, rl);
-
- if (edgerect) MEM_freeN(edgerect);
- edgerect= NULL;
-
- if (pa->rectmask) {
- MEM_freeN(pa->rectmask);
- pa->rectmask= NULL;
- }
- }
-
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
-
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->rectz); pa->rectz= NULL;
-}
-
-/* SSS preprocess tile render, fully threadable */
-typedef struct ZBufSSSHandle {
- RenderPart *pa;
- ListBase psmlist;
- int totps;
-} ZBufSSSHandle;
-
-static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z)
-{
- ZBufSSSHandle *handle = cb_handle;
- RenderPart *pa= handle->pa;
-
- /* extra border for filter gives double samples on part edges,
- * don't use those */
- if (x<pa->crop || x>=pa->rectx-pa->crop)
- return;
- if (y<pa->crop || y>=pa->recty-pa->crop)
- return;
-
- if (pa->rectall) {
- intptr_t *rs= pa->rectall + pa->rectx*y + x;
-
- addps(&handle->psmlist, rs, obi, facenr, z, 0, 0);
- handle->totps++;
- }
- if (pa->rectz) {
- int *rz= pa->rectz + pa->rectx*y + x;
- int *rp= pa->rectp + pa->rectx*y + x;
- int *ro= pa->recto + pa->rectx*y + x;
-
- if (z < *rz) {
- if (*rp == 0)
- handle->totps++;
- *rz= z;
- *rp= facenr;
- *ro= obi;
- }
- }
- if (pa->rectbackz) {
- int *rz= pa->rectbackz + pa->rectx*y + x;
- int *rp= pa->rectbackp + pa->rectx*y + x;
- int *ro= pa->rectbacko + pa->rectx*y + x;
-
- if (z >= *rz) {
- if (*rp == 0)
- handle->totps++;
- *rz= z;
- *rp= facenr;
- *ro= obi;
- }
- }
-}
-
-static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRen *obi, VlakRen *vlr, int quad, float x, float y, float z, float *co, float color[3], float *area)
-{
- ShadeInput *shi= ssamp->shi;
- ShadeResult shr;
- float /* texfac,*/ /* UNUSED */ orthoarea, nor[3], alpha, sx, sy;
-
- /* cache for shadow */
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
-
- if (quad)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* center pixel */
- sx = x + 0.5f;
- sy = y + 0.5f;
-
- /* we estimate the area here using shi->dxco and shi->dyco. we need to
- * enabled shi->osatex these are filled. we compute two areas, one with
- * the normal pointed at the camera and one with the original normal, and
- * then clamp to avoid a too large contribution from a single pixel */
- shi->osatex= 1;
-
- copy_v3_v3(nor, shi->facenor);
- calc_view_vector(shi->facenor, sx, sy);
- normalize_v3(shi->facenor);
- shade_input_set_viewco(shi, x, y, sx, sy, z);
- orthoarea= len_v3(shi->dxco)*len_v3(shi->dyco);
-
- copy_v3_v3(shi->facenor, nor);
- shade_input_set_viewco(shi, x, y, sx, sy, z);
- *area = min_ff(len_v3(shi->dxco) * len_v3(shi->dyco), 2.0f * orthoarea);
-
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
-
- /* we don't want flipped normals, they screw up back scattering */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- /* not a pretty solution, but fixes common cases */
- if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- }
-
- /* if nodetree, use the material that we are currently preprocessing
- * instead of the node material */
- if (shi->mat->nodetree && shi->mat->use_nodes)
- shi->mat= mat;
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* render */
- shade_input_set_shade_texco(shi);
-
- shade_samples_do_AO(ssamp);
- shade_material_loop(shi, &shr);
-
- copy_v3_v3(co, shi->co);
- copy_v3_v3(color, shr.combined);
-
- /* texture blending */
- /* texfac= shi->mat->sss_texfac; */ /* UNUSED */
-
- alpha= shr.combined[3];
- *area *= alpha;
-}
-
-static void zbufshade_sss_free(RenderPart *pa)
-{
-#if 0
- MEM_freeN(pa->rectall); pa->rectall= NULL;
- freeps(&handle.psmlist);
-#else
- MEM_freeN(pa->rectz); pa->rectz= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectbackz); pa->rectbackz= NULL;
- MEM_freeN(pa->rectbackp); pa->rectbackp= NULL;
- MEM_freeN(pa->rectbacko); pa->rectbacko= NULL;
-#endif
-}
-
-void zbufshade_sss_tile(RenderPart *pa)
-{
- Render *re= &R;
- ShadeSample ssamp;
- ZBufSSSHandle handle;
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- VlakRen *vlr;
- Material *mat= re->sss_mat;
- float (*co)[3], (*color)[3], *area, *fcol;
- int x, y, seed, quad, totpoint;
- const bool display = (re->r.scemode & (R_BUTS_PREVIEW | R_VIEWPORT_PREVIEW)) == 0;
- int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay;
-#if 0
- PixStr *ps;
- intptr_t *rs;
- int z;
-#endif
-
- /* setup pixelstr list and buffer for zbuffering */
- handle.pa= pa;
- handle.totps= 0;
-
-#if 0
- handle.psmlist.first= handle.psmlist.last= NULL;
- addpsmain(&handle.psmlist);
-
- pa->rectall= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "rectall");
-#else
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- pa->rectbacko= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbacko");
- pa->rectbackp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackp");
- pa->rectbackz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackz");
-#endif
-
- /* setup shade sample with correct passes */
- memset(&ssamp, 0, sizeof(ssamp));
- shade_sample_initialize(&ssamp, pa, rr->layers.first);
- ssamp.tot= 1;
-
- for (rl=rr->layers.first; rl; rl=rl->next) {
- ssamp.shi[0].lay |= (1 << 20) - 1;
- ssamp.shi[0].layflag |= rl->layflag;
- ssamp.shi[0].passflag |= rl->passflag;
- ssamp.shi[0].combinedflag |= ~rl->pass_xor;
- }
-
- rl= rr->layers.first;
- ssamp.shi[0].passflag |= SCE_PASS_RGBA|SCE_PASS_COMBINED;
- ssamp.shi[0].combinedflag &= ~(SCE_PASS_SPEC);
- lay= ssamp.shi[0].lay;
-
- /* create the pixelstrs to be used later */
- zbuffer_sss(pa, lay, &handle, addps_sss);
-
- if (handle.totps==0) {
- zbufshade_sss_free(pa);
- return;
- }
-
- fcol= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
-
- co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
- color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
- area= MEM_mallocN(sizeof(float)*handle.totps, "SSSArea");
-
-#if 0
- /* create ISB (does not work currently!) */
- if (re->r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-#endif
-
- if (display) {
- /* initialize scanline updates for main thread */
- rr->renrect.ymin = 0;
- rr->renlay= rl;
- }
-
- seed= pa->rectx*pa->disprect.ymin;
-#if 0
- rs= pa->rectall;
-#else
- rz= pa->rectz;
- rp= pa->rectp;
- ro= pa->recto;
- rbz= pa->rectbackz;
- rbp= pa->rectbackp;
- rbo= pa->rectbacko;
-#endif
- totpoint= 0;
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, fcol+=4) {
- /* per pixel fixed seed */
- BLI_thread_srandom(pa->thread, seed++);
-
-#if 0
- if (rs) {
- /* for each sample in this pixel, shade it */
- for (ps = (PixStr *)(*rs); ps; ps=ps->next) {
- ObjectInstanceRen *obi= &re->objectinstance[ps->obi];
- ObjectRen *obr= obi->obr;
- vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
- quad= (ps->facenr & RE_QUAD_OFFS);
- z= ps->z;
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, z,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- totpoint++;
-
- add_v3_v3(fcol, color);
- fcol[3]= 1.0f;
- }
-
- rs++;
- }
-#else
- if (rp) {
- if (*rp != 0) {
- ObjectInstanceRen *obi= &re->objectinstance[*ro];
- ObjectRen *obr= obi->obr;
-
- /* shade front */
- vlr= RE_findOrAddVlak(obr, (*rp-1) & RE_QUAD_MASK);
- quad= ((*rp) & RE_QUAD_OFFS);
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rz,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- add_v3_v3(fcol, color[totpoint]);
- fcol[3]= 1.0f;
- totpoint++;
- }
-
- rp++; rz++; ro++;
- }
-
- if (rbp) {
- if (*rbp != 0 && !(*rbp == *(rp-1) && *rbo == *(ro-1))) {
- ObjectInstanceRen *obi= &re->objectinstance[*rbo];
- ObjectRen *obr= obi->obr;
-
- /* shade back */
- vlr= RE_findOrAddVlak(obr, (*rbp-1) & RE_QUAD_MASK);
- quad= ((*rbp) & RE_QUAD_OFFS);
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rbz,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- /* to indicate this is a back sample */
- area[totpoint]= -area[totpoint];
-
- add_v3_v3(fcol, color[totpoint]);
- fcol[3]= 1.0f;
- totpoint++;
- }
-
- rbz++; rbp++; rbo++;
- }
-#endif
- }
-
- if (y&1)
- if (re->test_break(re->tbh)) break;
- }
-
- /* note: after adding we do not free these arrays, sss keeps them */
- if (totpoint > 0) {
- sss_add_points(re, co, color, area, totpoint);
- }
- else {
- MEM_freeN(co);
- MEM_freeN(color);
- MEM_freeN(area);
- }
-
-#if 0
- if (re->r.mode & R_SHADOW)
- ISB_free(pa);
-#endif
-
- if (display) {
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
- }
-
- zbufshade_sss_free(pa);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* postprocess version */
-{
- float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf;
- float haloxs, haloys;
- int minx, maxx, miny, maxy, x, y;
-
- /* calculate the disprect mapped coordinate for halo. note: rectx is disprect corrected */
- haloxs= har->xs - R.disprect.xmin;
- haloys= har->ys - R.disprect.ymin;
-
- har->miny= miny= haloys - har->rad/R.ycor;
- har->maxy= maxy= haloys + har->rad/R.ycor;
-
- if (maxy < 0) {
- /* pass */
- }
- else if (rr->recty < miny) {
- /* pass */
- }
- else {
- minx = floor(haloxs - har->rad);
- maxx = ceil(haloxs + har->rad);
-
- if (maxx < 0) {
- /* pass */
- }
- else if (rr->rectx < minx) {
- /* pass */
- }
- else {
- if (minx<0) minx= 0;
- if (maxx>=rr->rectx) maxx= rr->rectx-1;
- if (miny<0) miny= 0;
- if (maxy>rr->recty) maxy= rr->recty;
-
- rectft= rectf+ 4*rr->rectx*miny;
-
- for (y=miny; y<maxy; y++) {
-
- rtf= rectft+4*minx;
-
- yn= (y - haloys)*R.ycor;
- ysq= yn*yn;
-
- for (x=minx; x<=maxx; x++) {
- xn= x - haloxs;
- xsq= xn*xn;
- dist= xsq+ysq;
- if (dist<har->radsq) {
-
- if (shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec))
- addalphaAddfacFloat(rtf, colf, har->add);
- }
- rtf+=4;
- }
-
- rectft+= 4*rr->rectx;
-
- if (R.test_break(R.tbh)) break;
- }
- }
- }
-}
-/* ------------------------------------------------------------------------ */
-
-static void renderflare(RenderResult *rr, float *rectf, HaloRen *har)
-{
- extern const float hashvectf[];
- HaloRen fla;
- Material *ma;
- const float *rc;
- float rad, alfa, visifac, vec[3];
- int b, type;
-
- fla= *har;
- fla.linec= fla.ringc= fla.flarec= 0;
-
- rad= har->rad;
- alfa= har->alfa;
-
- visifac= R.ycor*(har->pixels);
- /* all radials added / r^3 == 1.0f! */
- visifac /= (har->rad*har->rad*har->rad);
- visifac*= visifac;
-
- ma= har->mat;
-
- /* first halo: just do */
-
- har->rad= rad*ma->flaresize*visifac;
- har->radsq= har->rad*har->rad;
- har->zs= fla.zs= 0;
-
- har->alfa= alfa*visifac;
-
- renderhalo_post(rr, rectf, har);
-
- /* next halo's: the flares */
- rc= hashvectf + ma->seed2;
-
- for (b=1; b<har->flarec; b++) {
-
- fla.r = fabsf(rc[0]);
- fla.g = fabsf(rc[1]);
- fla.b = fabsf(rc[2]);
- fla.alfa= ma->flareboost*fabsf(alfa*visifac*rc[3]);
- fla.hard= 20.0f + fabsf(70.0f*rc[7]);
- fla.tex= 0;
-
- type= (int)(fabsf(3.9f*rc[6]));
-
- fla.rad = ma->subsize * sqrtf(fabsf(2.0f * har->rad * rc[4]));
-
- if (type==3) {
- fla.rad*= 3.0f;
- fla.rad+= R.rectx/10;
- }
-
- fla.radsq= fla.rad*fla.rad;
-
- vec[0]= 1.4f*rc[5]*(har->xs-R.winx/2);
- vec[1]= 1.4f*rc[5]*(har->ys-R.winy/2);
- vec[2]= 32.0f*sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f);
-
- fla.xs= R.winx/2 + vec[0] + (1.2f+rc[8])*R.rectx*vec[0]/vec[2];
- fla.ys= R.winy/2 + vec[1] + (1.2f+rc[8])*R.rectx*vec[1]/vec[2];
-
- if (R.flag & R_SEC_FIELD) {
- if (R.r.mode & R_ODDFIELD) fla.ys += 0.5f;
- else fla.ys -= 0.5f;
- }
- if (type & 1) fla.type= HA_FLARECIRC;
- else fla.type= 0;
- renderhalo_post(rr, rectf, &fla);
-
- fla.alfa*= 0.5f;
- if (type & 2) fla.type= HA_FLARECIRC;
- else fla.type= 0;
- renderhalo_post(rr, rectf, &fla);
-
- rc+= 7;
- }
-}
-
-/* needs recode... integrate this better! */
-void add_halo_flare(Render *re)
-{
- RenderResult *rr= re->result;
- RenderLayer *rl;
- HaloRen *har;
- int a, mode;
- float *rect;
-
- /* for now, we get the first renderlayer in list with halos set */
- for (rl= rr->layers.first; rl; rl= rl->next) {
- bool do_draw = false;
-
- if ((rl->layflag & SCE_LAY_HALO) == 0)
- continue;
-
- rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
-
- if (rect==NULL)
- continue;
-
- mode= R.r.mode;
- R.r.mode &= ~R_PANORAMA;
-
- project_renderdata(&R, projectverto, 0, 0, 0);
-
- for (a=0; a<R.tothalo; a++) {
- har= R.sortedhalos[a];
-
- if (har->flarec && (har->lay & ((1 << 20) - 1))) {
- do_draw = true;
- renderflare(rr, rect, har);
- }
- }
-
- if (do_draw) {
- /* weak... the display callback wants an active renderlayer pointer... */
- rr->renlay= rl;
- re->display_update(re->duh, rr, NULL);
- }
-
- R.r.mode= mode;
- }
-}
-
-void render_internal_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
-{
- int type;
-
- RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
-
-#define CHECK_PASS(name, channels, chanid) \
- if (view_layer->passflag & (SCE_PASS_ ## name)) { \
- if (channels == 4) type = SOCK_RGBA; \
- else if (channels == 3) type = SOCK_VECTOR; \
- else type = SOCK_FLOAT; \
- RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_ ## name, channels, chanid, type); \
- }
-
- CHECK_PASS(Z, 1, "Z");
- CHECK_PASS(VECTOR, 4, "XYZW");
- CHECK_PASS(NORMAL, 3, "XYZ");
- CHECK_PASS(UV, 3, "UVA");
- CHECK_PASS(RGBA, 4, "RGBA");
- CHECK_PASS(EMIT, 3, "RGB");
- CHECK_PASS(DIFFUSE, 3, "RGB");
- CHECK_PASS(SPEC, 3, "RGB");
- CHECK_PASS(AO, 3, "RGB");
- CHECK_PASS(ENVIRONMENT, 3, "RGB");
- CHECK_PASS(INDIRECT, 3, "RGB");
- CHECK_PASS(SHADOW, 3, "RGB");
- CHECK_PASS(REFLECT, 3, "RGB");
- CHECK_PASS(REFRACT, 3, "RGB");
- CHECK_PASS(INDEXOB, 1, "X");
- CHECK_PASS(INDEXMA, 1, "X");
- CHECK_PASS(MIST, 1, "Z");
-
-#undef CHECK_PASS
-}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
deleted file mode 100644
index 2fbfcc64c8f..00000000000
--- a/source/blender/render/intern/source/renderdatabase.c
+++ /dev/null
@@ -1,1603 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/renderdatabase.c
- * \ingroup render
- */
-
-
-/*
- * Storage, retrieval and query of render specific data.
- *
- * All data from a Blender scene is converted by the renderconverter/
- * into a special format that is used by the render module to make
- * images out of. These functions interface to the render-specific
- * database.
- *
- * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data
- * entries each.
- *
- * The index of an entry is >>8 (the highest 24 * bits), to find an
- * offset in a 256-entry block.
- *
- * - If the 256-entry block entry has an entry in the
- * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in
- * that block is allocated to this entry.
- *
- * - If the entry has no block allocated for it yet, memory is
- * allocated.
- *
- * The pointer to the correct entry is returned. Memory is guaranteed
- * to exist (as long as the malloc does not break). Since guarded
- * allocation is used, memory _must_ be available. Otherwise, an
- * exit(0) would occur.
- *
- */
-
-#include <limits.h>
-#include <math.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_hash.h"
-
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_listBase.h"
-#include "DNA_particle_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-
-#include "RE_render_ext.h" /* externtex */
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "zbuf.h"
-
-/* ------------------------------------------------------------------------- */
-
-/* More dynamic allocation of options for render vertices and faces, so we don't
- * have to reserve this space inside vertices.
- * Important; vertices and faces, should have been created already (to get tables
- * checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
- * the index */
-
-/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
-#define RE_STRESS_ELEMS 1
-#define RE_RAD_ELEMS 4
-#define RE_STRAND_ELEMS 1
-#define RE_TANGENT_ELEMS 3
-#define RE_WINSPEED_ELEMS 4
-#define RE_MTFACE_ELEMS 1
-#define RE_MCOL_ELEMS 4
-#define RE_UV_ELEMS 2
-#define RE_VLAK_ORIGINDEX_ELEMS 1
-#define RE_VERT_ORIGINDEX_ELEMS 1
-#define RE_SURFNOR_ELEMS 3
-#define RE_RADFACE_ELEMS 1
-#define RE_SIMPLIFY_ELEMS 2
-#define RE_FACE_ELEMS 1
-#define RE_NMAP_TANGENT_ELEMS 16
-
-float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *stress;
- int nr= ver->index>>8;
-
- stress= obr->vertnodes[nr].stress;
- if (stress==NULL) {
- if (verify)
- stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
- else
- return NULL;
- }
- return stress + (ver->index & 255)*RE_STRESS_ELEMS;
-}
-
-/* this one callocs! */
-float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *rad;
- int nr= ver->index>>8;
-
- rad= obr->vertnodes[nr].rad;
- if (rad==NULL) {
- if (verify)
- rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
- else
- return NULL;
- }
- return rad + (ver->index & 255)*RE_RAD_ELEMS;
-}
-
-float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *strand;
- int nr= ver->index>>8;
-
- strand= obr->vertnodes[nr].strand;
- if (strand==NULL) {
- if (verify)
- strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
- else
- return NULL;
- }
- return strand + (ver->index & 255)*RE_STRAND_ELEMS;
-}
-
-/* needs calloc */
-float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *tangent;
- int nr= ver->index>>8;
-
- tangent= obr->vertnodes[nr].tangent;
- if (tangent==NULL) {
- if (verify)
- tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
- else
- return NULL;
- }
- return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
-}
-
-/* needs calloc! not all renderverts have them */
-/* also winspeed is exception, it is stored per instance */
-float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify)
-{
- float *winspeed;
- int totvector;
-
- winspeed= obi->vectors;
- if (winspeed==NULL) {
- if (verify) {
- totvector= obi->obr->totvert + obi->obr->totstrand;
- winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
- }
- else
- return NULL;
- }
- return winspeed + ver->index*RE_WINSPEED_ELEMS;
-}
-
-int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify)
-{
- int *origindex;
- int nr= ver->index>>8;
-
- origindex= obr->vertnodes[nr].origindex;
- if (origindex==NULL) {
- if (verify)
- origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
- else
- return NULL;
- }
- return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS;
-}
-
-VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
-{
- VertRen *v1= RE_findOrAddVert(obr, obr->totvert++);
- float *fp1, *fp2;
- int *int1, *int2;
- int index= v1->index;
-
- *v1= *ver;
- v1->index= index;
-
- fp1= RE_vertren_get_stress(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_stress(obr, v1, 1);
- memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_rad(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_rad(obr, v1, 1);
- memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_strand(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_strand(obr, v1, 1);
- memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_tangent(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_tangent(obr, v1, 1);
- memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
- }
- int1= RE_vertren_get_origindex(obr, ver, 0);
- if (int1) {
- int2= RE_vertren_get_origindex(obr, v1, 1);
- memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int));
- }
- return v1;
-}
-
-VertRen *RE_findOrAddVert(ObjectRen *obr, int nr)
-{
- VertTableNode *temp;
- VertRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddVert: %d\n", nr);
- return NULL;
- }
- a= nr>>8;
-
- if (a>=obr->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->vertnodes;
-
- obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE), "vertnodes");
- if (temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode));
- memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
-
- obr->vertnodeslen+=TABLEINITSIZE;
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->vertnodes[a].vert;
- if (v==NULL) {
- int i;
-
- v= (VertRen *)MEM_callocN(256*sizeof(VertRen), "findOrAddVert");
- obr->vertnodes[a].vert= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
- v[a].index= i;
- }
- }
- v+= (nr & 255);
- return v;
-}
-
-/* ------------------------------------------------------------------------ */
-
-MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
-{
- VlakTableNode *node;
- int nr= vlr->index>>8, vlakindex= (vlr->index&255);
- int index= (n<<8) + vlakindex;
-
- node= &obr->vlaknodes[nr];
-
- if (verify) {
- if (n>=node->totmtface) {
- MTFace *mtface= node->mtface;
- int size= (n+1)*256;
-
- node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface");
-
- if (mtface) {
- size= node->totmtface*256;
- memcpy(node->mtface, mtface, size*sizeof(MTFace));
- MEM_freeN(mtface);
- }
-
- node->totmtface= n+1;
- }
- }
- else {
- if (n>=node->totmtface)
- return NULL;
-
- if (name) *name= obr->mtface[n];
- }
-
- return node->mtface + index;
-}
-
-MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
-{
- VlakTableNode *node;
- int nr= vlr->index>>8, vlakindex= (vlr->index&255);
- int index= (n<<8) + vlakindex;
-
- node= &obr->vlaknodes[nr];
-
- if (verify) {
- if (n>=node->totmcol) {
- MCol *mcol= node->mcol;
- int size= (n+1)*256;
-
- node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol");
-
- if (mcol) {
- size= node->totmcol*256;
- memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
- MEM_freeN(mcol);
- }
-
- node->totmcol= n+1;
- }
- }
- else {
- if (n>=node->totmcol)
- return NULL;
-
- if (name) *name= obr->mcol[n];
- }
-
- return node->mcol + index*RE_MCOL_ELEMS;
-}
-
-int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- int *origindex;
- int nr= vlak->index>>8;
-
- origindex= obr->vlaknodes[nr].origindex;
- if (origindex==NULL) {
- if (verify)
- origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
- else
- return NULL;
- }
- return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS;
-}
-
-float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- float *surfnor;
- int nr= vlak->index>>8;
-
- surfnor= obr->vlaknodes[nr].surfnor;
- if (surfnor==NULL) {
- if (verify)
- surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
- else
- return NULL;
- }
- return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
-}
-
-float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
-{
- float **tangents;
- int nr= vlak->index>>8;
-
- tangents = obr->vlaknodes[nr].tangent_arrays;
-
- if (index + 1 > 8) {
- return NULL;
- }
-
- index = index < 0 ? 0: index;
-
- if (tangents[index] == NULL) {
- if (verify) {
- tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
- }
- else
- return NULL;
- }
-
- return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
-}
-
-RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- RadFace **radface;
- int nr= vlak->index>>8;
-
- radface= obr->vlaknodes[nr].radface;
- if (radface==NULL) {
- if (verify)
- radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table");
- else
- return NULL;
- }
- return radface + (vlak->index & 255)*RE_RADFACE_ELEMS;
-}
-
-VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
-{
- VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
- MTFace *mtface, *mtface1;
- MCol *mcol, *mcol1;
- float *surfnor, *surfnor1;
- float *tangent, *tangent1;
- int *origindex, *origindex1;
- RadFace **radface, **radface1;
- int i, index = vlr1->index;
- char *name;
-
- *vlr1= *vlr;
- vlr1->index= index;
-
- for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) {
- mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1);
- memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
- }
-
- for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) {
- mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1);
- memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
- }
-
- origindex= RE_vlakren_get_origindex(obr, vlr, 0);
- if (origindex) {
- origindex1= RE_vlakren_get_origindex(obr, vlr1, 1);
- /* Just an int, but memcpy for consistency. */
- memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS);
- }
-
- surfnor= RE_vlakren_get_surfnor(obr, vlr, 0);
- if (surfnor) {
- surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1);
- copy_v3_v3(surfnor1, surfnor);
- }
-
- for (i=0; i < MAX_MTFACE; i++) {
- tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
- if (!tangent)
- continue;
- tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
- memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
- }
-
- radface= RE_vlakren_get_radface(obr, vlr, 0);
- if (radface) {
- radface1= RE_vlakren_get_radface(obr, vlr1, 1);
- *radface1= *radface;
- }
-
- return vlr1;
-}
-
-void RE_vlakren_get_normal(Render *UNUSED(re), ObjectInstanceRen *obi, VlakRen *vlr, float r_nor[3])
-{
- float (*nmat)[3]= obi->nmat;
-
- if (obi->flag & R_TRANSFORMED) {
- mul_v3_m3v3(r_nor, nmat, vlr->n);
- normalize_v3(r_nor);
- }
- else {
- copy_v3_v3(r_nor, vlr->n);
- }
-}
-
-void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
-{
- /* CustomData layer names are stored per object here, because the
- * DerivedMesh which stores the layers is freed */
-
- CustomDataLayer *layer;
- int numtf = 0, numcol = 0, i, mtfn, mcn;
-
- if (CustomData_has_layer(data, CD_MTFACE)) {
- numtf= CustomData_number_of_layers(data, CD_MTFACE);
- obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames");
- }
-
- if (CustomData_has_layer(data, CD_MCOL)) {
- numcol= CustomData_number_of_layers(data, CD_MCOL);
- obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames");
- }
-
- for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
- layer= &data->layers[i];
-
- if (layer->type == CD_MTFACE) {
- BLI_strncpy(obr->mtface[mtfn++], layer->name, sizeof(layer->name));
- obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf);
- obr->bakemtface= layer->active;
- }
- else if (layer->type == CD_MCOL) {
- BLI_strncpy(obr->mcol[mcn++], layer->name, sizeof(layer->name));
- obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol);
- }
- }
-}
-
-VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr)
-{
- VlakTableNode *temp;
- VlakRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddVlak: %d\n", nr);
- return obr->vlaknodes[0].vlak;
- }
- a= nr>>8;
-
- if (a>=obr->vlaknodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->vlaknodes;
-
- obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE), "vlaknodes");
- if (temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode));
- memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
-
- obr->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->vlaknodes[a].vlak;
-
- if (v==NULL) {
- int i;
-
- v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen), "findOrAddVlak");
- obr->vlaknodes[a].vlak= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
- v[a].index= i;
- }
- v+= (nr & 255);
- return v;
-}
-
-/* ------------------------------------------------------------------------ */
-
-float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify)
-{
- float *surfnor;
- int nr= strand->index>>8;
-
- surfnor= obr->strandnodes[nr].surfnor;
- if (surfnor==NULL) {
- if (verify)
- surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table");
- else
- return NULL;
- }
- return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
-}
-
-float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
-{
- StrandTableNode *node;
- int nr= strand->index>>8, strandindex= (strand->index&255);
- int index= (n<<8) + strandindex;
-
- node= &obr->strandnodes[nr];
-
- if (verify) {
- if (n>=node->totuv) {
- float *uv= node->uv;
- int size= (n+1)*256;
-
- node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table");
-
- if (uv) {
- size= node->totuv*256;
- memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS);
- MEM_freeN(uv);
- }
-
- node->totuv= n+1;
- }
- }
- else {
- if (n>=node->totuv)
- return NULL;
-
- if (name) *name= obr->mtface[n];
- }
-
- return node->uv + index*RE_UV_ELEMS;
-}
-
-MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
-{
- StrandTableNode *node;
- int nr= strand->index>>8, strandindex= (strand->index&255);
- int index= (n<<8) + strandindex;
-
- node= &obr->strandnodes[nr];
-
- if (verify) {
- if (n>=node->totmcol) {
- MCol *mcol= node->mcol;
- int size= (n+1)*256;
-
- node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table");
-
- if (mcol) {
- size= node->totmcol*256;
- memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
- MEM_freeN(mcol);
- }
-
- node->totmcol= n+1;
- }
- }
- else {
- if (n>=node->totmcol)
- return NULL;
-
- if (name) *name= obr->mcol[n];
- }
-
- return node->mcol + index*RE_MCOL_ELEMS;
-}
-
-float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify)
-{
- float *simplify;
- int nr= strand->index>>8;
-
- simplify= obr->strandnodes[nr].simplify;
- if (simplify==NULL) {
- if (verify)
- simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table");
- else
- return NULL;
- }
- return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
-}
-
-int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify)
-{
- int *face;
- int nr= strand->index>>8;
-
- face= obr->strandnodes[nr].face;
- if (face==NULL) {
- if (verify)
- face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table");
- else
- return NULL;
- }
- return face + (strand->index & 255)*RE_FACE_ELEMS;
-}
-
-/* winspeed is exception, it is stored per instance */
-float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
-{
- float *winspeed;
- int totvector;
-
- winspeed= obi->vectors;
- if (winspeed==NULL) {
- if (verify) {
- totvector= obi->obr->totvert + obi->obr->totstrand;
- winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table");
- }
- else
- return NULL;
- }
- return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS;
-}
-
-StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr)
-{
- StrandTableNode *temp;
- StrandRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddStrand: %d\n", nr);
- return obr->strandnodes[0].strand;
- }
- a= nr>>8;
-
- if (a>=obr->strandnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->strandnodes;
-
- obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE), "strandnodes");
- if (temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode));
- memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
-
- obr->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->strandnodes[a].strand;
-
- if (v==NULL) {
- int i;
-
- v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen), "findOrAddStrand");
- obr->strandnodes[a].strand= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
- v[a].index= i;
- }
- v+= (nr & 255);
- return v;
-}
-
-StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
-{
- StrandBuffer *strandbuf;
-
- strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
- strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
- strandbuf->totvert= totvert;
- strandbuf->obr= obr;
-
- obr->strandbuf= strandbuf;
-
- return strandbuf;
-}
-
-/* ------------------------------------------------------------------------ */
-
-ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay)
-{
- ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct");
-
- BLI_addtail(&re->objecttable, obr);
- obr->ob= ob;
- obr->par= par;
- obr->index= index;
- obr->psysindex= psysindex;
- obr->lay= lay;
-
- return obr;
-}
-
-void free_renderdata_vertnodes(VertTableNode *vertnodes)
-{
- int a;
-
- if (vertnodes==NULL) return;
-
- for (a=0; vertnodes[a].vert; a++) {
- MEM_freeN(vertnodes[a].vert);
-
- if (vertnodes[a].rad)
- MEM_freeN(vertnodes[a].rad);
- if (vertnodes[a].strand)
- MEM_freeN(vertnodes[a].strand);
- if (vertnodes[a].tangent)
- MEM_freeN(vertnodes[a].tangent);
- if (vertnodes[a].stress)
- MEM_freeN(vertnodes[a].stress);
- if (vertnodes[a].winspeed)
- MEM_freeN(vertnodes[a].winspeed);
- if (vertnodes[a].origindex)
- MEM_freeN(vertnodes[a].origindex);
- }
-
- MEM_freeN(vertnodes);
-}
-
-void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
-{
- int a;
-
- if (vlaknodes==NULL) return;
-
- for (a=0; vlaknodes[a].vlak; a++) {
- MEM_freeN(vlaknodes[a].vlak);
-
- if (vlaknodes[a].mtface)
- MEM_freeN(vlaknodes[a].mtface);
- if (vlaknodes[a].mcol)
- MEM_freeN(vlaknodes[a].mcol);
- if (vlaknodes[a].origindex)
- MEM_freeN(vlaknodes[a].origindex);
- if (vlaknodes[a].surfnor)
- MEM_freeN(vlaknodes[a].surfnor);
- for (int b = 0; b < MAX_MTFACE; b++) {
- if (vlaknodes[a].tangent_arrays[b])
- MEM_freeN(vlaknodes[a].tangent_arrays[b]);
- }
- if (vlaknodes[a].radface)
- MEM_freeN(vlaknodes[a].radface);
- }
-
- MEM_freeN(vlaknodes);
-}
-
-static void free_renderdata_strandnodes(StrandTableNode *strandnodes)
-{
- int a;
-
- if (strandnodes==NULL) return;
-
- for (a=0; strandnodes[a].strand; a++) {
- MEM_freeN(strandnodes[a].strand);
-
- if (strandnodes[a].uv)
- MEM_freeN(strandnodes[a].uv);
- if (strandnodes[a].mcol)
- MEM_freeN(strandnodes[a].mcol);
- if (strandnodes[a].winspeed)
- MEM_freeN(strandnodes[a].winspeed);
- if (strandnodes[a].surfnor)
- MEM_freeN(strandnodes[a].surfnor);
- if (strandnodes[a].simplify)
- MEM_freeN(strandnodes[a].simplify);
- if (strandnodes[a].face)
- MEM_freeN(strandnodes[a].face);
- }
-
- MEM_freeN(strandnodes);
-}
-
-void free_renderdata_tables(Render *re)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- StrandBuffer *strandbuf;
- int a=0;
-
- for (obr=re->objecttable.first; obr; obr=obr->next) {
- if (obr->vertnodes) {
- free_renderdata_vertnodes(obr->vertnodes);
- obr->vertnodes= NULL;
- obr->vertnodeslen= 0;
- }
-
- if (obr->vlaknodes) {
- free_renderdata_vlaknodes(obr->vlaknodes);
- obr->vlaknodes= NULL;
- obr->vlaknodeslen= 0;
- obr->totvlak= 0;
- }
-
- if (obr->bloha) {
- for (a=0; obr->bloha[a]; a++)
- MEM_freeN(obr->bloha[a]);
-
- MEM_freeN(obr->bloha);
- obr->bloha= NULL;
- obr->blohalen= 0;
- }
-
- if (obr->strandnodes) {
- free_renderdata_strandnodes(obr->strandnodes);
- obr->strandnodes= NULL;
- obr->strandnodeslen= 0;
- }
-
- strandbuf= obr->strandbuf;
- if (strandbuf) {
- if (strandbuf->vert) MEM_freeN(strandbuf->vert);
- if (strandbuf->bound) MEM_freeN(strandbuf->bound);
- MEM_freeN(strandbuf);
- }
-
- if (obr->mtface)
- MEM_freeN(obr->mtface);
-
- if (obr->mcol)
- MEM_freeN(obr->mcol);
-
- if (obr->rayfaces) {
- MEM_freeN(obr->rayfaces);
- obr->rayfaces = NULL;
- }
-
- if (obr->rayprimitives) {
- MEM_freeN(obr->rayprimitives);
- obr->rayprimitives = NULL;
- }
-
- if (obr->raytree) {
- RE_rayobject_free(obr->raytree);
- obr->raytree = NULL;
- }
- }
-
- if (re->objectinstance) {
- for (obi=re->instancetable.first; obi; obi=obi->next) {
- if (obi->vectors)
- MEM_freeN(obi->vectors);
-
- if (obi->raytree)
- RE_rayobject_free(obi->raytree);
- }
-
- MEM_freeN(re->objectinstance);
- re->objectinstance= NULL;
- re->totinstance= 0;
- re->instancetable.first= re->instancetable.last= NULL;
- }
-
- if (re->sortedhalos) {
- MEM_freeN(re->sortedhalos);
- re->sortedhalos= NULL;
- }
-
- BLI_freelistN(&re->customdata_names);
- BLI_freelistN(&re->objecttable);
- BLI_freelistN(&re->instancetable);
-}
-
-/* ------------------------------------------------------------------------ */
-
-HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr)
-{
- HaloRen *h, **temp;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddHalo: %d\n", nr);
- return NULL;
- }
- a= nr>>8;
-
- if (a>=obr->blohalen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- //printf("Allocating %i more halo groups. %i total.\n",
- // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE );
- temp=obr->bloha;
-
- obr->bloha = (HaloRen **)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha");
- if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *));
- memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *));
- obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- h= obr->bloha[a];
- if (h==NULL) {
- h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen), "findOrAdHalo");
- obr->bloha[a]= h;
- }
- h+= (nr & 255);
- return h;
-}
-
-/* ------------------------------------------------------------------------- */
-
-HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, float hasize, float vectsize, int seed)
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- HaloRen *har;
- MTex *mtex;
- float tin, tr, tg, tb, ta;
- float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
-
- if (hasize==0.0f) return NULL;
-
- projectverto(vec, re->winmat, hoco);
- if (hoco[3]==0.0f) return NULL;
- if (vec1) {
- projectverto(vec1, re->winmat, hoco1);
- if (hoco1[3]==0.0f) return NULL;
- }
-
- har= RE_findOrAddHalo(obr, obr->tothalo++);
- copy_v3_v3(har->co, vec);
- har->hasize= hasize;
-
- /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
- /* we do it here for sorting of halos */
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(hoco[0]/zn);
- har->ys= 0.5f*re->winy*(hoco[1]/zn);
- har->zs= 0x7FFFFF*(hoco[2]/zn);
-
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- /* halovect */
- if (vec1) {
-
- har->type |= HA_VECT;
-
- xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
- yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
- else zn = atan2f(yn, xn);
-
- har->sin = sinf(zn);
- har->cos = cosf(zn);
- zn= len_v3v3(vec1, vec);
-
- har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
-
- sub_v3_v3v3(har->no, vec, vec1);
- normalize_v3(har->no);
- }
-
- if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
-
- har->alfa= ma->alpha;
- har->r= ma->r;
- har->g= ma->g;
- har->b= ma->b;
- har->add= (255.0f*ma->add);
- har->mat= ma;
- har->hard= ma->har;
- har->seed= seed % 256;
-
- if (ma->mode & MA_STAR) har->starpoints= ma->starc;
- if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
- if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
- if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
-
-
- if (ma->mtex[0]) {
-
- if (ma->mode & MA_HALOTEX) {
- har->tex = 1;
- }
- else if (har->mat->septex & (1 << 0)) {
- /* only 1 level textures */
- }
- else {
- mtex= ma->mtex[0];
- copy_v3_v3(texvec, vec);
-
- if (mtex->texco & TEXCO_NORM) {
- ;
- }
- else if (mtex->texco & TEXCO_OBJECT) {
- /* texvec[0]+= imatbase->ivec[0]; */
- /* texvec[1]+= imatbase->ivec[1]; */
- /* texvec[2]+= imatbase->ivec[2]; */
- /* mul_m3_v3(imatbase->imat, texvec); */
- }
- else {
- if (orco) {
- copy_v3_v3(texvec, orco);
- }
- }
-
- externtex(mtex,
- texvec,
- &tin, &tr, &tg, &tb, &ta,
- 0,
- re->pool,
- skip_load_image,
- texnode_preview);
-
- yn= tin*mtex->colfac;
- //zn= tin*mtex->alphafac;
-
- if (mtex->mapto & MAP_COL) {
- zn= 1.0f-yn;
- har->r= (yn*tr+ zn*ma->r);
- har->g= (yn*tg+ zn*ma->g);
- har->b= (yn*tb+ zn*ma->b);
- }
- if (mtex->texco & TEXCO_UV) {
- har->alfa= tin;
- }
- if (mtex->mapto & MAP_ALPHA)
- har->alfa= tin;
- }
- }
-
- har->pool = re->pool;
- har->skip_load_image = skip_load_image;
- har->texnode_preview = texnode_preview;
-
- return har;
-}
-
-HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3])
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- HaloRen *har;
- MTex *mtex;
- float tin, tr, tg, tb, ta;
- float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3], tex[3], out[3];
- int i, hasrgb;
-
- if (hasize==0.0f) return NULL;
-
- projectverto(vec, re->winmat, hoco);
- if (hoco[3]==0.0f) return NULL;
- if (vec1) {
- projectverto(vec1, re->winmat, hoco1);
- if (hoco1[3]==0.0f) return NULL;
- }
-
- har= RE_findOrAddHalo(obr, obr->tothalo++);
- copy_v3_v3(har->co, vec);
- har->hasize= hasize;
-
- /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
- /* we do it here for sorting of halos */
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(hoco[0]/zn);
- har->ys= 0.5f*re->winy*(hoco[1]/zn);
- har->zs= 0x7FFFFF*(hoco[2]/zn);
-
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- /* halovect */
- if (vec1) {
-
- har->type |= HA_VECT;
-
- xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
- yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
- else zn = atan2f(yn, xn);
-
- har->sin = sinf(zn);
- har->cos = cosf(zn);
- zn= len_v3v3(vec1, vec)*0.5f;
-
- har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
-
- sub_v3_v3v3(har->no, vec, vec1);
- normalize_v3(har->no);
- }
-
- if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
-
- har->alfa= ma->alpha;
- har->r= ma->r;
- har->g= ma->g;
- har->b= ma->b;
- har->add= (255.0f*ma->add);
- har->mat= ma;
- har->hard= ma->har;
- har->seed= seed % 256;
-
- if (ma->mode & MA_STAR) har->starpoints= ma->starc;
- if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
- if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
- if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
-
- if ((ma->mode & MA_HALOTEX) && ma->mtex[0])
- har->tex= 1;
-
- for (i=0; i<MAX_MTEX; i++)
- if (ma->mtex[i] && (ma->septex & (1<<i))==0) {
- mtex= ma->mtex[i];
- copy_v3_v3(texvec, vec);
-
- if (mtex->texco & TEXCO_NORM) {
- ;
- }
- else if (mtex->texco & TEXCO_OBJECT) {
- if (mtex->object)
- mul_m4_v3(mtex->object->imat_ren, texvec);
- }
- else if (mtex->texco & TEXCO_GLOB) {
- copy_v3_v3(texvec, vec);
- }
- else if (mtex->texco & TEXCO_UV && uvco) {
- int uv_index=CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, mtex->uvname);
- if (uv_index<0)
- uv_index=CustomData_get_active_layer_index(&dm->faceData, CD_MTFACE);
-
- uv_index-=CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
-
- texvec[0]=2.0f*uvco[2*uv_index]-1.0f;
- texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f;
- texvec[2]=0.0f;
- }
- else if (mtex->texco & TEXCO_PARTICLE) {
- /* particle coordinates in range [0, 1] */
- texvec[0] = 2.f * pa_co[0] - 1.f;
- texvec[1] = 2.f * pa_co[1] - 1.f;
- texvec[2] = pa_co[2];
- }
- else if (orco) {
- copy_v3_v3(texvec, orco);
- }
-
- hasrgb = externtex(mtex,
- texvec,
- &tin, &tr, &tg, &tb, &ta,
- 0,
- re->pool,
- skip_load_image,
- texnode_preview);
-
- //yn= tin*mtex->colfac;
- //zn= tin*mtex->alphafac;
- if (mtex->mapto & MAP_COL) {
- tex[0]=tr;
- tex[1]=tg;
- tex[2]=tb;
- out[0]=har->r;
- out[1]=har->g;
- out[2]=har->b;
-
- texture_rgb_blend(in, tex, out, tin, mtex->colfac, mtex->blendtype);
- // zn= 1.0-yn;
- //har->r= (yn*tr+ zn*ma->r);
- //har->g= (yn*tg+ zn*ma->g);
- //har->b= (yn*tb+ zn*ma->b);
- har->r= in[0];
- har->g= in[1];
- har->b= in[2];
- }
-
- /* alpha returned, so let's use it instead of intensity */
- if (hasrgb)
- tin = ta;
-
- if (mtex->mapto & MAP_ALPHA)
- har->alfa = texture_value_blend(mtex->def_var, har->alfa, tin, mtex->alphafac, mtex->blendtype);
- if (mtex->mapto & MAP_HAR)
- har->hard = 1.0f+126.0f*texture_value_blend(mtex->def_var, ((float)har->hard)/127.0f, tin, mtex->hardfac, mtex->blendtype);
- if (mtex->mapto & MAP_RAYMIRR)
- har->hasize = 100.0f*texture_value_blend(mtex->def_var, har->hasize/100.0f, tin, mtex->raymirrfac, mtex->blendtype);
- if (mtex->mapto & MAP_TRANSLU) {
- float add = texture_value_blend(mtex->def_var, (float)har->add/255.0f, tin, mtex->translfac, mtex->blendtype);
- CLAMP(add, 0.f, 1.f);
- har->add = 255.0f*add;
- }
- /* now what on earth is this good for?? */
- //if (mtex->texco & 16) {
- // har->alfa= tin;
- //}
- }
-
- har->pool = re->pool;
- har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
-
- return har;
-}
-
-/* -------------------------- operations on entire database ----------------------- */
-
-/* ugly function for halos in panorama */
-static int panotestclip(Render *re, bool do_pano, float v[4])
-{
- /* part size (ensure we run RE_parts_clamp first) */
- BLI_assert(re->partx == min_ii(re->r.tilex, re->rectx));
- BLI_assert(re->party == min_ii(re->r.tiley, re->recty));
-
- if (do_pano == false) {
- return testclip(v);
- }
- else {
- /* to be used for halos en infos */
- float abs4;
- short c = 0;
-
- int xparts = (re->rectx + re->partx - 1) / re->partx;
-
- abs4= fabsf(v[3]);
-
- if (v[2]< -abs4) c=16; /* this used to be " if (v[2]<0) ", see clippz() */
- else if (v[2]> abs4) c+= 32;
-
- if ( v[1]>abs4) c+=4;
- else if ( v[1]< -abs4) c+=8;
-
- abs4*= xparts;
- if ( v[0]>abs4) c+=2;
- else if ( v[0]< -abs4) c+=1;
-
- return c;
- }
-}
-
-/**
- * This adds the hcs coordinates to vertices. It iterates over all
- * vertices, halos and faces. After the conversion, we clip in hcs.
- *
- * Elsewhere, all primites are converted to vertices.
- * Called in
- * - envmapping (envmap.c)
- * - shadow buffering (shadbuf.c)
- */
-
-void project_renderdata(Render *re,
- void (*projectfunc)(const float *, float mat[4][4], float *),
- bool do_pano, float xoffs, bool UNUSED(do_buckets))
-{
- ObjectRen *obr;
- HaloRen *har = NULL;
- float zn, vec[3], hoco[4];
- int a;
-
- if (do_pano) {
- float panophi= xoffs;
-
- re->panosi = sinf(panophi);
- re->panoco = cosf(panophi);
- }
-
- for (obr=re->objecttable.first; obr; obr=obr->next) {
- /* calculate view coordinates (and zbuffer value) */
- for (a=0; a<obr->tothalo; a++) {
- if ((a & 255)==0) har= obr->bloha[a>>8];
- else har++;
-
- if (do_pano) {
- vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
- vec[1]= har->co[1];
- vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
- }
- else {
- copy_v3_v3(vec, har->co);
- }
-
- projectfunc(vec, re->winmat, hoco);
-
- /* we clip halos less critical, but not for the Z */
- hoco[0]*= 0.5f;
- hoco[1]*= 0.5f;
-
- if ( panotestclip(re, do_pano, hoco) ) {
- har->miny= har->maxy= -10000; /* that way render clips it */
- }
- else if (hoco[3]<0.0f) {
- har->miny= har->maxy= -10000; /* render clips it */
- }
- else { /* do the projection...*/
- /* bring back hocos */
- hoco[0]*= 2.0f;
- hoco[1]*= 2.0f;
-
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(1.0f+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
- har->ys= 0.5f*re->winy*(1.0f+hoco[1]/zn);
-
- /* this should be the zbuffer coordinate */
- har->zs= 0x7FFFFF*(hoco[2]/zn);
- /* taking this from the face clip functions? seems ok... */
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- vec[0]+= har->hasize;
- projectfunc(vec, re->winmat, hoco);
- vec[0]-= har->hasize;
- zn= hoco[3];
- har->rad= fabsf(har->xs- 0.5f*re->winx*(1.0f+hoco[0]/zn));
-
- /* this clip is not really OK, to prevent stars to become too large */
- if (har->type & HA_ONLYSKY) {
- if (har->rad>3.0f) har->rad= 3.0f;
- }
-
- har->radsq= har->rad*har->rad;
-
- har->miny= har->ys - har->rad/re->ycor;
- har->maxy= har->ys + har->rad/re->ycor;
-
- /* the Zd value is still not really correct for pano */
-
- vec[2] -= har->hasize; /* z negative, otherwise it's clipped */
- projectfunc(vec, re->winmat, hoco);
- zn = hoco[3];
- zn = fabsf((float)har->zs - 0x7FFFFF * (hoco[2] / zn));
- har->zd = CLAMPIS(zn, 0, INT_MAX);
-
- }
-
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag)
-{
- /* flag specifies what things have changed. */
- if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) {
- copy_m4_m4(obi->obmat, obi->ob->obmat);
- invert_m4_m4(obi->obinvmat, obi->obmat);
- }
- if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) {
- mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat);
- mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv);
- }
-}
-
-void RE_updateRenderInstances(Render *re, int flag)
-{
- int i = 0;
- for (i = 0; i < re->totinstance; i++)
- RE_updateRenderInstance(re, &re->objectinstance[i], flag);
-}
-
-ObjectInstanceRen *RE_addRenderInstance(
- Render *re, ObjectRen *obr, Object *ob, Object *par,
- int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob)
-{
- ObjectInstanceRen *obi;
- float mat3[3][3];
-
- obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen");
- obi->obr= obr;
- obi->ob= ob;
- obi->par= par;
- obi->index= index;
- obi->psysindex= psysindex;
- obi->lay= lay;
-
- /* Fill particle info */
- if (par && dob) {
- const ParticleSystem *psys = dob->particle_system;
- if (psys) {
- int part_index;
- if (obi->index < psys->totpart) {
- part_index = obi->index;
- }
- else if (psys->child) {
- part_index = psys->child[obi->index - psys->totpart].parent;
- }
- else {
- part_index = -1;
- }
-
- if (part_index >= 0) {
- const ParticleData *p = &psys->particles[part_index];
- obi->part_index = part_index;
- obi->part_size = p->size;
- obi->part_age = RE_GetStats(re)->cfra - p->time;
- obi->part_lifetime = p->lifetime;
-
- copy_v3_v3(obi->part_co, p->state.co);
- copy_v3_v3(obi->part_vel, p->state.vel);
- copy_v3_v3(obi->part_avel, p->state.ave);
- }
- }
- }
-
- /* Fill object info */
- if (dob) {
- obi->random_id = dob->random_id;
- }
- else {
- obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
- }
-
- RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
-
- if (mat) {
- copy_m4_m4(obi->mat, mat);
- copy_m3_m4(mat3, mat);
- invert_m3_m3(obi->nmat, mat3);
- transpose_m3(obi->nmat);
- obi->flag |= R_DUPLI_TRANSFORMED;
- }
-
- BLI_addtail(&re->instancetable, obi);
-
- return obi;
-}
-
-void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3])
-{
- *index = obi->part_index;
- *random = BLI_hash_int_01(obi->part_index);
- *age = obi->part_age;
- *lifetime = obi->part_lifetime;
- copy_v3_v3(co, obi->part_co);
- *size = obi->part_size;
- copy_v3_v3(vel, obi->part_vel);
- copy_v3_v3(angvel, obi->part_avel);
-}
-
-
-void RE_makeRenderInstances(Render *re)
-{
- ObjectInstanceRen *obi, *oldobi;
- ListBase newlist;
- int tot;
-
- /* convert list of object instances to an array for index based lookup */
- tot= BLI_listbase_count(&re->instancetable);
- re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance");
- re->totinstance= tot;
- newlist.first= newlist.last= NULL;
-
- obi= re->objectinstance;
- for (oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
- *obi= *oldobi;
-
- if (obi->obr) {
- obi->prev= obi->next= NULL;
- BLI_addtail(&newlist, obi);
- obi++;
- }
- else
- re->totinstance--;
- }
-
- BLI_freelistN(&re->instancetable);
- re->instancetable= newlist;
-}
-
-/* four functions to facilitate envmap rotation for raytrace */
-void RE_instance_rotate_ray_start(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- copy_v3_v3(is->origstart, is->start);
- mul_m4_v3(obi->imat, is->start);
- }
-}
-
-void RE_instance_rotate_ray_dir(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- float end[3];
-
- copy_v3_v3(is->origdir, is->dir);
- add_v3_v3v3(end, is->origstart, is->dir);
-
- mul_m4_v3(obi->imat, end);
- sub_v3_v3v3(is->dir, end, is->start);
- }
-}
-
-void RE_instance_rotate_ray(ObjectInstanceRen *obi, Isect *is)
-{
- RE_instance_rotate_ray_start(obi, is);
- RE_instance_rotate_ray_dir(obi, is);
-}
-
-void RE_instance_rotate_ray_restore(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- copy_v3_v3(is->start, is->origstart);
- copy_v3_v3(is->dir, is->origdir);
- }
-}
-
-int clip_render_object(float boundbox[2][3], float bounds[4], float winmat[4][4])
-{
- float mat[4][4], vec[4];
- int a, fl, flag = -1;
-
- copy_m4_m4(mat, winmat);
-
- for (a=0; a < 8; a++) {
- vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0];
- vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1];
- vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2];
- vec[3]= 1.0;
- mul_m4_v4(mat, vec);
-
- fl = 0;
- if (bounds) {
- if (vec[0] < bounds[0] * vec[3]) fl |= 1;
- else if (vec[0] > bounds[1] * vec[3]) fl |= 2;
-
- if (vec[1] > bounds[3] * vec[3]) fl |= 4;
- else if (vec[1] < bounds[2] * vec[3]) fl |= 8;
- }
- else {
- if (vec[0] < -vec[3]) fl |= 1;
- else if (vec[0] > vec[3]) fl |= 2;
-
- if (vec[1] > vec[3]) fl |= 4;
- else if (vec[1] < -vec[3]) fl |= 8;
- }
- if (vec[2] < -vec[3]) fl |= 16;
- else if (vec[2] > vec[3]) fl |= 32;
-
- flag &= fl;
- if (flag == 0) {
- return 0;
- }
- }
-
- return flag;
-}
-
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
deleted file mode 100644
index fb441662829..00000000000
--- a/source/blender/render/intern/source/shadbuf.c
+++ /dev/null
@@ -1,2647 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributor(s): 2004-2006, Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadbuf.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <string.h>
-
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_memarena.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_global.h"
-#include "BKE_scene.h"
-
-#include "PIL_time.h"
-
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "zbuf.h"
-
-/* XXX, could be better implemented... this is for endian issues */
-#ifdef __BIG_ENDIAN__
-//# define RCOMP 3
-# define GCOMP 2
-# define BCOMP 1
-# define ACOMP 0
-#else
-//# define RCOMP 0
-# define GCOMP 1
-# define BCOMP 2
-# define ACOMP 3
-#endif
-
-#define RCT_SIZE_X(rct) ((rct)->xmax - (rct)->xmin)
-#define RCT_SIZE_Y(rct) ((rct)->ymax - (rct)->ymin)
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* ------------------------------------------------------------------------- */
-
-/* initshadowbuf() in convertBlenderScene.c */
-
-/* ------------------------------------------------------------------------- */
-
-static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1)
-{
- int len4, *rz;
- int x2, y2;
-
- x2= x1+tile;
- y2= y1+tile;
- if (x2>=size) x2= size-1;
- if (y2>=size) y2= size-1;
-
- if (x1>=x2 || y1>=y2) return;
-
- len4= 4*(x2- x1);
- rz= rectz + size*y1 + x1;
- for (; y1<y2; y1++) {
- memcpy(r1, rz, len4);
- rz+= size;
- r1+= len4;
- }
-}
-
-#if 0
-static int sizeoflampbuf(ShadBuf *shb)
-{
- int num, count=0;
- char *cp;
-
- cp= shb->cbuf;
- num= (shb->size*shb->size)/256;
-
- while (num--) count+= *(cp++);
-
- return 256*count;
-}
-#endif
-
-/* not threadsafe... */
-static float *give_jitter_tab(int samp)
-{
- /* these are all possible jitter tables, takes up some
- * 12k, not really bad!
- * For soft shadows, it saves memory and render time
- */
- static int tab[17]={1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256};
- static float jit[1496][2];
- static char ctab[17]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int a, offset=0;
-
- if (samp<2) samp= 2;
- else if (samp>16) samp= 16;
-
- for (a=0; a<samp-1; a++) offset+= tab[a];
-
- if (ctab[samp]==0) {
- ctab[samp]= 1;
- BLI_jitter_init((float (*)[2])jit[offset], samp*samp);
- }
-
- return jit[offset];
-
-}
-
-static void make_jitter_weight_tab(Render *re, ShadBuf *shb, short filtertype)
-{
- float *jit, totw= 0.0f;
- int samp= get_render_shadow_samples(&re->r, shb->samp);
- int a, tot=samp*samp;
-
- shb->weight= MEM_mallocN(sizeof(float)*tot, "weight tab lamp");
-
- for (jit= shb->jit, a=0; a<tot; a++, jit+=2) {
- if (filtertype==LA_SHADBUF_TENT)
- shb->weight[a] = 0.71f - sqrtf(jit[0] * jit[0] + jit[1] * jit[1]);
- else if (filtertype==LA_SHADBUF_GAUSS)
- shb->weight[a] = RE_filter_value(R_FILTER_GAUSS, 1.8f * sqrtf(jit[0] * jit[0] + jit[1] * jit[1]));
- else
- shb->weight[a]= 1.0f;
-
- totw+= shb->weight[a];
- }
-
- totw= 1.0f/totw;
- for (a=0; a<tot; a++) {
- shb->weight[a]*= totw;
- }
-}
-
-static int verg_deepsample(const void *poin1, const void *poin2)
-{
- const DeepSample *ds1= (const DeepSample*)poin1;
- const DeepSample *ds2= (const DeepSample*)poin2;
-
- if (ds1->z < ds2->z) return -1;
- else if (ds1->z == ds2->z) return 0;
- else return 1;
-}
-
-static int compress_deepsamples(DeepSample *dsample, int tot, float epsilon)
-{
- /* uses doubles to avoid overflows and other numerical issues,
- * could be improved */
- DeepSample *ds, *newds;
- float v;
- double slope, slopemin, slopemax, min, max, div, newmin, newmax;
- int a, first, z, newtot= 0;
-
-#if 0
- if (print) {
- for (a=0, ds=dsample; a<tot; a++, ds++)
- printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
- printf("\n");
- }
-#endif
-
- /* read from and write into same array */
- ds= dsample;
- newds= dsample;
- a= 0;
-
- /* as long as we are not at the end of the array */
- for (a++, ds++; a<tot; a++, ds++) {
- slopemin= 0.0f;
- slopemax= 0.0f;
- first= 1;
-
- for (; a<tot; a++, ds++) {
- //dz= ds->z - newds->z;
- if (ds->z == newds->z) {
- /* still in same z position, simply check
- * visibility difference against epsilon */
- if (!(fabsf(newds->v - ds->v) <= epsilon)) {
- break;
- }
- }
- else {
- /* compute slopes */
- div= (double)0x7FFFFFFF / ((double)ds->z - (double)newds->z);
- min= (double)((ds->v - epsilon) - newds->v) * div;
- max= (double)((ds->v + epsilon) - newds->v) * div;
-
- /* adapt existing slopes */
- if (first) {
- newmin= min;
- newmax= max;
- first= 0;
- }
- else {
- newmin= MAX2(slopemin, min);
- newmax= MIN2(slopemax, max);
-
- /* verify if there is still space between the slopes */
- if (newmin > newmax) {
- ds--;
- a--;
- break;
- }
- }
-
- slopemin= newmin;
- slopemax= newmax;
- }
- }
-
- if (a == tot) {
- ds--;
- a--;
- }
-
- /* always previous z */
- z= ds->z;
-
- if (first || a==tot-1) {
- /* if slopes were not initialized, use last visibility */
- v= ds->v;
- }
- else {
- /* compute visibility at center between slopes at z */
- slope = (slopemin + slopemax) * 0.5;
- v = (double)newds->v + slope * ((double)(z - newds->z) / (double)0x7FFFFFFF);
- }
-
- newds++;
- newtot++;
-
- newds->z= z;
- newds->v= v;
- }
-
- if (newtot == 0 || (newds->v != (newds-1)->v))
- newtot++;
-
-#if 0
- if (print) {
- for (a=0, ds=dsample; a<newtot; a++, ds++)
- printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
- printf("\n");
- }
-#endif
-
- return newtot;
-}
-
-static float deep_alpha(Render *re, int obinr, int facenr, bool use_strand)
-{
- ObjectInstanceRen *obi= &re->objectinstance[obinr];
- Material *ma;
-
- if (use_strand) {
- StrandRen *strand= RE_findOrAddStrand(obi->obr, facenr-1);
- ma= strand->buffer->ma;
- }
- else {
- VlakRen *vlr= RE_findOrAddVlak(obi->obr, (facenr-1) & RE_QUAD_MASK);
- ma= vlr->mat;
- }
-
- return ma->shad_alpha;
-}
-
-static void compress_deepshadowbuf(Render *re, ShadBuf *shb, APixstr *apixbuf, APixstrand *apixbufstrand)
-{
- ShadSampleBuf *shsample;
- DeepSample *ds[RE_MAX_OSA], *sampleds[RE_MAX_OSA], *dsb, *newbuf;
- APixstr *ap, *apn;
- APixstrand *aps, *apns;
- float visibility;
-
- const int totbuf= shb->totbuf;
- const float totbuf_f= (float)shb->totbuf;
- const float totbuf_f_inv= 1.0f/totbuf_f;
- const int size= shb->size;
-
- int a, b, c, tot, minz, found, prevtot, newtot;
- int sampletot[RE_MAX_OSA], totsample = 0, totsamplec = 0;
-
- shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
- BLI_addtail(&shb->buffers, shsample);
-
- shsample->totbuf = MEM_callocN(sizeof(int) * size * size, "deeptotbuf");
- shsample->deepbuf = MEM_callocN(sizeof(DeepSample *) * size * size, "deepbuf");
-
- ap= apixbuf;
- aps= apixbufstrand;
- for (a=0; a<size*size; a++, ap++, aps++) {
- /* count number of samples */
- for (c=0; c<totbuf; c++)
- sampletot[c]= 0;
-
- tot= 0;
- for (apn=ap; apn; apn=apn->next)
- for (b=0; b<4; b++)
- if (apn->p[b])
- for (c=0; c<totbuf; c++)
- if (apn->mask[b] & (1<<c))
- sampletot[c]++;
-
- if (apixbufstrand) {
- for (apns=aps; apns; apns=apns->next)
- for (b=0; b<4; b++)
- if (apns->p[b])
- for (c=0; c<totbuf; c++)
- if (apns->mask[b] & (1<<c))
- sampletot[c]++;
- }
-
- for (c=0; c<totbuf; c++)
- tot += sampletot[c];
-
- if (tot == 0) {
- shsample->deepbuf[a]= NULL;
- shsample->totbuf[a]= 0;
- continue;
- }
-
- /* fill samples */
- ds[0]= sampleds[0]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
- for (c=1; c<totbuf; c++)
- ds[c]= sampleds[c]= sampleds[c-1] + sampletot[c-1]*2;
-
- for (apn=ap; apn; apn=apn->next) {
- for (b=0; b<4; b++) {
- if (apn->p[b]) {
- for (c=0; c<totbuf; c++) {
- if (apn->mask[b] & (1<<c)) {
- /* two entries to create step profile */
- ds[c]->z= apn->z[b];
- ds[c]->v= 1.0f; /* not used */
- ds[c]++;
- ds[c]->z= apn->z[b];
- ds[c]->v= deep_alpha(re, apn->obi[b], apn->p[b], 0);
- ds[c]++;
- }
- }
- }
- }
- }
-
- if (apixbufstrand) {
- for (apns=aps; apns; apns=apns->next) {
- for (b=0; b<4; b++) {
- if (apns->p[b]) {
- for (c=0; c<totbuf; c++) {
- if (apns->mask[b] & (1<<c)) {
- /* two entries to create step profile */
- ds[c]->z= apns->z[b];
- ds[c]->v= 1.0f; /* not used */
- ds[c]++;
- ds[c]->z= apns->z[b];
- ds[c]->v= deep_alpha(re, apns->obi[b], apns->p[b], 1);
- ds[c]++;
- }
- }
- }
- }
- }
- }
-
- for (c=0; c<totbuf; c++) {
- /* sort by increasing z */
- qsort(sampleds[c], sampletot[c], sizeof(DeepSample)*2, verg_deepsample);
-
- /* sum visibility, replacing alpha values */
- visibility= 1.0f;
- ds[c]= sampleds[c];
-
- for (b=0; b<sampletot[c]; b++) {
- /* two entries creating step profile */
- ds[c]->v= visibility;
- ds[c]++;
-
- visibility *= 1.0f-ds[c]->v;
- ds[c]->v= visibility;
- ds[c]++;
- }
-
- /* halfway trick, probably won't work well for volumes? */
- ds[c]= sampleds[c];
- for (b=0; b<sampletot[c]; b++) {
- if (b+1 < sampletot[c]) {
- ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
- ds[c]++;
- ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
- ds[c]++;
- }
- else {
- ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
- ds[c]++;
- ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
- ds[c]++;
- }
- }
-
- /* init for merge loop */
- ds[c]= sampleds[c];
- sampletot[c] *= 2;
- }
-
- shsample->deepbuf[a]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
- shsample->totbuf[a]= 0;
-
- /* merge buffers */
- dsb= shsample->deepbuf[a];
- while (1) {
- minz= 0;
- found= 0;
-
- for (c=0; c<totbuf; c++) {
- if (sampletot[c] && (!found || ds[c]->z < minz)) {
- minz= ds[c]->z;
- found= 1;
- }
- }
-
- if (!found)
- break;
-
- dsb->z= minz;
- dsb->v= 0.0f;
-
- visibility= 0.0f;
- for (c=0; c<totbuf; c++) {
- if (sampletot[c] && ds[c]->z == minz) {
- ds[c]++;
- sampletot[c]--;
- }
-
- if (sampleds[c] == ds[c])
- visibility += totbuf_f_inv;
- else
- visibility += (ds[c]-1)->v / totbuf_f;
- }
-
- dsb->v= visibility;
- dsb++;
- shsample->totbuf[a]++;
- }
-
- prevtot= shsample->totbuf[a];
- totsample += prevtot;
-
- newtot= compress_deepsamples(shsample->deepbuf[a], prevtot, shb->compressthresh);
- shsample->totbuf[a]= newtot;
- totsamplec += newtot;
-
- if (newtot < prevtot) {
- newbuf= MEM_mallocN(sizeof(DeepSample)*newtot, "cdeepsample");
- memcpy(newbuf, shsample->deepbuf[a], sizeof(DeepSample)*newtot);
- MEM_freeN(shsample->deepbuf[a]);
- shsample->deepbuf[a]= newbuf;
- }
-
- MEM_freeN(sampleds[0]);
- }
-
- //printf("%d -> %d, ratio %f\n", totsample, totsamplec, (float)totsamplec/(float)totsample);
-}
-
-/* create Z tiles (for compression): this system is 24 bits!!! */
-static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
-{
- ShadSampleBuf *shsample;
- float dist;
- uintptr_t *ztile;
- int *rz, *rz1, verg, verg1, size= shb->size;
- int a, x, y, minx, miny, byt1, byt2;
- char *rc, *rcline, *ctile, *zt;
-
- shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
- BLI_addtail(&shb->buffers, shsample);
-
- shsample->zbuf= MEM_mallocN(sizeof(uintptr_t)*(size*size)/256, "initshadbuf2");
- shsample->cbuf= MEM_callocN((size*size)/256, "initshadbuf3");
-
- ztile= (uintptr_t *)shsample->zbuf;
- ctile= shsample->cbuf;
-
- /* help buffer */
- rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2");
-
- for (y=0; y<size; y+=16) {
- if (y< size/2) miny= y+15-size/2;
- else miny= y-size/2;
-
- for (x=0; x<size; x+=16) {
-
- /* is tile within spotbundle? */
- a= size/2;
- if (x< a) minx= x+15-a;
- else minx= x-a;
-
- dist = sqrtf((float)(minx * minx + miny * miny));
-
- if (square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */
- a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */
- rz1= (&verg)+1;
- }
- else {
- copy_to_ztile(rectz, size, x, y, 16, rcline);
- rz1= (int *)rcline;
-
- verg= (*rz1 & 0xFFFFFF00);
-
- for (a=0;a<256;a++, rz1++) {
- if ( (*rz1 & 0xFFFFFF00) !=verg) break;
- }
- }
- if (a==256) { /* complete empty tile */
- *ctile= 0;
- *ztile= *(rz1-1);
- }
- else {
-
- /* ACOMP etc. are defined to work L/B endian */
-
- rc= rcline;
- rz1= (int *)rcline;
- verg= rc[ACOMP];
- verg1= rc[BCOMP];
- rc+= 4;
- byt1= 1; byt2= 1;
- for (a=1;a<256;a++, rc+=4) {
- byt1 &= (verg==rc[ACOMP]);
- byt2 &= (verg1==rc[BCOMP]);
-
- if (byt1==0) break;
- }
- if (byt1 && byt2) { /* only store byte */
- *ctile= 1;
- *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1");
- rz= (int *)*ztile;
- *rz= *rz1;
-
- zt= (char *)(rz+1);
- rc= rcline;
- for (a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP];
- }
- else if (byt1) { /* only store short */
- *ctile= 2;
- *ztile= (uintptr_t)MEM_mallocN(2*256+4, "Tile2");
- rz= (int *)*ztile;
- *rz= *rz1;
-
- zt= (char *)(rz+1);
- rc= rcline;
- for (a=0; a<256; a++, zt+=2, rc+=4) {
- zt[0]= rc[BCOMP];
- zt[1]= rc[GCOMP];
- }
- }
- else { /* store triple */
- *ctile= 3;
- *ztile= (uintptr_t)MEM_mallocN(3*256, "Tile3");
-
- zt= (char *)*ztile;
- rc= rcline;
- for (a=0; a<256; a++, zt+=3, rc+=4) {
- zt[0]= rc[ACOMP];
- zt[1]= rc[BCOMP];
- zt[2]= rc[GCOMP];
- }
- }
- }
- ztile++;
- ctile++;
- }
- }
-
- MEM_freeN(rcline);
-}
-
-/* sets start/end clipping. lar->shb should be initialized */
-static void shadowbuf_autoclip(Render *re, LampRen *lar)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- VertRen *ver= NULL;
- Material *ma= NULL;
- float minz, maxz, vec[3], viewmat[4][4], obviewmat[4][4];
- unsigned int lay = -1;
- int i, a, maxtotvert, ok= 1;
- char *clipflag;
-
- minz= 1.0e30f; maxz= -1.0e30f;
- copy_m4_m4(viewmat, lar->shb->viewmat);
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- maxtotvert= 0;
- for (obr=re->objecttable.first; obr; obr=obr->next)
- maxtotvert = max_ii(obr->totvert, maxtotvert);
-
- clipflag= MEM_callocN(sizeof(char)*maxtotvert, "autoclipflag");
-
- /* set clip in vertices when face visible */
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obviewmat, viewmat, obi->mat);
- else
- copy_m4_m4(obviewmat, viewmat);
-
- memset(clipflag, 0, sizeof(char)*obr->totvert);
-
- /* clear clip, is being set if face is visible (clip is calculated for real later) */
- for (a=0; a<obr->totvlak; a++) {
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note; these conditions are copied from zbuffer_shadow() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (obi->lay & lay)) {
- clipflag[vlr->v1->index]= 1;
- clipflag[vlr->v2->index]= 1;
- clipflag[vlr->v3->index]= 1;
- if (vlr->v4) clipflag[vlr->v4->index]= 1;
- }
- }
-
- /* calculate min and max */
- for (a=0; a< obr->totvert;a++) {
- if ((a & 255)==0) ver= RE_findOrAddVert(obr, a);
- else ver++;
-
- if (clipflag[a]) {
- copy_v3_v3(vec, ver->co);
- mul_m4_v3(obviewmat, vec);
- /* Z on visible side of lamp space */
- if (vec[2] < 0.0f) {
- float inpr, z= -vec[2];
-
- /* since vec is rotated in lampspace, this is how to get the cosine of angle */
- /* precision is set 20% larger */
- vec[2]*= 1.2f;
- normalize_v3(vec);
- inpr= - vec[2];
-
- if (inpr>=lar->spotsi) {
- if (z<minz) minz= z;
- if (z>maxz) maxz= z;
- }
- }
- }
- }
- }
-
- MEM_freeN(clipflag);
-
- /* set clipping min and max */
- if (minz < maxz) {
- float delta= (maxz - minz); /* threshold to prevent precision issues */
-
- //printf("minz %f maxz %f delta %f\n", minz, maxz, delta);
- if (lar->bufflag & LA_SHADBUF_AUTO_START)
- lar->shb->d= minz - delta*0.02f; /* 0.02 is arbitrary... needs more thinking! */
- if (lar->bufflag & LA_SHADBUF_AUTO_END)
- lar->shb->clipend= maxz + delta*0.1f;
-
- /* bias was calculated as percentage, we scale it to prevent animation issues */
- delta= (lar->clipend-lar->clipsta)/(lar->shb->clipend-lar->shb->d);
- //printf("bias delta %f\n", delta);
- lar->shb->bias= (int) (delta*(float)lar->shb->bias);
- }
-}
-
-static void makeflatshadowbuf(Render *re, LampRen *lar, float *jitbuf)
-{
- ShadBuf *shb= lar->shb;
- int *rectz, samples;
-
- /* zbuffering */
- rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf");
-
- for (samples=0; samples<shb->totbuf; samples++) {
- zbuffer_shadow(re, shb->persmat, lar, rectz, shb->size, jitbuf[2*samples], jitbuf[2*samples+1]);
- /* create Z tiles (for compression): this system is 24 bits!!! */
- compress_shadowbuf(shb, rectz, lar->mode & LA_SQUARE);
-
- if (re->test_break(re->tbh))
- break;
- }
-
- MEM_freeN(rectz);
-}
-
-static void makedeepshadowbuf(Render *re, LampRen *lar, float *jitbuf)
-{
- ShadBuf *shb= lar->shb;
- APixstr *apixbuf;
- APixstrand *apixbufstrand= NULL;
- ListBase apsmbase= {NULL, NULL};
-
- /* zbuffering */
- apixbuf= MEM_callocN(sizeof(APixstr)*shb->size*shb->size, "APixbuf");
- if (re->totstrand)
- apixbufstrand= MEM_callocN(sizeof(APixstrand)*shb->size*shb->size, "APixbufstrand");
-
- zbuffer_abuf_shadow(re, lar, shb->persmat, apixbuf, apixbufstrand, &apsmbase, shb->size,
- shb->totbuf, (float(*)[2])jitbuf);
-
- /* create Z tiles (for compression): this system is 24 bits!!! */
- compress_deepshadowbuf(re, shb, apixbuf, apixbufstrand);
-
- MEM_freeN(apixbuf);
- if (apixbufstrand)
- MEM_freeN(apixbufstrand);
- freepsA(&apsmbase);
-}
-
-void makeshadowbuf(Render *re, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp;
-
- if (lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END))
- shadowbuf_autoclip(re, lar);
-
- /* just to enforce identical behavior of all irregular buffers */
- if (lar->buftype==LA_SHADBUF_IRREGULAR)
- shb->size= 1024;
-
- /* matrices and window: in winmat the transformation is being put,
- * transforming from observer view to lamp view, including lamp window matrix */
-
- angle= saacos(lar->spotsi);
- temp = 0.5f * shb->size * cosf(angle) / sinf(angle);
- shb->pixsize= (shb->d)/temp;
- wsize= shb->pixsize*(shb->size/2.0f);
-
- perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend);
- mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat);
-
- if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) {
- shb->totbuf= lar->buffers;
-
- /* jitter, weights - not threadsafe! */
- BLI_thread_lock(LOCK_CUSTOM1);
- shb->jit= give_jitter_tab(get_render_shadow_samples(&re->r, shb->samp));
- make_jitter_weight_tab(re, shb, lar->filtertype);
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- if (shb->totbuf==4) jitbuf= give_jitter_tab(2);
- else if (shb->totbuf==9) jitbuf= give_jitter_tab(3);
- else jitbuf= twozero;
-
- /* zbuffering */
- if (lar->buftype == LA_SHADBUF_DEEP) {
- makedeepshadowbuf(re, lar, jitbuf);
- shb->totbuf= 1;
- }
- else
- makeflatshadowbuf(re, lar, jitbuf);
-
- /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */
- }
-}
-
-static void *do_shadow_thread(void *re_v)
-{
- Render *re = (Render *)re_v;
- LampRen *lar;
-
- do {
- BLI_thread_lock(LOCK_CUSTOM1);
- for (lar=re->lampren.first; lar; lar=lar->next) {
- if (lar->shb && !lar->thread_assigned) {
- lar->thread_assigned= 1;
- break;
- }
- }
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- /* if type is irregular, this only sets the perspective matrix and autoclips */
- if (lar) {
- makeshadowbuf(re, lar);
- BLI_thread_lock(LOCK_CUSTOM1);
- lar->thread_ready= 1;
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
- } while (lar && !re->test_break(re->tbh));
-
- return NULL;
-}
-
-static volatile int g_break= 0;
-static int thread_break(void *UNUSED(arg))
-{
- return g_break;
-}
-
-void threaded_makeshadowbufs(Render *re)
-{
- ListBase threads;
- LampRen *lar;
- int a, totthread= 0;
- int (*test_break)(void *);
-
- /* count number of threads to use */
- if (G.is_rendering) {
- for (lar=re->lampren.first; lar; lar= lar->next)
- if (lar->shb)
- totthread++;
-
- totthread = min_ii(totthread, re->r.threads);
- }
- else
- totthread = 1; /* preview render */
-
- if (totthread <= 1) {
- for (lar=re->lampren.first; lar; lar= lar->next) {
- if (re->test_break(re->tbh)) break;
- if (lar->shb) {
- /* if type is irregular, this only sets the perspective matrix and autoclips */
- makeshadowbuf(re, lar);
- }
- }
- }
- else {
- /* swap test break function */
- test_break= re->test_break;
- re->test_break= thread_break;
-
- for (lar=re->lampren.first; lar; lar= lar->next) {
- lar->thread_assigned= 0;
- lar->thread_ready= 0;
- }
-
- BLI_threadpool_init(&threads, do_shadow_thread, totthread);
-
- for (a=0; a<totthread; a++)
- BLI_threadpool_insert(&threads, re);
-
- /* keep rendering as long as there are shadow buffers not ready */
- do {
- if ((g_break=test_break(re->tbh)))
- break;
-
- PIL_sleep_ms(50);
-
- BLI_thread_lock(LOCK_CUSTOM1);
- for (lar=re->lampren.first; lar; lar= lar->next)
- if (lar->shb && !lar->thread_ready)
- break;
- BLI_thread_unlock(LOCK_CUSTOM1);
- } while (lar);
-
- BLI_threadpool_end(&threads);
-
- /* unset threadsafety */
- re->test_break= test_break;
- g_break= 0;
- }
-}
-
-void freeshadowbuf(LampRen *lar)
-{
- if (lar->shb) {
- ShadBuf *shb= lar->shb;
- ShadSampleBuf *shsample;
- int b, v;
-
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
- if (shsample->deepbuf) {
- v= shb->size*shb->size;
- for (b=0; b<v; b++)
- if (shsample->deepbuf[b])
- MEM_freeN(shsample->deepbuf[b]);
-
- MEM_freeN(shsample->deepbuf);
- MEM_freeN(shsample->totbuf);
- }
- else {
- intptr_t *ztile= shsample->zbuf;
- const char *ctile= shsample->cbuf;
-
- v= (shb->size*shb->size)/256;
- for (b=0; b<v; b++, ztile++, ctile++)
- if (*ctile) MEM_freeN((void *) *ztile);
-
- MEM_freeN(shsample->zbuf);
- MEM_freeN(shsample->cbuf);
- }
- }
- BLI_freelistN(&shb->buffers);
-
- if (shb->weight) MEM_freeN(shb->weight);
- MEM_freeN(lar->shb);
-
- lar->shb= NULL;
- }
-}
-
-
-static int firstreadshadbuf(ShadBuf *shb, ShadSampleBuf *shsample, int **rz, int xs, int ys, int nr)
-{
- /* return a 1 if fully compressed shadbuf-tile && z==const */
- int ofs;
- const char *ct;
-
- if (shsample->deepbuf)
- return 0;
-
- /* always test borders of shadowbuffer */
- if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
- if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- if (*ct==0) {
- if (nr==0) {
- *rz= *( (int **)(shsample->zbuf+ofs) );
- return 1;
- }
- else if (*rz!= *( (int **)(shsample->zbuf+ofs) )) return 0;
-
- return 1;
- }
-
- return 0;
-}
-
-static float readdeepvisibility(DeepSample *dsample, int tot, int z, int bias, float *biast)
-{
- DeepSample *ds, *prevds;
- float t;
- int a;
-
- /* tricky stuff here; we use ints which can overflow easily with bias values */
-
- ds= dsample;
- for (a=0; a<tot && (z-bias > ds->z); a++, ds++) {}
-
- if (a == tot) {
- if (biast)
- *biast= 0.0f;
- return (ds-1)->v; /* completely behind all samples */
- }
-
- /* check if this read needs bias blending */
- if (biast) {
- if (z > ds->z)
- *biast= (float)(z - ds->z)/(float)bias;
- else
- *biast= 0.0f;
- }
-
- if (a == 0)
- return 1.0f; /* completely in front of all samples */
-
- /* converting to float early here because ds->z - prevds->z can overflow */
- prevds= ds-1;
- t= ((float)(z-bias) - (float)prevds->z)/((float)ds->z - (float)prevds->z);
- return t*ds->v + (1.0f-t)*prevds->v;
-}
-
-static float readdeepshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
-{
- float v, biasv, biast;
- int ofs, tot;
-
- if (zs < - 0x7FFFFE00 + bias)
- return 1.0; /* extreme close to clipstart */
-
- /* calc z */
- ofs= ys*shb->size + xs;
- tot= shsample->totbuf[ofs];
- if (tot == 0)
- return 1.0f;
-
- v= readdeepvisibility(shsample->deepbuf[ofs], tot, zs, bias, &biast);
-
- if (biast != 0.0f) {
- /* in soft bias area */
- biasv = readdeepvisibility(shsample->deepbuf[ofs], tot, zs, 0, NULL);
-
- biast= biast*biast;
- return (1.0f-biast)*v + biast*biasv;
- }
-
- return v;
-}
-
-/* return 1.0 : fully in light */
-static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
-{
- float temp;
- int *rz, ofs;
- int zsamp=0;
- char *ct, *cz;
-
- /* simpleclip */
- /* if (xs<0 || ys<0) return 1.0; */
- /* if (xs>=shb->size || ys>=shb->size) return 1.0; */
-
- /* always test borders of shadowbuffer */
- if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
- if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
-
- if (shsample->deepbuf)
- return readdeepshadowbuf(shb, shsample, bias, xs, ys, zs);
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- rz= *( (int **)(shsample->zbuf+ofs) );
-
- if (*ct==3) {
- ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
- cz= (char *)&zsamp;
- cz[ACOMP]= ct[0];
- cz[BCOMP]= ct[1];
- cz[GCOMP]= ct[2];
- }
- else if (*ct==2) {
- ct= ((char *)rz);
- ct+= 4+2*16*(ys & 15)+2*(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[BCOMP]= ct[0];
- cz[GCOMP]= ct[1];
- }
- else if (*ct==1) {
- ct= ((char *)rz);
- ct+= 4+16*(ys & 15)+(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[GCOMP]= ct[0];
-
- }
- else {
- /* got warning on this for 64 bits.... */
- /* but it's working code! in this case rz is not a pointer but zvalue (ton) */
- zsamp= GET_INT_FROM_POINTER(rz);
- }
-
- /* tricky stuff here; we use ints which can overflow easily with bias values */
-
- if (zsamp > zs) return 1.0; /* absolute no shadow */
- else if (zs < - 0x7FFFFE00 + bias) return 1.0; /* extreme close to clipstart */
- else if (zsamp < zs-bias) return 0.0; /* absolute in shadow */
- else { /* soft area */
-
- temp= ( (float)(zs- zsamp) )/(float)bias;
- return 1.0f - temp*temp;
-
- }
-}
-
-static void shadowbuf_project_co(float *x, float *y, float *z, ShadBuf *shb, const float co[3])
-{
- float hco[4], size= 0.5f*(float)shb->size;
-
- copy_v3_v3(hco, co);
- hco[3]= 1.0f;
-
- mul_m4_v4(shb->persmat, hco);
-
- *x= size*(1.0f+hco[0]/hco[3]);
- *y= size*(1.0f+hco[1]/hco[3]);
- if (z) *z= (hco[2]/hco[3]);
-}
-
-/* the externally called shadow testing (reading) function */
-/* return 1.0: no shadow at all */
-float testshadowbuf(Render *re, ShadBuf *shb, const float co[3], const float dxco[3], const float dyco[3], float inp, float mat_bias)
-{
- ShadSampleBuf *shsample;
- float fac, dco[3], dx[3], dy[3], shadfac=0.0f;
- float xs1, ys1, zs1, *jit, *weight, xres, yres, biasf;
- int xs, ys, zs, bias, *rz;
- short a, num;
-
- /* crash preventer */
- if (shb->buffers.first==NULL)
- return 1.0f;
-
- /* when facing away, assume fully in shadow */
- if (inp <= 0.0f)
- return 0.0f;
-
- /* project coordinate to pixel space */
- shadowbuf_project_co(&xs1, &ys1, &zs1, shb, co);
-
- /* clip z coordinate, z is projected so that (-1.0, 1.0) matches
- * (clipstart, clipend), so we can do this simple test */
- if (zs1>=1.0f)
- return 0.0f;
- else if (zs1<= -1.0f)
- return 1.0f;
-
- zs= ((float)0x7FFFFFFF)*zs1;
-
- /* take num*num samples, increase area with fac */
- num= get_render_shadow_samples(&re->r, shb->samp);
- num= num*num;
- fac= shb->soft;
-
- /* compute z bias */
- if (mat_bias!=0.0f) biasf= shb->bias*mat_bias;
- else biasf= shb->bias;
- /* with inp==1.0, bias is half the size. correction value was 1.1, giving errors
- * on cube edges, with one side being almost frontal lighted (ton) */
- bias= (1.5f-inp*inp)*biasf;
-
- /* in case of no filtering we can do things simpler */
- if (num==1) {
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
- shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
-
- return shadfac/(float)shb->totbuf;
- }
-
- /* calculate filter size */
- add_v3_v3v3(dco, co, dxco);
- shadowbuf_project_co(&dx[0], &dx[1], NULL, shb, dco);
- dx[0]= xs1 - dx[0];
- dx[1]= ys1 - dx[1];
-
- add_v3_v3v3(dco, co, dyco);
- shadowbuf_project_co(&dy[0], &dy[1], NULL, shb, dco);
- dy[0]= xs1 - dy[0];
- dy[1]= ys1 - dy[1];
-
- xres = fac * (fabsf(dx[0]) + fabsf(dy[0]));
- yres = fac * (fabsf(dx[1]) + fabsf(dy[1]));
- if (xres<1.0f) xres= 1.0f;
- if (yres<1.0f) yres= 1.0f;
-
- /* make xs1/xs1 corner of sample area */
- xs1 -= xres*0.5f;
- ys1 -= yres*0.5f;
-
- /* in case we have a constant value in a tile, we can do quicker lookup */
- if (xres<16.0f && yres<16.0f) {
- shsample= shb->buffers.first;
- if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)ys1, 0)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)ys1, 1)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)(ys1+yres), 1)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)(ys1+yres), 1)) {
- return readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
- }
- }
- }
- }
- }
-
- /* full jittered shadow buffer lookup */
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
- jit= shb->jit;
- weight= shb->weight;
-
- for (a=num; a>0; a--, jit+=2, weight++) {
- /* instead of jit i tried random: ugly! */
- /* note: the plus 0.5 gives best sampling results, jit goes from -0.5 to 0.5 */
- /* xs1 and ys1 are already corrected to be corner of sample area */
- xs= xs1 + xres*(jit[0] + 0.5f);
- ys= ys1 + yres*(jit[1] + 0.5f);
-
- shadfac+= *weight * readshadowbuf(shb, shsample, bias, xs, ys, zs);
- }
- }
-
- /* Renormalizes for the sample number: */
- return shadfac/(float)shb->totbuf;
-}
-
-/* different function... sampling behind clipend can be LIGHT, bias is negative! */
-/* return: light */
-static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, int ys, int zs)
-{
- float temp;
- int *rz, ofs;
- int bias, zbias, zsamp;
- char *ct, *cz;
-
- /* negative! The other side is more important */
- bias= -shb->bias;
-
- /* simpleclip */
- if (xs<0 || ys<0) return 0.0;
- if (xs>=shb->size || ys>=shb->size) return 0.0;
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- rz= *( (int **)(shsample->zbuf+ofs) );
-
- if (*ct==3) {
- ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
- cz= (char *)&zsamp;
- zsamp= 0;
- cz[ACOMP]= ct[0];
- cz[BCOMP]= ct[1];
- cz[GCOMP]= ct[2];
- }
- else if (*ct==2) {
- ct= ((char *)rz);
- ct+= 4+2*16*(ys & 15)+2*(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[BCOMP]= ct[0];
- cz[GCOMP]= ct[1];
- }
- else if (*ct==1) {
- ct= ((char *)rz);
- ct+= 4+16*(ys & 15)+(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[GCOMP]= ct[0];
-
- }
- else {
- /* same as before */
- /* still working code! (ton) */
- zsamp= GET_INT_FROM_POINTER(rz);
- }
-
- /* NO schadow when sampled at 'eternal' distance */
-
- if (zsamp >= 0x7FFFFE00) return 1.0;
-
- if (zsamp > zs) return 1.0; /* absolute no shadww */
- else {
- /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */
- zbias= 0x7fffffff - zs;
- if (zbias > -bias) {
- if ( zsamp < zs-bias) return 0.0; /* absolute in shadow */
- }
- else return 0.0; /* absolute shadow */
- }
-
- /* soft area */
-
- temp= ( (float)(zs- zsamp) )/(float)bias;
- return 1.0f - temp*temp;
-}
-
-
-float shadow_halo(LampRen *lar, const float p1[3], const float p2[3])
-{
- /* p1 p2 already are rotated in spot-space */
- ShadBuf *shb= lar->shb;
- ShadSampleBuf *shsample;
- float co[4], siz;
- float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
- float zf, xf1, yf1, zf1, xf2, yf2, zf2;
- float count, lightcount;
- int x, y, z, xs1, ys1;
- int dx = 0, dy = 0;
-
- siz= 0.5f*(float)shb->size;
-
- co[0]= p1[0];
- co[1]= p1[1];
- co[2]= p1[2]/lar->sh_zfac;
- co[3]= 1.0;
- mul_m4_v4(shb->winmat, co); /* rational hom co */
- xf1= siz*(1.0f+co[0]/co[3]);
- yf1= siz*(1.0f+co[1]/co[3]);
- zf1= (co[2]/co[3]);
-
-
- co[0]= p2[0];
- co[1]= p2[1];
- co[2]= p2[2]/lar->sh_zfac;
- co[3]= 1.0;
- mul_m4_v4(shb->winmat, co); /* rational hom co */
- xf2= siz*(1.0f+co[0]/co[3]);
- yf2= siz*(1.0f+co[1]/co[3]);
- zf2= (co[2]/co[3]);
-
- /* the 2dda (a pixel line formula) */
-
- xs1= (int)xf1;
- ys1= (int)yf1;
-
- if (xf1 != xf2) {
- if (xf2-xf1 > 0.0f) {
- lambda_x= (xf1-xs1-1.0f)/(xf1-xf2);
- ldx= -shb->shadhalostep/(xf1-xf2);
- dx= shb->shadhalostep;
- }
- else {
- lambda_x= (xf1-xs1)/(xf1-xf2);
- ldx= shb->shadhalostep/(xf1-xf2);
- dx= -shb->shadhalostep;
- }
- }
- else {
- lambda_x= 1.0;
- ldx= 0.0;
- }
-
- if (yf1 != yf2) {
- if (yf2-yf1 > 0.0f) {
- lambda_y= (yf1-ys1-1.0f)/(yf1-yf2);
- ldy= -shb->shadhalostep/(yf1-yf2);
- dy= shb->shadhalostep;
- }
- else {
- lambda_y= (yf1-ys1)/(yf1-yf2);
- ldy= shb->shadhalostep/(yf1-yf2);
- dy= -shb->shadhalostep;
- }
- }
- else {
- lambda_y= 1.0;
- ldy= 0.0;
- }
-
- x= xs1;
- y= ys1;
- lambda= count= lightcount= 0.0;
-
-/* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */
-
- do {
- lambda_o= lambda;
-
- if (lambda_x==lambda_y) {
- lambda_x+= ldx;
- x+= dx;
- lambda_y+= ldy;
- y+= dy;
- }
- else {
- if (lambda_x<lambda_y) {
- lambda_x+= ldx;
- x+= dx;
- }
- else {
- lambda_y+= ldy;
- y+= dy;
- }
- }
-
- lambda = min_ff(lambda_x, lambda_y);
-
- /* not making any progress? */
- if (lambda==lambda_o) break;
-
- /* clip to end of volume */
- lambda = min_ff(lambda, 1.0f);
-
- zf= zf1 + lambda*(zf2-zf1);
- count+= (float)shb->totbuf;
-
- if (zf<= -1.0f) lightcount += 1.0f; /* close to the spot */
- else {
-
- /* make sure, behind the clipend we extend halolines. */
- if (zf>=1.0f) z= 0x7FFFF000;
- else z= (int)(0x7FFFF000*zf);
-
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
- lightcount+= readshadowbuf_halo(shb, shsample, x, y, z);
-
- }
- }
- while (lambda < 1.0f);
-
- if (count!=0.0f) return (lightcount/count);
- return 0.0f;
-
-}
-
-
-/* ********************* Irregular Shadow Buffer (ISB) ************* */
-/* ********** storage of all view samples in a raster of lists ***** */
-
-/* based on several articles describing this method, like:
- * The Irregular Z-Buffer and its Application to Shadow Mapping
- * Gregory S. Johnson - William R. Mark - Christopher A. Burns
- * and
- * Alias-Free Shadow Maps
- * Timo Aila and Samuli Laine
- */
-
-/* bsp structure (actually kd tree) */
-
-#define BSPMAX_SAMPLE 128
-#define BSPMAX_DEPTH 32
-
-/* aligned with struct rctf */
-typedef struct Boxf {
- float xmin, xmax;
- float ymin, ymax;
- float zmin, zmax;
-} Boxf;
-
-typedef struct ISBBranch {
- struct ISBBranch *left, *right;
- float divider[2];
- Boxf box;
- short totsamp, index, full, unused;
- ISBSample **samples;
-} ISBBranch;
-
-typedef struct BSPFace {
- Boxf box;
- const float *v1, *v2, *v3, *v4;
- int obi; /* object for face lookup */
- int facenr; /* index to retrieve VlakRen */
- int type; /* only for strand now */
- short shad_alpha, is_full;
-
- /* strand caching data, optimize for point_behind_strand() */
- float radline, radline_end, len;
- float vec1[3], vec2[3], rc[3];
-} BSPFace;
-
-/* boxes are in lamp projection */
-static void init_box(Boxf *box)
-{
- box->xmin = 1000000.0f;
- box->xmax = 0;
- box->ymin = 1000000.0f;
- box->ymax = 0;
- box->zmin= 0x7FFFFFFF;
- box->zmax= - 0x7FFFFFFF;
-}
-
-/* use v1 to calculate boundbox */
-static void bound_boxf(Boxf *box, const float v1[3])
-{
- if (v1[0] < box->xmin) box->xmin = v1[0];
- if (v1[0] > box->xmax) box->xmax = v1[0];
- if (v1[1] < box->ymin) box->ymin = v1[1];
- if (v1[1] > box->ymax) box->ymax = v1[1];
- if (v1[2] < box->zmin) box->zmin= v1[2];
- if (v1[2] > box->zmax) box->zmax= v1[2];
-}
-
-/* use v1 to calculate boundbox */
-static void bound_rectf(rctf *box, const float v1[2])
-{
- if (v1[0] < box->xmin) box->xmin = v1[0];
- if (v1[0] > box->xmax) box->xmax = v1[0];
- if (v1[1] < box->ymin) box->ymin = v1[1];
- if (v1[1] > box->ymax) box->ymax = v1[1];
-}
-
-
-/* halfway splitting, for initializing a more regular tree */
-static void isb_bsp_split_init(ISBBranch *root, MemArena *mem, int level)
-{
-
- /* if level > 0 we create new branches and go deeper */
- if (level > 0) {
- ISBBranch *left, *right;
- int i;
-
- /* splitpoint */
- root->divider[0]= 0.5f*(root->box.xmin+root->box.xmax);
- root->divider[1]= 0.5f*(root->box.ymin+root->box.ymax);
-
- /* find best splitpoint */
- if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
- i = root->index = 0;
- else
- i = root->index = 1;
-
- left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
- right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
-
- /* box info */
- left->box= root->box;
- right->box= root->box;
- if (i==0) {
- left->box.xmax = root->divider[0];
- right->box.xmin = root->divider[0];
- }
- else {
- left->box.ymax = root->divider[1];
- right->box.ymin = root->divider[1];
- }
- isb_bsp_split_init(left, mem, level-1);
- isb_bsp_split_init(right, mem, level-1);
- }
- else {
- /* we add sample array */
- root->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
- }
-}
-
-/* note; if all samples on same location we just spread them over 2 new branches */
-static void isb_bsp_split(ISBBranch *root, MemArena *mem)
-{
- ISBBranch *left, *right;
- ISBSample *samples[BSPMAX_SAMPLE];
- int a, i;
-
- /* splitpoint */
- root->divider[0]= root->divider[1]= 0.0f;
- for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
- root->divider[0]+= root->samples[a]->zco[0];
- root->divider[1]+= root->samples[a]->zco[1];
- }
- root->divider[0]/= BSPMAX_SAMPLE;
- root->divider[1]/= BSPMAX_SAMPLE;
-
- /* find best splitpoint */
- if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
- i = root->index = 0;
- else
- i = root->index = 1;
-
- /* new branches */
- left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
- right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
-
- /* new sample array */
- left->samples = BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
- right->samples = samples; /* tmp */
-
- /* split samples */
- for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
- int comp= 0;
- /* this prevents adding samples all to 1 branch when divider is equal to samples */
- if (root->samples[a]->zco[i] == root->divider[i])
- comp= a & 1;
- else if (root->samples[a]->zco[i] < root->divider[i])
- comp= 1;
-
- if (comp==1) {
- left->samples[left->totsamp]= root->samples[a];
- left->totsamp++;
- }
- else {
- right->samples[right->totsamp]= root->samples[a];
- right->totsamp++;
- }
- }
-
- /* copy samples from tmp */
- memcpy(root->samples, samples, right->totsamp*(sizeof(void *)));
- right->samples= root->samples;
- root->samples= NULL;
-
- /* box info */
- left->box= root->box;
- right->box= root->box;
- if (i==0) {
- left->box.xmax = root->divider[0];
- right->box.xmin = root->divider[0];
- }
- else {
- left->box.ymax = root->divider[1];
- right->box.ymin = root->divider[1];
- }
-}
-
-/* inserts sample in main tree, also splits on threshold */
-/* returns 1 if error */
-static int isb_bsp_insert(ISBBranch *root, MemArena *memarena, ISBSample *sample)
-{
- ISBBranch *bspn= root;
- const float *zco= sample->zco;
- int i= 0;
-
- /* debug counter, also used to check if something was filled in ever */
- root->totsamp++;
-
- /* going over branches until last one found */
- while (bspn->left) {
- if (zco[bspn->index] <= bspn->divider[bspn->index])
- bspn= bspn->left;
- else
- bspn= bspn->right;
- i++;
- }
- /* bspn now is the last branch */
-
- if (bspn->totsamp==BSPMAX_SAMPLE) {
- printf("error in bsp branch\n"); /* only for debug, cannot happen */
- return 1;
- }
-
- /* insert */
- bspn->samples[bspn->totsamp]= sample;
- bspn->totsamp++;
-
- /* split if allowed and needed */
- if (bspn->totsamp==BSPMAX_SAMPLE) {
- if (i==BSPMAX_DEPTH) {
- bspn->totsamp--; /* stop filling in... will give errors */
- return 1;
- }
- isb_bsp_split(bspn, memarena);
- }
- return 0;
-}
-
-/* initialize vars in face, for optimal point-in-face test */
-static void bspface_init_strand(BSPFace *face)
-{
-
- face->radline= 0.5f* len_v2v2(face->v1, face->v2);
-
- mid_v3_v3v3(face->vec1, face->v1, face->v2);
- if (face->v4)
- mid_v3_v3v3(face->vec2, face->v3, face->v4);
- else
- copy_v3_v3(face->vec2, face->v3);
-
- face->rc[0]= face->vec2[0]-face->vec1[0];
- face->rc[1]= face->vec2[1]-face->vec1[1];
- face->rc[2]= face->vec2[2]-face->vec1[2];
-
- face->len= face->rc[0]*face->rc[0]+ face->rc[1]*face->rc[1];
-
- if (face->len != 0.0f) {
- face->radline_end = face->radline / sqrtf(face->len);
- face->len = 1.0f / face->len;
- }
-}
-
-/* brought back to a simple 2d case */
-static int point_behind_strand(const float p[3], BSPFace *face)
-{
- /* v1 - v2 is radius, v1 - v3 length */
- float dist, rc[2], pt[2];
-
- /* using code from dist_to_line_segment_v2(), distance vec to line-piece */
-
- if (face->len==0.0f) {
- rc[0]= p[0]-face->vec1[0];
- rc[1]= p[1]-face->vec1[1];
- dist = len_v2(rc);
-
- if (dist < face->radline)
- return 1;
- }
- else {
- float lambda= ( face->rc[0]*(p[0]-face->vec1[0]) + face->rc[1]*(p[1]-face->vec1[1]) )*face->len;
-
- if (lambda > -face->radline_end && lambda < 1.0f+face->radline_end) {
- /* hesse for dist: */
- //dist= (float)(fabs( (p[0]-vec2[0])*rc[1] + (p[1]-vec2[1])*rc[0])/len);
-
- pt[0]= lambda*face->rc[0]+face->vec1[0];
- pt[1]= lambda*face->rc[1]+face->vec1[1];
-
- rc[0]= pt[0]-p[0];
- rc[1]= pt[1]-p[1];
- dist = len_v2(rc);
-
- if (dist < face->radline) {
- float zval= face->vec1[2] + lambda*face->rc[2];
- if (p[2] > zval)
- return 1;
- }
- }
- }
- return 0;
-}
-
-
-/* return 1 if inside. code derived from src/parametrizer.c */
-static int point_behind_tria2d(const float p[3], const float v1[3], const float v2[3], const float v3[3])
-{
- float a[2], c[2], h[2], div;
- float u, v;
-
- a[0] = v2[0] - v1[0];
- a[1] = v2[1] - v1[1];
- c[0] = v3[0] - v1[0];
- c[1] = v3[1] - v1[1];
-
- div = a[0]*c[1] - a[1]*c[0];
- if (div==0.0f)
- return 0;
-
- h[0] = p[0] - v1[0];
- h[1] = p[1] - v1[1];
-
- div = 1.0f/div;
-
- u = (h[0]*c[1] - h[1]*c[0])*div;
- if (u >= 0.0f) {
- v = (a[0]*h[1] - a[1]*h[0])*div;
- if (v >= 0.0f) {
- if ( u + v <= 1.0f) {
- /* inside, now check if point p is behind */
- float z= (1.0f-u-v)*v1[2] + u*v2[2] + v*v3[2];
- if (z <= p[2])
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-#if 0
-/* tested these calls, but it gives inaccuracy, 'side' cannot be found reliably using v3 */
-
-/* check if line v1-v2 has all rect points on other side of point v3 */
-static int rect_outside_line(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
-{
- float a, b, c;
- int side;
-
- /* line formula for v1-v2 */
- a= v2[1]-v1[1];
- b= v1[0]-v2[0];
- c= -a*v1[0] - b*v1[1];
- side= a*v3[0] + b*v3[1] + c < 0.0f;
-
- /* the four quad points */
- if ( side==(rect->xmin*a + rect->ymin*b + c >= 0.0f) )
- if ( side==(rect->xmax*a + rect->ymin*b + c >= 0.0f) )
- if ( side==(rect->xmax*a + rect->ymax*b + c >= 0.0f) )
- if ( side==(rect->xmin*a + rect->ymax*b + c >= 0.0f) )
- return 1;
- return 0;
-}
-
-/* check if one of the triangle edges separates all rect points on 1 side */
-static int rect_isect_tria(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
-{
- if (rect_outside_line(rect, v1, v2, v3))
- return 0;
- if (rect_outside_line(rect, v2, v3, v1))
- return 0;
- if (rect_outside_line(rect, v3, v1, v2))
- return 0;
- return 1;
-}
-#endif
-
-/* if face overlaps a branch, it executes func. recursive */
-static void isb_bsp_face_inside(ISBBranch *bspn, BSPFace *face)
-{
-
- /* are we descending? */
- if (bspn->left) {
- /* hrmf, the box struct cannot be addressed with index */
- if (bspn->index==0) {
- if (face->box.xmin <= bspn->divider[0])
- isb_bsp_face_inside(bspn->left, face);
- if (face->box.xmax > bspn->divider[0])
- isb_bsp_face_inside(bspn->right, face);
- }
- else {
- if (face->box.ymin <= bspn->divider[1])
- isb_bsp_face_inside(bspn->left, face);
- if (face->box.ymax > bspn->divider[1])
- isb_bsp_face_inside(bspn->right, face);
- }
- }
- else {
- /* else: end branch reached */
- int a;
-
- if (bspn->totsamp==0) return;
-
- /* check for nodes entirely in shadow, can be skipped */
- if (bspn->totsamp==bspn->full)
- return;
-
- /* if bsp node is entirely in front of face, give up */
- if (bspn->box.zmax < face->box.zmin)
- return;
-
- /* if face boundbox is outside of branch rect, give up */
- if (0==BLI_rctf_isect((rctf *)&face->box, (rctf *)&bspn->box, NULL))
- return;
-
- /* test all points inside branch */
- for (a=bspn->totsamp-1; a>=0; a--) {
- ISBSample *samp= bspn->samples[a];
-
- if ((samp->facenr!=face->facenr || samp->obi!=face->obi) && samp->shadfac) {
- if (face->box.zmin < samp->zco[2]) {
- if (BLI_rctf_isect_pt_v((rctf *)&face->box, samp->zco)) {
- int inshadow= 0;
-
- if (face->type) {
- if (point_behind_strand(samp->zco, face))
- inshadow= 1;
- }
- else if ( point_behind_tria2d(samp->zco, face->v1, face->v2, face->v3))
- inshadow= 1;
- else if (face->v4 && point_behind_tria2d(samp->zco, face->v1, face->v3, face->v4))
- inshadow= 1;
-
- if (inshadow) {
- *(samp->shadfac) += face->shad_alpha;
- /* optimize; is_full means shad_alpha==4096 */
- if (*(samp->shadfac) >= 4096 || face->is_full) {
- bspn->full++;
- samp->shadfac= NULL;
- }
- }
- }
- }
- }
- }
- }
-}
-
-/* based on available samples, recalculate the bounding box for bsp nodes, recursive */
-static void isb_bsp_recalc_box(ISBBranch *root)
-{
- if (root->left) {
- isb_bsp_recalc_box(root->left);
- isb_bsp_recalc_box(root->right);
- }
- else if (root->totsamp) {
- int a;
-
- init_box(&root->box);
- for (a=root->totsamp-1; a>=0; a--)
- bound_boxf(&root->box, root->samples[a]->zco);
- }
-}
-
-/* callback function for zbuf clip */
-static void isb_bsp_test_strand(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- BSPFace face;
-
- face.v1= v1;
- face.v2= v2;
- face.v3= v3;
- face.v4= v4;
- face.obi= obi;
- face.facenr= zvlnr & ~RE_QUAD_OFFS;
- face.type= R_STRAND;
- if (R.osa)
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
- else
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
-
- face.is_full= (zspan->shad_alpha==1.0f);
-
- /* setup boundbox */
- init_box(&face.box);
- bound_boxf(&face.box, v1);
- bound_boxf(&face.box, v2);
- bound_boxf(&face.box, v3);
- if (v4)
- bound_boxf(&face.box, v4);
-
- /* optimize values */
- bspface_init_strand(&face);
-
- isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
-
-}
-
-/* callback function for zbuf clip */
-static void isb_bsp_test_face(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- BSPFace face;
-
- face.v1= v1;
- face.v2= v2;
- face.v3= v3;
- face.v4= v4;
- face.obi= obi;
- face.facenr= zvlnr & ~RE_QUAD_OFFS;
- face.type= 0;
- if (R.osa)
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
- else
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
-
- face.is_full= (zspan->shad_alpha==1.0f);
-
- /* setup boundbox */
- init_box(&face.box);
- bound_boxf(&face.box, v1);
- bound_boxf(&face.box, v2);
- bound_boxf(&face.box, v3);
- if (v4)
- bound_boxf(&face.box, v4);
-
- isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
-}
-
-static int testclip_minmax(const float ho[4], const float minmax[4])
-{
- float wco= ho[3];
- int flag= 0;
-
- if ( ho[0] > minmax[1]*wco) flag = 1;
- else if ( ho[0]< minmax[0]*wco) flag = 2;
-
- if ( ho[1] > minmax[3]*wco) flag |= 4;
- else if ( ho[1]< minmax[2]*wco) flag |= 8;
-
- return flag;
-}
-
-/* main loop going over all faces and check in bsp overlaps, fill in shadfac values */
-static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- ShadBuf *shb= lar->shb;
- ZSpan zspan, zspanstrand;
- VlakRen *vlr= NULL;
- Material *ma= NULL;
- float minmaxf[4], winmat[4][4];
- int size= shb->size;
- int i, a, ok=1, lay= -1;
-
- /* further optimize, also sets minz maxz */
- isb_bsp_recalc_box(root);
-
- /* extra clipping for minmax */
- minmaxf[0]= (2.0f*root->box.xmin - size-2.0f)/size;
- minmaxf[1]= (2.0f*root->box.xmax - size+2.0f)/size;
- minmaxf[2]= (2.0f*root->box.ymin - size-2.0f)/size;
- minmaxf[3]= (2.0f*root->box.ymax - size+2.0f)/size;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- /* (ab)use zspan, since we use zbuffer clipping code */
- zbuf_alloc_span(&zspan, size, size, re->clipcrop);
-
- zspan.zmulx= ((float)size)/2.0f;
- zspan.zmuly= ((float)size)/2.0f;
- zspan.zofsx= -0.5f;
- zspan.zofsy= -0.5f;
-
- /* pass on bsp root to zspan */
- zspan.rectz= (int *)root;
-
- /* filling methods */
- zspanstrand= zspan;
- // zspan.zbuflinefunc= zbufline_onlyZ;
- zspan.zbuffunc= isb_bsp_test_face;
- zspanstrand.zbuffunc= isb_bsp_test_strand;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, shb->persmat, obi->mat);
- else
- copy_m4_m4(winmat, shb->persmat);
-
- for (a=0; a<obr->totvlak; a++) {
-
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- if (ma->material_type == MA_TYPE_WIRE) ok= 0;
- zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha;
- }
-
- if (ok && (obi->lay & lay)) {
- float hoco[4][4];
- int c1, c2, c3, c4=0;
- int d1, d2, d3, d4=0;
- int partclip;
-
- /* create hocos per face, it is while render */
- projectvert(vlr->v1->co, winmat, hoco[0]); d1= testclip_minmax(hoco[0], minmaxf);
- projectvert(vlr->v2->co, winmat, hoco[1]); d2= testclip_minmax(hoco[1], minmaxf);
- projectvert(vlr->v3->co, winmat, hoco[2]); d3= testclip_minmax(hoco[2], minmaxf);
- if (vlr->v4) {
- projectvert(vlr->v4->co, winmat, hoco[3]); d4= testclip_minmax(hoco[3], minmaxf);
- }
-
- /* minmax clipping */
- if (vlr->v4) partclip= d1 & d2 & d3 & d4;
- else partclip= d1 & d2 & d3;
-
- if (partclip==0) {
-
- /* window clipping */
- c1= testclip(hoco[0]);
- c2= testclip(hoco[1]);
- c3= testclip(hoco[2]);
- if (vlr->v4)
- c4= testclip(hoco[3]);
-
- /* ***** NO WIRE YET */
- if (ma->material_type == MA_TYPE_WIRE) {
- if (vlr->v4)
- zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- else
- zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], NULL, c1, c2, c3, 0);
- }
- else if (vlr->v4) {
- if (vlr->flag & R_STRAND)
- zbufclip4(&zspanstrand, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- else
- zbufclip4(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- }
- else
- zbufclip(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], c1, c2, c3);
-
- }
- }
- }
- }
-
- zbuf_free_span(&zspan);
-}
-
-/* returns 1 when the viewpixel is visible in lampbuffer */
-static int viewpixel_to_lampbuf(ShadBuf *shb, ObjectInstanceRen *obi, VlakRen *vlr, float x, float y, float co_r[3])
-{
- float hoco[4], v1[3], nor[3];
- float dface, fac, siz;
-
- RE_vlakren_get_normal(&R, obi, vlr, nor);
- copy_v3_v3(v1, vlr->v1->co);
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, v1);
-
- /* from shadepixel() */
- dface = dot_v3v3(v1, nor);
- hoco[3]= 1.0f;
-
- /* ortho viewplane cannot intersect using view vector originating in (0, 0, 0) */
- if (R.r.mode & R_ORTHO) {
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx= 2.0f/(R.winx*R.winmat[0][0]);
- float fy= 2.0f/(R.winy*R.winmat[1][1]);
-
- hoco[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
- hoco[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
-
- /* using a*x + b*y + c*z = d equation, (a b c) is normal */
- if (nor[2]!=0.0f)
- hoco[2]= (dface - nor[0]*hoco[0] - nor[1]*hoco[1])/nor[2];
- else
- hoco[2]= 0.0f;
- }
- else {
- float div, view[3];
-
- calc_view_vector(view, x, y);
-
- div = dot_v3v3(nor, view);
- if (div==0.0f)
- return 0;
-
- fac= dface/div;
-
- hoco[0]= fac*view[0];
- hoco[1]= fac*view[1];
- hoco[2]= fac*view[2];
- }
-
- /* move 3d vector to lampbuf */
- mul_m4_v4(shb->persmat, hoco); /* rational hom co */
-
- /* clip We can test for -1.0/1.0 because of the properties of the
- * coordinate transformations. */
- fac = fabsf(hoco[3]);
- if (hoco[0]<-fac || hoco[0]>fac)
- return 0;
- if (hoco[1]<-fac || hoco[1]>fac)
- return 0;
- if (hoco[2]<-fac || hoco[2]>fac)
- return 0;
-
- siz= 0.5f*(float)shb->size;
- co_r[0]= siz*(1.0f+hoco[0]/hoco[3]) -0.5f;
- co_r[1]= siz*(1.0f+hoco[1]/hoco[3]) -0.5f;
- co_r[2]= ((float)0x7FFFFFFF)*(hoco[2]/hoco[3]);
-
- /* XXXX bias, much less than normal shadbuf, or do we need a constant? */
- co_r[2] -= 0.05f*shb->bias;
-
- return 1;
-}
-
-/* storage of shadow results, solid osa and transp case */
-static void isb_add_shadfac(ISBShadfacA **isbsapp, MemArena *mem, int obi, int facenr, short shadfac, short samples)
-{
- ISBShadfacA *new;
- float shadfacf;
-
- /* in osa case, the samples were filled in with factor 1.0/R.osa. if fewer samples we have to correct */
- if (R.osa)
- shadfacf= ((float)shadfac*R.osa)/(4096.0f*samples);
- else
- shadfacf= ((float)shadfac)/(4096.0f);
-
- new= BLI_memarena_alloc(mem, sizeof(ISBShadfacA));
- new->obi= obi;
- new->facenr= facenr & ~RE_QUAD_OFFS;
- new->shadfac= shadfacf;
- if (*isbsapp)
- new->next= (*isbsapp);
- else
- new->next= NULL;
-
- *isbsapp= new;
-}
-
-/* adding samples, solid case */
-static int isb_add_samples(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSample **samplebuf)
-{
- int xi, yi, *xcos, *ycos;
- int sample, bsp_err= 0;
-
- /* bsp split doesn't like to handle regular sequences */
- xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
- ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
- for (xi=0; xi<pa->rectx; xi++)
- xcos[xi]= xi;
- for (yi=0; yi<pa->recty; yi++)
- ycos[yi]= yi;
- BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
- BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
-
- for (sample=0; sample<(R.osa?R.osa:1); sample++) {
- ISBSample *samp= samplebuf[sample], *samp1;
-
- for (yi=0; yi<pa->recty; yi++) {
- int y= ycos[yi];
- for (xi=0; xi<pa->rectx; xi++) {
- int x= xcos[xi];
- samp1= samp + y*pa->rectx + x;
- if (samp1->facenr)
- bsp_err |= isb_bsp_insert(root, memarena, samp1);
- }
- if (bsp_err) break;
- }
- }
-
- MEM_freeN(xcos);
- MEM_freeN(ycos);
-
- return bsp_err;
-}
-
-/* solid version */
-/* lar->shb, pa->rectz and pa->rectp should exist */
-static void isb_make_buffer(RenderPart *pa, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- ISBData *isbdata;
- ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */
- ISBBranch root;
- MemArena *memarena;
- intptr_t *rd;
- int *recto, *rectp, x, y, sindex, sample, bsp_err=0;
-
- /* storage for shadow, per thread */
- isbdata= shb->isb_result[pa->thread];
-
- /* to map the shi->xs and ys coordinate */
- isbdata->minx= pa->disprect.xmin;
- isbdata->miny= pa->disprect.ymin;
- isbdata->rectx= pa->rectx;
- isbdata->recty= pa->recty;
-
- /* branches are added using memarena (32k branches) */
- memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
- BLI_memarena_use_calloc(memarena);
-
- /* samplebuf is in camera view space (pixels) */
- for (sample=0; sample<(R.osa?R.osa:1); sample++)
- samplebuf[sample]= MEM_callocN(sizeof(ISBSample)*pa->rectx*pa->recty, "isb samplebuf");
-
- /* for end result, ISBSamples point to this in non OSA case, otherwise to pixstruct->shadfac */
- if (R.osa==0)
- isbdata->shadfacs= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "isb shadfacs");
-
- /* setup bsp root */
- memset(&root, 0, sizeof(ISBBranch));
- root.box.xmin = (float)shb->size;
- root.box.ymin = (float)shb->size;
-
- /* create the sample buffers */
- for (sindex=0, y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, sindex++) {
-
- /* this makes it a long function, but splitting it out would mean 10+ arguments */
- /* first check OSA case */
- if (R.osa) {
- rd= pa->rectdaps + sindex;
- if (*rd) {
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- for (sample=0; sample<R.osa; sample++) {
- PixStr *ps= (PixStr *)(*rd);
- int mask= (1<<sample);
-
- while (ps) {
- if (ps->mask & mask)
- break;
- ps= ps->next;
- }
- if (ps && ps->facenr>0) {
- ObjectInstanceRen *obi= &R.objectinstance[ps->obi];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
-
- samp= samplebuf[sample] + sindex;
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], samp->zco)) {
- samp->obi= ps->obi;
- samp->facenr= ps->facenr & ~RE_QUAD_OFFS;
- ps->shadfac= 0;
- samp->shadfac= &ps->shadfac;
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
- else {
- rectp= pa->rectp + sindex;
- recto= pa->recto + sindex;
- if (*rectp>0) {
- ObjectInstanceRen *obi= &R.objectinstance[*recto];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (*rectp-1) & RE_QUAD_MASK);
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- samp= samplebuf[0] + sindex;
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, samp->zco)) {
- samp->obi= *recto;
- samp->facenr= *rectp & ~RE_QUAD_OFFS;
- samp->shadfac= isbdata->shadfacs + sindex;
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
-
- /* simple method to see if we have samples */
- if (root.box.xmin != (float)shb->size) {
- /* now create a regular split, root.box has the initial bounding box of all pixels */
- /* split bsp 8 levels deep, in regular grid (16 x 16) */
- isb_bsp_split_init(&root, memarena, 8);
-
- /* insert all samples in BSP now */
- bsp_err= isb_add_samples(pa, &root, memarena, samplebuf);
-
- if (bsp_err==0) {
- /* go over all faces and fill in shadow values */
-
- isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
-
- /* copy shadow samples to persistent buffer, reduce memory overhead */
- if (R.osa) {
- ISBShadfacA **isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
-
- isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
- BLI_memarena_use_calloc(isbdata->memarena);
-
- for (rd= pa->rectdaps, x=pa->rectx*pa->recty; x>0; x--, rd++, isbsa++) {
-
- if (*rd) {
- PixStr *ps= (PixStr *)(*rd);
- while (ps) {
- if (ps->shadfac)
- isb_add_shadfac(isbsa, isbdata->memarena, ps->obi, ps->facenr, ps->shadfac, count_mask(ps->mask));
- ps= ps->next;
- }
- }
- }
- }
- }
- }
- else {
- if (isbdata->shadfacs) {
- MEM_freeN(isbdata->shadfacs);
- isbdata->shadfacs= NULL;
- }
- }
-
- /* free BSP */
- BLI_memarena_free(memarena);
-
- /* free samples */
- for (x=0; x<(R.osa?R.osa:1); x++)
- MEM_freeN(samplebuf[x]);
-
- if (bsp_err) printf("error in filling bsp\n");
-}
-
-/* add sample to buffer, isbsa is the root sample in a buffer */
-static ISBSampleA *isb_alloc_sample_transp(ISBSampleA **isbsa, MemArena *mem)
-{
- ISBSampleA *new;
-
- new= BLI_memarena_alloc(mem, sizeof(ISBSampleA));
- if (*isbsa)
- new->next= (*isbsa);
- else
- new->next= NULL;
-
- *isbsa= new;
- return new;
-}
-
-/* adding samples in BSP, transparent case */
-static int isb_add_samples_transp(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSampleA ***samplebuf)
-{
- int xi, yi, *xcos, *ycos;
- int sample, bsp_err= 0;
-
- /* bsp split doesn't like to handle regular sequences */
- xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
- ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
- for (xi=0; xi<pa->rectx; xi++)
- xcos[xi]= xi;
- for (yi=0; yi<pa->recty; yi++)
- ycos[yi]= yi;
- BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
- BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
-
- for (sample=0; sample<(R.osa?R.osa:1); sample++) {
- ISBSampleA **samp= samplebuf[sample], *samp1;
-
- for (yi=0; yi<pa->recty; yi++) {
- int y= ycos[yi];
- for (xi=0; xi<pa->rectx; xi++) {
- int x= xcos[xi];
-
- samp1= *(samp + y*pa->rectx + x);
- while (samp1) {
- bsp_err |= isb_bsp_insert(root, memarena, (ISBSample *)samp1);
- samp1= samp1->next;
- }
- }
- if (bsp_err) break;
- }
- }
-
- MEM_freeN(xcos);
- MEM_freeN(ycos);
-
- return bsp_err;
-}
-
-
-/* Ztransp version */
-/* lar->shb, pa->rectz and pa->rectp should exist */
-static void isb_make_buffer_transp(RenderPart *pa, APixstr *apixbuf, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- ISBData *isbdata;
- ISBSampleA *samp, **samplebuf[16]; /* MAX_OSA */
- ISBBranch root;
- MemArena *memarena;
- APixstr *ap;
- int x, y, sindex, sample, bsp_err=0;
-
- /* storage for shadow, per thread */
- isbdata= shb->isb_result[pa->thread];
-
- /* to map the shi->xs and ys coordinate */
- isbdata->minx= pa->disprect.xmin;
- isbdata->miny= pa->disprect.ymin;
- isbdata->rectx= pa->rectx;
- isbdata->recty= pa->recty;
-
- /* branches are added using memarena (32k branches) */
- memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
- BLI_memarena_use_calloc(memarena);
-
- /* samplebuf is in camera view space (pixels) */
- for (sample=0; sample<(R.osa?R.osa:1); sample++)
- samplebuf[sample]= MEM_callocN(sizeof(void *)*pa->rectx*pa->recty, "isb alpha samplebuf");
-
- /* setup bsp root */
- memset(&root, 0, sizeof(ISBBranch));
- root.box.xmin = (float)shb->size;
- root.box.ymin = (float)shb->size;
-
- /* create the sample buffers */
- for (ap= apixbuf, sindex=0, y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, sindex++, ap++) {
-
- if (ap->p[0]) {
- APixstr *apn;
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- for (apn=ap; apn; apn= apn->next) {
- int a;
- for (a=0; a<4; a++) {
- if (apn->p[a]) {
- ObjectInstanceRen *obi= &R.objectinstance[apn->obi[a]];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (apn->p[a]-1) & RE_QUAD_MASK);
- float zco[3];
-
- /* here we store shadfac, easier to create the end storage buffer. needs zero'ed, multiple shadowbufs use it */
- apn->shadfac[a]= 0;
-
- if (R.osa) {
- for (sample=0; sample<R.osa; sample++) {
- int mask= (1<<sample);
-
- if (apn->mask[a] & mask) {
-
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], zco)) {
- samp= isb_alloc_sample_transp(samplebuf[sample] + sindex, memarena);
- samp->obi= apn->obi[a];
- samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
- samp->shadfac= &apn->shadfac[a];
-
- copy_v3_v3(samp->zco, zco);
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- else {
-
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, zco)) {
-
- samp= isb_alloc_sample_transp(samplebuf[0] + sindex, memarena);
- samp->obi= apn->obi[a];
- samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
- samp->shadfac= &apn->shadfac[a];
-
- copy_v3_v3(samp->zco, zco);
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
- }
- }
- }
-
- /* simple method to see if we have samples */
- if (root.box.xmin != (float)shb->size) {
- /* now create a regular split, root.box has the initial bounding box of all pixels */
- /* split bsp 8 levels deep, in regular grid (16 x 16) */
- isb_bsp_split_init(&root, memarena, 8);
-
- /* insert all samples in BSP now */
- bsp_err= isb_add_samples_transp(pa, &root, memarena, samplebuf);
-
- if (bsp_err==0) {
- ISBShadfacA **isbsa;
-
- /* go over all faces and fill in shadow values */
- isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
-
- /* copy shadow samples to persistent buffer, reduce memory overhead */
- isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
-
- isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
-
- for (ap= apixbuf, x=pa->rectx*pa->recty; x>0; x--, ap++, isbsa++) {
-
- if (ap->p[0]) {
- APixstr *apn;
- for (apn=ap; apn; apn= apn->next) {
- int a;
- for (a=0; a<4; a++) {
- if (apn->p[a] && apn->shadfac[a]) {
- if (R.osa)
- isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], count_mask(apn->mask[a]));
- else
- isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], 0);
- }
- }
- }
- }
- }
- }
- }
-
- /* free BSP */
- BLI_memarena_free(memarena);
-
- /* free samples */
- for (x=0; x<(R.osa?R.osa:1); x++)
- MEM_freeN(samplebuf[x]);
-
- if (bsp_err) printf("error in filling bsp\n");
-}
-
-
-
-/* exported */
-
-/* returns amount of light (1.0 = no shadow) */
-/* note, shadepixel() rounds the coordinate, not the real sample info */
-float ISB_getshadow(ShadeInput *shi, ShadBuf *shb)
-{
- /* if raytracing, we can't accept irregular shadow */
- if (shi->depth==0) {
- ISBData *isbdata= shb->isb_result[shi->thread];
-
- if (isbdata) {
- if (isbdata->shadfacs || isbdata->shadfaca) {
- int x= shi->xs - isbdata->minx;
-
- if (x >= 0 && x < isbdata->rectx) {
- int y= shi->ys - isbdata->miny;
-
- if (y >= 0 && y < isbdata->recty) {
- if (isbdata->shadfacs) {
- const short *sp= isbdata->shadfacs + y*isbdata->rectx + x;
- return *sp>=4096?0.0f:1.0f - ((float)*sp)/4096.0f;
- }
- else {
- int sindex= y*isbdata->rectx + x;
- int obi= shi->obi - R.objectinstance;
- ISBShadfacA *isbsa= *(isbdata->shadfaca + sindex);
-
- while (isbsa) {
- if (isbsa->facenr==shi->facenr+1 && isbsa->obi==obi)
- return isbsa->shadfac>=1.0f?0.0f:1.0f - isbsa->shadfac;
- isbsa= isbsa->next;
- }
- }
- }
- }
- }
- }
- }
- return 1.0f;
-}
-
-/* part is supposed to be solid zbuffered (apixbuf==NULL) or transparent zbuffered */
-void ISB_create(RenderPart *pa, APixstr *apixbuf)
-{
- GroupObject *go;
-
- /* go over all lamps, and make the irregular buffers */
- for (go=R.lights.first; go; go= go->next) {
- LampRen *lar= go->lampren;
-
- if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
-
- /* create storage for shadow, per thread */
- lar->shb->isb_result[pa->thread]= MEM_callocN(sizeof(ISBData), "isb data");
-
- if (apixbuf)
- isb_make_buffer_transp(pa, apixbuf, lar);
- else
- isb_make_buffer(pa, lar);
- }
- }
-}
-
-
-/* end of part rendering, free stored shadow data for this thread from all lamps */
-void ISB_free(RenderPart *pa)
-{
- GroupObject *go;
-
- /* go over all lamps, and free the irregular buffers */
- for (go=R.lights.first; go; go= go->next) {
- LampRen *lar= go->lampren;
-
- if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
- ISBData *isbdata= lar->shb->isb_result[pa->thread];
-
- if (isbdata) {
- if (isbdata->shadfacs)
- MEM_freeN(isbdata->shadfacs);
- if (isbdata->shadfaca)
- MEM_freeN(isbdata->shadfaca);
-
- if (isbdata->memarena)
- BLI_memarena_free(isbdata->memarena);
-
- MEM_freeN(isbdata);
- lar->shb->isb_result[pa->thread]= NULL;
- }
- }
- }
-}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
deleted file mode 100644
index 6cad37c3e78..00000000000
--- a/source/blender/render/intern/source/shadeinput.c
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * ***** 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) 2006 Blender Foundation
- * All rights reserved.
- *
- * Contributors: Hos, Robert Wenzlaff.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadeinput.c
- * \ingroup render
- */
-
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_lamp_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_material_types.h"
-#include "DNA_particle_types.h"
-
-#include "BKE_scene.h"
-
-#include "BKE_node.h"
-
-/* local include */
-#include "raycounter.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shading.h"
-#include "strand.h"
-#include "texture.h"
-#include "volumetric.h"
-#include "zbuf.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* Shade Sample order:
- *
- * - shade_samples_fill_with_ps()
- * - for each sample
- * - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle()
- * - if vlr
- * - shade_input_set_viewco() <- not for ray or bake
- * - shade_input_set_uv() <- not for ray or bake
- * - shade_input_set_normals()
- * - shade_samples()
- * - if AO
- * - shade_samples_do_AO()
- * - if shading happens
- * - for each sample
- * - shade_input_set_shade_texco()
- * - shade_samples_do_shade()
- * - OSA: distribute sample result with filter masking
- *
- */
-
-/* initialize material variables in shadeinput,
- * doing inverse gamma correction where applicable */
-void shade_input_init_material(ShadeInput *shi)
-{
- /* note, keep this synced with render_types.h */
- memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
- shi->har = shi->mat->har;
-}
-
-/* also used as callback for nodes */
-/* delivers a fully filled in ShadeResult, for all passes */
-void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
-{
-
- shade_lamp_loop(shi, shr); /* clears shr */
-
- if (shi->translucency != 0.0f) {
- ShadeResult shr_t;
- float fac = shi->translucency;
-
- shade_input_init_material(shi);
- negate_v3_v3(shi->vn, shi->vno);
- negate_v3(shi->facenor);
- shi->depth++; /* hack to get real shadow now */
- shade_lamp_loop(shi, &shr_t);
- shi->depth--;
-
- /* a couple of passes */
- madd_v3_v3fl(shr->combined, shr_t.combined, fac);
- if (shi->passflag & SCE_PASS_SPEC)
- madd_v3_v3fl(shr->spec, shr_t.spec, fac);
- if (shi->passflag & SCE_PASS_DIFFUSE) {
- madd_v3_v3fl(shr->diff, shr_t.diff, fac);
- madd_v3_v3fl(shr->diffshad, shr_t.diffshad, fac);
- }
- if (shi->passflag & SCE_PASS_SHADOW)
- madd_v3_v3fl(shr->shad, shr_t.shad, fac);
-
- negate_v3(shi->vn);
- negate_v3(shi->facenor);
- }
-
- /* depth >= 1 when ray-shading */
- if (shi->depth == 0 || shi->volume_depth > 0) {
- if (R.r.mode & R_RAYTRACE) {
- if (shi->ray_mirror != 0.0f || ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f)) {
- /* ray trace works on combined, but gives pass info */
- ray_trace(shi, shr);
- }
- }
- /* disable adding of sky for raytransp */
- if ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP))
- if ((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode == R_ADDSKY))
- shr->alpha = 1.0f;
- }
-
- if (R.r.mode & R_RAYTRACE) {
- if (R.render_volumes_inside.first)
- shade_volume_inside(shi, shr);
- }
-}
-
-
-/* do a shade, finish up some passes, apply mist */
-void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
-{
- bool compat = false;
- float alpha;
-
- /* ------ main shading loop -------- */
-#ifdef RE_RAYCOUNTER
- memset(&shi->raycounter, 0, sizeof(shi->raycounter));
-#endif
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- }
-
- /* also run this when node shaders fail, due to incompatible shader nodes */
- if (compat == false) {
- /* copy all relevant material vars, note, keep this synced with render_types.h */
- shade_input_init_material(shi);
-
- if (shi->mat->material_type == MA_TYPE_VOLUME) {
- if (R.r.mode & R_RAYTRACE) {
- shade_volume_outside(shi, shr);
- }
- }
- else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */
- shade_material_loop(shi, shr);
- }
- }
-
- /* copy additional passes */
- if (shi->passflag & (SCE_PASS_VECTOR | SCE_PASS_NORMAL)) {
- copy_v4_v4(shr->winspeed, shi->winspeed);
- copy_v3_v3(shr->nor, shi->vn);
- }
-
- /* MIST */
- if ((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0)) {
- if (R.r.mode & R_ORTHO)
- shr->mist = mistfactor(-shi->co[2], shi->co);
- else
- shr->mist = mistfactor(len_v3(shi->co), shi->co);
- }
- else shr->mist = 0.0f;
-
- if ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0) {
- alpha = shr->mist;
- }
- else alpha = 1.0f;
-
- /* add mist and premul color */
- if (shr->alpha != 1.0f || alpha != 1.0f) {
- float fac = alpha * (shr->alpha);
- shr->combined[3] = fac;
-
- if (shi->mat->material_type != MA_TYPE_VOLUME)
- mul_v3_fl(shr->combined, fac);
- }
- else
- shr->combined[3] = 1.0f;
-
- /* add z */
- shr->z = -shi->co[2];
-
- /* RAYHITS */
-#if 0
- if (1 || shi->passflag & SCE_PASS_RAYHITS) {
- shr->rayhits[0] = (float)shi->raycounter.faces.test;
- shr->rayhits[1] = (float)shi->raycounter.bb.hit;
- shr->rayhits[2] = 0.0;
- shr->rayhits[3] = 1.0;
- }
-#endif
-
- RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter);
-}
-
-/* **************************************************************************** */
-/* ShadeInput */
-/* **************************************************************************** */
-
-
-void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
-{
- /* to prevent storing new tfaces or vcols, we check a split runtime */
- /* 4---3 4---3 */
- /* |\ 1| or |1 /| */
- /* |0\ | |/ 0| */
- /* 1---2 1---2 0 = orig face, 1 = new face */
-
- /* Update vert nums to point to correct verts of original face */
- if (vlr->flag & R_DIVIDE_24) {
- if (vlr->flag & R_FACE_SPLIT) {
- (*i1)++; (*i2)++; (*i3)++;
- }
- else {
- (*i3)++;
- }
- }
- else if (vlr->flag & R_FACE_SPLIT) {
- (*i2)++; (*i3)++;
- }
-}
-
-/* copy data from face to ShadeInput, general case */
-/* indices 0 1 2 3 only */
-void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3)
-{
- VertRen **vpp = &vlr->v1;
-
- shi->vlr = vlr;
- shi->obi = obi;
- shi->obr = obi->obr;
-
- shi->v1 = vpp[i1];
- shi->v2 = vpp[i2];
- shi->v3 = vpp[i3];
-
- shi->i1 = i1;
- shi->i2 = i2;
- shi->i3 = i3;
-
- /* note, shi->mat is set in node shaders */
- shi->mat = vlr->mat;
-
- shi->osatex = (shi->mat->texco & TEXCO_OSA);
- shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
- shi->mode2 = shi->mat->mode2_l;
-
- /* facenormal copy, can get flipped */
- shi->flippednor = 0;
- RE_vlakren_get_normal(&R, obi, vlr, shi->facenor);
-
- /* calculate vertexnormals */
- if (vlr->flag & R_SMOOTH) {
- copy_v3_v3(shi->n1, shi->v1->n);
- copy_v3_v3(shi->n2, shi->v2->n);
- copy_v3_v3(shi->n3, shi->v3->n);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m3_v3(obi->nmat, shi->n1); normalize_v3(shi->n1);
- mul_m3_v3(obi->nmat, shi->n2); normalize_v3(shi->n2);
- mul_m3_v3(obi->nmat, shi->n3); normalize_v3(shi->n3);
- }
- }
-}
-
-/* copy data from face to ShadeInput, scanline case */
-void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip))
-{
- if (facenr > 0) {
- shi->obi = &R.objectinstance[obi];
- shi->obr = shi->obi->obr;
- shi->facenr = (facenr - 1) & RE_QUAD_MASK;
- if (shi->facenr < shi->obr->totvlak) {
- VlakRen *vlr = RE_findOrAddVlak(shi->obr, shi->facenr);
-
- if (facenr & RE_QUAD_OFFS)
- shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 1, 2);
- }
- else
- shi->vlr = NULL; /* general signal we got sky */
- }
- else
- shi->vlr = NULL; /* general signal we got sky */
-}
-
-/* full osa case: copy static info */
-void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from)
-{
- /* not so nice, but works... warning is in RE_shader_ext.h */
- memcpy(shi, from, sizeof(struct ShadeInputCopy));
-}
-
-/* copy data from strand to shadeinput */
-void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint)
-{
- /* note, shi->mat is set in node shaders */
- shi->mat = strand->buffer->ma;
-
- shi->osatex = (shi->mat->texco & TEXCO_OSA);
- shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
-
- /* shade_input_set_viewco equivalent */
- copy_v3_v3(shi->co, spoint->co);
- copy_v3_v3(shi->view, shi->co);
- normalize_v3(shi->view);
-
- shi->xs = (int)spoint->x;
- shi->ys = (int)spoint->y;
-
- if (shi->osatex || (R.r.mode & R_SHADOW)) {
- copy_v3_v3(shi->dxco, spoint->dtco);
- copy_v3_v3(shi->dyco, spoint->dsco);
- }
-
- /* dxview, dyview, not supported */
-
- /* facenormal, simply viewco flipped */
- copy_v3_v3(shi->facenor, spoint->nor);
-
- /* shade_input_set_normals equivalent */
- if (shi->mat->mode & MA_TANGENT_STR) {
- copy_v3_v3(shi->vn, spoint->tan);
- }
- else {
- float cross[3];
-
- cross_v3_v3v3(cross, spoint->co, spoint->tan);
- cross_v3_v3v3(shi->vn, cross, spoint->tan);
- normalize_v3(shi->vn);
-
- if (dot_v3v3(shi->vn, shi->view) < 0.0f)
- negate_v3(shi->vn);
- }
-
- copy_v3_v3(shi->vno, shi->vn);
-}
-
-void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint)
-{
- StrandBuffer *strandbuf = strand->buffer;
- ObjectRen *obr = strandbuf->obr;
- StrandVert *sv;
- int mode = shi->mode; /* or-ed result for all nodes */
- short texco = shi->mat->texco;
-
- if ((shi->mat->texco & TEXCO_REFL)) {
- /* shi->dxview, shi->dyview, not supported */
- }
-
- if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL))) {
- /* not supported */
- }
-
- if (mode & (MA_TANGENT_V | MA_NORMAP_TANG)) {
- copy_v3_v3(shi->tang, spoint->tan);
- copy_v3_v3(shi->nmaptang, spoint->tan);
- }
-
- if (mode & MA_STR_SURFDIFF) {
- const float *surfnor = RE_strandren_get_surfnor(obr, strand, 0);
-
- if (surfnor)
- copy_v3_v3(shi->surfnor, surfnor);
- else
- copy_v3_v3(shi->surfnor, shi->vn);
-
- if (shi->mat->strand_surfnor > 0.0f) {
- shi->surfdist = 0.0f;
- for (sv = strand->vert; sv != svert; sv++)
- shi->surfdist += len_v3v3(sv->co, (sv + 1)->co);
- shi->surfdist += spoint->t * len_v3v3(sv->co, (sv + 1)->co);
- }
- }
-
- if (R.r.mode & R_SPEED) {
- const float *speed;
-
- speed = RE_strandren_get_winspeed(shi->obi, strand, 0);
- if (speed)
- copy_v4_v4(shi->winspeed, speed);
- else
- shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
- }
-
- /* shade_input_set_shade_texco equivalent */
- if (texco & NEED_UV) {
- if (texco & TEXCO_ORCO) {
- copy_v3_v3(shi->lo, strand->orco);
- /* no shi->osatex, orco derivatives are zero */
- }
-
- if (texco & TEXCO_GLOB) {
- mul_v3_m4v3(shi->gl, R.viewinv, shi->co);
-
- if (shi->osatex) {
- mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco);
- mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco);
- }
- }
-
- if (texco & TEXCO_STRAND) {
- shi->strandco = spoint->strandco;
-
- if (shi->osatex) {
- shi->dxstrand = spoint->dtstrandco;
- shi->dystrand = 0.0f;
- }
- }
-
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP))) {
- MCol *mcol;
- const float *uv;
- char *name;
- int i;
-
- shi->totuv = 0;
- shi->totcol = 0;
- shi->actuv = obr->actmtface;
- shi->actcol = obr->actmcol;
-
- if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
- for (i = 0; (mcol = RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) {
- ShadeInputCol *scol = &shi->col[i];
- const char *cp = (char *)mcol;
-
- shi->totcol++;
- scol->name = name;
-
- scol->col[0] = cp[3] / 255.0f;
- scol->col[1] = cp[2] / 255.0f;
- scol->col[2] = cp[1] / 255.0f;
- scol->col[3] = cp[0] / 255.0f;
- }
-
- if (shi->totcol) {
- shi->vcol[0] = shi->col[shi->actcol].col[0];
- shi->vcol[1] = shi->col[shi->actcol].col[1];
- shi->vcol[2] = shi->col[shi->actcol].col[2];
- shi->vcol[3] = shi->col[shi->actcol].col[3];
- }
- else {
- shi->vcol[0] = 0.0f;
- shi->vcol[1] = 0.0f;
- shi->vcol[2] = 0.0f;
- shi->vcol[3] = 0.0f;
- }
- }
-
- for (i = 0; (uv = RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) {
- ShadeInputUV *suv = &shi->uv[i];
-
- shi->totuv++;
- suv->name = name;
-
- if (strandbuf->overrideuv == i) {
- suv->uv[0] = -1.0f;
- suv->uv[1] = spoint->strandco;
- suv->uv[2] = 0.0f;
- }
- else {
- suv->uv[0] = -1.0f + 2.0f * uv[0];
- suv->uv[1] = -1.0f + 2.0f * uv[1];
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
- }
-
- if (shi->osatex) {
- suv->dxuv[0] = 0.0f;
- suv->dxuv[1] = 0.0f;
- suv->dyuv[0] = 0.0f;
- suv->dyuv[1] = 0.0f;
- }
- }
-
- if (shi->totuv == 0) {
- ShadeInputUV *suv = &shi->uv[0];
-
- suv->uv[0] = 0.0f;
- suv->uv[1] = spoint->strandco;
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
- }
-
- }
-
- if (texco & TEXCO_NORM) {
- shi->orn[0] = -shi->vn[0];
- shi->orn[1] = -shi->vn[1];
- shi->orn[2] = -shi->vn[2];
- }
-
- if (texco & TEXCO_STRESS) {
- /* not supported */
- }
-
- if (texco & TEXCO_TANGENT) {
- if ((mode & MA_TANGENT_V) == 0) {
- /* just prevent surprises */
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
- }
- }
- }
-
- /* this only avalailable for scanline renders */
- if (shi->depth == 0) {
- if (texco & TEXCO_WINDOW) {
- shi->winco[0] = -1.0f + 2.0f * spoint->x / (float)R.winx;
- shi->winco[1] = -1.0f + 2.0f * spoint->y / (float)R.winy;
- shi->winco[2] = 0.0f;
-
- /* not supported */
- if (shi->osatex) {
- shi->dxwin[0] = 0.0f;
- shi->dywin[1] = 0.0f;
- shi->dxwin[0] = 0.0f;
- shi->dywin[1] = 0.0f;
- }
- }
- }
-
- if (shi->do_manage) {
- if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
- srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
- }
- }
-
-}
-
-/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
-void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3])
-{
- /* returns not normalized, so is in viewplane coords */
- calc_view_vector(view, x, y);
-
- if (shi->mat->material_type == MA_TYPE_WIRE) {
- /* wire cannot use normal for calculating shi->co, so
- * we reconstruct the coordinate less accurate */
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(co, x, y, z);
- else
- calc_renderco_zbuf(co, view, z);
- }
- else {
- /* for non-wire, intersect with the triangle to get the exact coord */
- float fac, dface, v1[3];
-
- copy_v3_v3(v1, shi->v1->co);
- if (shi->obi->flag & R_TRANSFORMED)
- mul_m4_v3(shi->obi->mat, v1);
-
- dface = dot_v3v3(v1, shi->facenor);
-
- /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */
- if (R.r.mode & R_ORTHO) {
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx = 2.0f / (R.winx * R.winmat[0][0]);
- float fy = 2.0f / (R.winy * R.winmat[1][1]);
-
- co[0] = (x - 0.5f * R.winx) * fx - R.winmat[3][0] / R.winmat[0][0];
- co[1] = (y - 0.5f * R.winy) * fy - R.winmat[3][1] / R.winmat[1][1];
-
- /* using a*x + b*y + c*z = d equation, (a b c) is normal */
- if (shi->facenor[2] != 0.0f)
- co[2] = (dface - shi->facenor[0] * co[0] - shi->facenor[1] * co[1]) / shi->facenor[2];
- else
- co[2] = 0.0f;
-
- if (dxco && dyco) {
- dxco[0] = fx;
- dxco[1] = 0.0f;
- if (shi->facenor[2] != 0.0f)
- dxco[2] = -(shi->facenor[0] * fx) / shi->facenor[2];
- else
- dxco[2] = 0.0f;
-
- dyco[0] = 0.0f;
- dyco[1] = fy;
- if (shi->facenor[2] != 0.0f)
- dyco[2] = -(shi->facenor[1] * fy) / shi->facenor[2];
- else
- dyco[2] = 0.0f;
-
- if (dxyview) {
- fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f;
- dxyview[0] = -R.viewdx * fac;
- dxyview[1] = -R.viewdy * fac;
- }
- }
- }
- else {
- float div;
-
- div = dot_v3v3(shi->facenor, view);
- if (div != 0.0f) fac = dface / div;
- else fac = 0.0f;
-
- co[0] = fac * view[0];
- co[1] = fac * view[1];
- co[2] = fac * view[2];
-
- /* pixel dx/dy for render coord */
- if (dxco && dyco) {
- float u = dface / (div - R.viewdx * shi->facenor[0]);
- float v = dface / (div - R.viewdy * shi->facenor[1]);
-
- dxco[0] = co[0] - (view[0] - R.viewdx) * u;
- dxco[1] = co[1] - (view[1]) * u;
- dxco[2] = co[2] - (view[2]) * u;
-
- dyco[0] = co[0] - (view[0]) * v;
- dyco[1] = co[1] - (view[1] - R.viewdy) * v;
- dyco[2] = co[2] - (view[2]) * v;
-
- if (dxyview) {
- if (fac != 0.0f) fac = 1.0f / fac;
- dxyview[0] = -R.viewdx * fac;
- dxyview[1] = -R.viewdy * fac;
- }
- }
- }
- }
-
- /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space)
- * however for raytrace it can be different - the position of the last intersection */
- shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f;
-
- /* cannot normalize earlier, code above needs it at viewplane level */
- normalize_v3(view);
-}
-
-/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
-void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z)
-{
- float *dxyview = NULL, *dxco = NULL, *dyco = NULL;
-
- /* currently in use for dithering (soft shadow), node preview, irregular shad */
- shi->xs = (int)xs;
- shi->ys = (int)ys;
-
- /* original scanline coordinate without jitter */
- shi->scanco[0] = x;
- shi->scanco[1] = y;
- shi->scanco[2] = z;
-
- /* check if we need derivatives */
- if (shi->osatex || (R.r.mode & R_SHADOW)) {
- dxco = shi->dxco;
- dyco = shi->dyco;
-
- if ((shi->mat->texco & TEXCO_REFL))
- dxyview = &shi->dxview;
- }
-
- shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco);
-}
-
-void barycentric_differentials_from_position(
- const float co[3], const float v1[3], const float v2[3], const float v3[3],
- const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
- float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
-{
- /* find most stable axis to project */
- int axis1, axis2;
- axis_dominant_v3(&axis1, &axis2, facenor);
-
- /* compute u,v and derivatives */
- float t00 = v3[axis1] - v1[axis1];
- float t01 = v3[axis2] - v1[axis2];
- float t10 = v3[axis1] - v2[axis1];
- float t11 = v3[axis2] - v2[axis2];
-
- float detsh = (t00 * t11 - t10 * t01);
- detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
- t00 *= detsh; t01 *= detsh;
- t10 *= detsh; t11 *= detsh;
-
- *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
- *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
- if (differentials) {
- *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
- *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
- *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
- *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
- }
-}
-/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
-void shade_input_set_uv(ShadeInput *shi)
-{
- VlakRen *vlr = shi->vlr;
-
- if ((vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) {
- float v1[3], v2[3], v3[3];
-
- copy_v3_v3(v1, shi->v1->co);
- copy_v3_v3(v2, shi->v2->co);
- copy_v3_v3(v3, shi->v3->co);
-
- if (shi->obi->flag & R_TRANSFORMED) {
- mul_m4_v3(shi->obi->mat, v1);
- mul_m4_v3(shi->obi->mat, v2);
- mul_m4_v3(shi->obi->mat, v3);
- }
-
- /* exception case for wire render of edge */
- if (vlr->v2 == vlr->v3) {
- float lend, lenc;
-
- lend = len_v3v3(v2, v1);
- lenc = len_v3v3(shi->co, v1);
-
- if (lend == 0.0f) {
- shi->u = shi->v = 0.0f;
- }
- else {
- shi->u = -(1.0f - lenc / lend);
- shi->v = 0.0f;
- }
-
- if (shi->osatex) {
- shi->dx_u = 0.0f;
- shi->dx_v = 0.0f;
- shi->dy_u = 0.0f;
- shi->dy_v = 0.0f;
- }
- }
- else {
- barycentric_differentials_from_position(
- shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex,
- &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v);
-
- shi->u = -shi->u;
- shi->v = -shi->v;
-
- /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
- CLAMP(shi->u, -2.0f, 1.0f);
- CLAMP(shi->v, -2.0f, 1.0f);
- }
- }
-}
-
-void shade_input_set_normals(ShadeInput *shi)
-{
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v;
-
- shi->flippednor = 0;
-
- /* test flip normals to viewing direction */
- if (!(shi->vlr->flag & R_TANGENT)) {
- if (dot_v3v3(shi->facenor, shi->view) < 0.0f) {
- negate_v3(shi->facenor);
- shi->flippednor = 1;
- }
- }
-
- /* calculate vertexnormals */
- if (shi->vlr->flag & R_SMOOTH) {
- float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- if (shi->flippednor) {
- negate_v3(n1);
- negate_v3(n2);
- negate_v3(n3);
- }
-
- shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
- shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
- shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
-
- /* use unnormalized normal (closer to games) */
- copy_v3_v3(shi->nmapnorm, shi->vn);
-
- normalize_v3(shi->vn);
- }
- else {
- copy_v3_v3(shi->vn, shi->facenor);
- copy_v3_v3(shi->nmapnorm, shi->vn);
- }
-
- /* used in nodes */
- copy_v3_v3(shi->vno, shi->vn);
-
- /* flip normals to viewing direction */
- if (!(shi->vlr->flag & R_TANGENT))
- if (dot_v3v3(shi->facenor, shi->view) < 0.0f)
- shade_input_flip_normals(shi);
-}
-
-/* XXX shi->flippednor messes up otherwise */
-void shade_input_set_vertex_normals(ShadeInput *shi)
-{
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v;
-
- /* calculate vertexnormals */
- if (shi->vlr->flag & R_SMOOTH) {
- const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
- shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
- shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
-
- /* use unnormalized normal (closer to games) */
- copy_v3_v3(shi->nmapnorm, shi->vn);
-
- normalize_v3(shi->vn);
- }
- else {
- copy_v3_v3(shi->vn, shi->facenor);
- copy_v3_v3(shi->nmapnorm, shi->vn);
- }
-
- /* used in nodes */
- copy_v3_v3(shi->vno, shi->vn);
-}
-
-
-/* use by raytrace, sss, bake to flip into the right direction */
-void shade_input_flip_normals(ShadeInput *shi)
-{
- negate_v3(shi->facenor);
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- shi->flippednor = !shi->flippednor;
-}
-
-void shade_input_set_shade_texco(ShadeInput *shi)
-{
- ObjectInstanceRen *obi = shi->obi;
- ObjectRen *obr = shi->obr;
- VertRen *v1 = shi->v1, *v2 = shi->v2, *v3 = shi->v3;
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v, dl;
- int mode = shi->mode; /* or-ed result for all nodes */
- int mode2 = shi->mode2;
- short texco = shi->mat->texco;
- const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
- const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
-
- /* calculate dxno */
- if (shi->vlr->flag & R_SMOOTH) {
-
- if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL)) ) {
- const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- dl = shi->dx_u + shi->dx_v;
- shi->dxno[0] = dl * n3[0] - shi->dx_u * n1[0] - shi->dx_v * n2[0];
- shi->dxno[1] = dl * n3[1] - shi->dx_u * n1[1] - shi->dx_v * n2[1];
- shi->dxno[2] = dl * n3[2] - shi->dx_u * n1[2] - shi->dx_v * n2[2];
- dl = shi->dy_u + shi->dy_v;
- shi->dyno[0] = dl * n3[0] - shi->dy_u * n1[0] - shi->dy_v * n2[0];
- shi->dyno[1] = dl * n3[1] - shi->dy_u * n1[1] - shi->dy_v * n2[1];
- shi->dyno[2] = dl * n3[2] - shi->dy_u * n1[2] - shi->dy_v * n2[2];
-
- }
- }
-
- /* calc tangents */
- if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
- const float *s1, *s2, *s3;
- float tl, tu, tv;
-
- if (shi->vlr->flag & R_SMOOTH) {
- tl = l;
- tu = u;
- tv = v;
- }
- else {
- /* qdn: flat faces have tangents too,
- * could pick either one, using average here */
- tl = 1.0f / 3.0f;
- tu = -1.0f / 3.0f;
- tv = -1.0f / 3.0f;
- }
-
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
-
- if (mode & MA_TANGENT_V) {
- s1 = RE_vertren_get_tangent(obr, v1, 0);
- s2 = RE_vertren_get_tangent(obr, v2, 0);
- s3 = RE_vertren_get_tangent(obr, v3, 0);
-
- if (s1 && s2 && s3) {
- shi->tang[0] = (tl * s3[0] - tu * s1[0] - tv * s2[0]);
- shi->tang[1] = (tl * s3[1] - tu * s1[1] - tv * s2[1]);
- shi->tang[2] = (tl * s3[2] - tu * s1[2] - tv * s2[2]);
-
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, shi->tang);
-
- normalize_v3(shi->tang);
- copy_v3_v3(shi->nmaptang, shi->tang);
- }
- }
-
- if (need_mikk_tangent || need_mikk_tangent_concrete) {
- int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
- float c0[3], c1[3], c2[3];
- int acttang = obr->actmtface;
-
- vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
-
- /* cycle through all tangent in vlakren */
- for (int i = 0; i < MAX_MTFACE; i++) {
- const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
- if (!tangent)
- continue;
-
- copy_v3_v3(c0, &tangent[j1 * 4]);
- copy_v3_v3(c1, &tangent[j2 * 4]);
- copy_v3_v3(c2, &tangent[j3 * 4]);
-
- /* keeping tangents normalized at vertex level
- * corresponds better to how it's done in game engines */
- if (obi->flag & R_TRANSFORMED) {
- mul_mat3_m4_v3(obi->mat, c0); normalize_v3(c0);
- mul_mat3_m4_v3(obi->mat, c1); normalize_v3(c1);
- mul_mat3_m4_v3(obi->mat, c2); normalize_v3(c2);
- }
-
- /* we don't normalize the interpolated TBN tangent
- * corresponds better to how it's done in game engines */
- shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
- shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
- shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
-
- /* the sign is the same for all 3 vertices of any
- * non degenerate triangle. */
- shi->tangents[i][3] = tangent[j1 * 4 + 3];
-
- if (acttang == i && need_mikk_tangent) {
- for (int m = 0; m < 4; m++) {
- shi->nmaptang[m] = shi->tangents[i][m];
- }
- }
- }
- }
- }
-
- if (mode & MA_STR_SURFDIFF) {
- const float *surfnor = RE_vlakren_get_surfnor(obr, shi->vlr, 0);
-
- if (surfnor) {
- copy_v3_v3(shi->surfnor, surfnor);
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, shi->surfnor);
- }
- else
- copy_v3_v3(shi->surfnor, shi->vn);
-
- shi->surfdist = 0.0f;
- }
-
- if (R.r.mode & R_SPEED) {
- const float *s1, *s2, *s3;
-
- s1 = RE_vertren_get_winspeed(obi, v1, 0);
- s2 = RE_vertren_get_winspeed(obi, v2, 0);
- s3 = RE_vertren_get_winspeed(obi, v3, 0);
- if (s1 && s2 && s3) {
- shi->winspeed[0] = (l * s3[0] - u * s1[0] - v * s2[0]);
- shi->winspeed[1] = (l * s3[1] - u * s1[1] - v * s2[1]);
- shi->winspeed[2] = (l * s3[2] - u * s1[2] - v * s2[2]);
- shi->winspeed[3] = (l * s3[3] - u * s1[3] - v * s2[3]);
- }
- else {
- shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
- }
- }
-
- /* pass option forces UV calc */
- if ((shi->passflag & SCE_PASS_UV) || (R.flag & R_NEED_VCOL))
- texco |= (NEED_UV | TEXCO_UV);
-
- /* texture coordinates. shi->dxuv shi->dyuv have been set */
- if (texco & NEED_UV) {
-
- if (texco & TEXCO_ORCO) {
- if (v1->orco) {
- const float *o1, *o2, *o3;
-
- o1 = v1->orco;
- o2 = v2->orco;
- o3 = v3->orco;
-
- shi->lo[0] = l * o3[0] - u * o1[0] - v * o2[0];
- shi->lo[1] = l * o3[1] - u * o1[1] - v * o2[1];
- shi->lo[2] = l * o3[2] - u * o1[2] - v * o2[2];
-
- if (shi->osatex) {
- dl = shi->dx_u + shi->dx_v;
- shi->dxlo[0] = dl * o3[0] - shi->dx_u * o1[0] - shi->dx_v * o2[0];
- shi->dxlo[1] = dl * o3[1] - shi->dx_u * o1[1] - shi->dx_v * o2[1];
- shi->dxlo[2] = dl * o3[2] - shi->dx_u * o1[2] - shi->dx_v * o2[2];
- dl = shi->dy_u + shi->dy_v;
- shi->dylo[0] = dl * o3[0] - shi->dy_u * o1[0] - shi->dy_v * o2[0];
- shi->dylo[1] = dl * o3[1] - shi->dy_u * o1[1] - shi->dy_v * o2[1];
- shi->dylo[2] = dl * o3[2] - shi->dy_u * o1[2] - shi->dy_v * o2[2];
- }
- }
-
- copy_v3_v3(shi->duplilo, obi->dupliorco);
- }
-
- if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
- if (shi->osatex) {
- copy_v3_v3(shi->dxgl, shi->dxco);
- mul_mat3_m4_v3(R.viewinv, shi->dxgl);
- copy_v3_v3(shi->dygl, shi->dyco);
- mul_mat3_m4_v3(R.viewinv, shi->dygl);
- }
- }
-
- if (texco & TEXCO_STRAND) {
- shi->strandco = (l * v3->accum - u * v1->accum - v * v2->accum);
- if (shi->osatex) {
- dl = shi->dx_u + shi->dx_v;
- shi->dxstrand = dl * v3->accum - shi->dx_u * v1->accum - shi->dx_v * v2->accum;
- dl = shi->dy_u + shi->dy_v;
- shi->dystrand = dl * v3->accum - shi->dy_u * v1->accum - shi->dy_v * v2->accum;
- }
- }
-
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
- VlakRen *vlr = shi->vlr;
- MTFace *tface;
- MCol *mcol;
- char *name;
- int i, j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
-
- /* uv and vcols are not copied on split, so set them according vlr divide flag */
- vlr_set_uv_indices(vlr, &j1, &j2, &j3);
-
- shi->totuv = 0;
- shi->totcol = 0;
- shi->actuv = obr->actmtface;
- shi->actcol = obr->actmcol;
-
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
- for (i = 0; (mcol = RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) {
- ShadeInputCol *scol = &shi->col[i];
- const char *cp1, *cp2, *cp3;
- float a[3];
-
- shi->totcol++;
- scol->name = name;
-
- cp1 = (char *)(mcol + j1);
- cp2 = (char *)(mcol + j2);
- cp3 = (char *)(mcol + j3);
-
- /* alpha values */
- a[0] = ((float)cp1[0]) / 255.f;
- a[1] = ((float)cp2[0]) / 255.f;
- a[2] = ((float)cp3[0]) / 255.f;
- scol->col[3] = l * a[2] - u * a[0] - v * a[1];
-
- /* sample premultiplied color value */
- scol->col[0] = (l * ((float)cp3[3]) * a[2] - u * ((float)cp1[3]) * a[0] - v * ((float)cp2[3]) * a[1]) / 255.f;
- scol->col[1] = (l * ((float)cp3[2]) * a[2] - u * ((float)cp1[2]) * a[0] - v * ((float)cp2[2]) * a[1]) / 255.f;
- scol->col[2] = (l * ((float)cp3[1]) * a[2] - u * ((float)cp1[1]) * a[0] - v * ((float)cp2[1]) * a[1]) / 255.f;
-
- /* if not zero alpha, restore non-multiplied color */
- if (scol->col[3]) {
- mul_v3_fl(scol->col, 1.0f / scol->col[3]);
- }
- }
-
- if (shi->totcol) {
- shi->vcol[0] = shi->col[shi->actcol].col[0];
- shi->vcol[1] = shi->col[shi->actcol].col[1];
- shi->vcol[2] = shi->col[shi->actcol].col[2];
- shi->vcol[3] = shi->col[shi->actcol].col[3];
- }
- else {
- shi->vcol[0] = 0.0f;
- shi->vcol[1] = 0.0f;
- shi->vcol[2] = 0.0f;
- shi->vcol[3] = 1.0f;
- }
- }
-
- for (i = 0; (tface = RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) {
- ShadeInputUV *suv = &shi->uv[i];
- const float *uv1 = tface->uv[j1];
- const float *uv2 = tface->uv[j2];
- const float *uv3 = tface->uv[j3];
-
- shi->totuv++;
- suv->name = name;
-
- if ((shi->mat->mapflag & MA_MAPFLAG_UVPROJECT) && (shi->depth == 0)) {
- float x = shi->xs;
- float y = shi->ys;
-
- float s1[2] = {-1.0f + 2.0f * uv1[0], -1.0f + 2.0f * uv1[1]};
- float s2[2] = {-1.0f + 2.0f * uv2[0], -1.0f + 2.0f * uv2[1]};
- float s3[2] = {-1.0f + 2.0f * uv3[0], -1.0f + 2.0f * uv3[1]};
-
-
- float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4];
- float Zmulx, Zmuly;
- float hox, hoy, l_proj, dl_proj, u_proj, v_proj;
- float s00, s01, s10, s11, detsh;
-
- /* old globals, localized now */
- Zmulx = ((float)R.winx) / 2.0f;
- Zmuly = ((float)R.winy) / 2.0f;
-
- zbuf_make_winmat(&R, winmat);
- if (shi->obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- zbuf_render_project(obwinmat, v1->co, ho1);
- zbuf_render_project(obwinmat, v2->co, ho2);
- zbuf_render_project(obwinmat, v3->co, ho3);
-
- s00 = ho3[0] / ho3[3] - ho1[0] / ho1[3];
- s01 = ho3[1] / ho3[3] - ho1[1] / ho1[3];
- s10 = ho3[0] / ho3[3] - ho2[0] / ho2[3];
- s11 = ho3[1] / ho3[3] - ho2[1] / ho2[3];
-
- detsh = s00 * s11 - s10 * s01;
- detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
- s00 *= detsh; s01 *= detsh;
- s10 *= detsh; s11 *= detsh;
-
- /* recalc u and v again */
- hox = x / Zmulx - 1.0f;
- hoy = y / Zmuly - 1.0f;
- u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10;
- v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01;
- l_proj = 1.0f + u_proj + v_proj;
-
- suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0];
- suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1];
- suv->uv[2] = 0.0f;
-
- if (shi->osatex) {
- float dxuv[2], dyuv[2];
- dxuv[0] = s11 / Zmulx;
- dxuv[1] = -s01 / Zmulx;
- dyuv[0] = -s10 / Zmuly;
- dyuv[1] = s00 / Zmuly;
-
- dl_proj = dxuv[0] + dxuv[1];
- suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0];
- suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1];
- dl_proj = dyuv[0] + dyuv[1];
- suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0];
- suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1];
- }
- }
- else {
-
- suv->uv[0] = -1.0f + 2.0f * (l * uv3[0] - u * uv1[0] - v * uv2[0]);
- suv->uv[1] = -1.0f + 2.0f * (l * uv3[1] - u * uv1[1] - v * uv2[1]);
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
-
- if (shi->osatex) {
- float duv[2];
-
- dl = shi->dx_u + shi->dx_v;
- duv[0] = shi->dx_u;
- duv[1] = shi->dx_v;
-
- suv->dxuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
- suv->dxuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
-
- dl = shi->dy_u + shi->dy_v;
- duv[0] = shi->dy_u;
- duv[1] = shi->dy_v;
-
- suv->dyuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
- suv->dyuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
- }
- }
- }
-
- shi->dupliuv[0] = -1.0f + 2.0f * obi->dupliuv[0];
- shi->dupliuv[1] = -1.0f + 2.0f * obi->dupliuv[1];
- shi->dupliuv[2] = 0.0f;
-
- if (shi->totuv == 0) {
- ShadeInputUV *suv = &shi->uv[0];
-
- suv->uv[0] = 2.0f * (u + .5f);
- suv->uv[1] = 2.0f * (v + .5f);
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
- }
- }
-
- if (texco & TEXCO_NORM) {
- shi->orn[0] = -shi->vn[0];
- shi->orn[1] = -shi->vn[1];
- shi->orn[2] = -shi->vn[2];
- }
-
- if (texco & TEXCO_STRESS) {
- const float *s1, *s2, *s3;
-
- s1 = RE_vertren_get_stress(obr, v1, 0);
- s2 = RE_vertren_get_stress(obr, v2, 0);
- s3 = RE_vertren_get_stress(obr, v3, 0);
- if (s1 && s2 && s3) {
- shi->stress = l * s3[0] - u * s1[0] - v * s2[0];
- if (shi->stress < 1.0f) shi->stress -= 1.0f;
- else shi->stress = (shi->stress - 1.0f) / shi->stress;
- }
- else shi->stress = 0.0f;
- }
-
- if (texco & TEXCO_TANGENT) {
- if ((mode & MA_TANGENT_V) == 0) {
- /* just prevent surprises */
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
- }
- }
- }
-
- /* this only avalailable for scanline renders */
- if (shi->depth == 0) {
- float x = shi->xs;
- float y = shi->ys;
-
- if (texco & TEXCO_WINDOW) {
- shi->winco[0] = -1.0f + 2.0f * x / (float)R.winx;
- shi->winco[1] = -1.0f + 2.0f * y / (float)R.winy;
- shi->winco[2] = 0.0f;
- if (shi->osatex) {
- shi->dxwin[0] = 2.0f / (float)R.winx;
- shi->dywin[1] = 2.0f / (float)R.winy;
- shi->dxwin[1] = shi->dxwin[2] = 0.0f;
- shi->dywin[0] = shi->dywin[2] = 0.0f;
- }
- }
- }
- /* else {
- * Note! For raytracing winco is not set,
- * important because thus means all shader input's need to have their variables set to zero
- * else un-initialized values are used
- */
- if (shi->do_manage) {
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
- srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
- }
- }
-
-}
-
-/* ****************** ShadeSample ************************************** */
-
-/* initialize per part, not per pixel! */
-void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
-{
-
- memset(shi, 0, sizeof(ShadeInput));
-
- shi->sample = sample;
- shi->thread = pa->thread;
- shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0;
-
- shi->do_manage = BKE_scene_check_color_management_enabled(R.scene);
- shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene);
-
- shi->lay = (1 << 20) - 1;
- shi->layflag = rl->layflag;
- shi->passflag = rl->passflag;
- shi->combinedflag = ~rl->pass_xor;
-// shi->rl= rl;
- /* note shi.depth==0 means first hit, not raytracing */
-
-}
-
-/* initialize per part, not per pixel! */
-void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl)
-{
- int a, tot;
-
- tot = R.osa == 0 ? 1 : R.osa;
-
- for (a = 0; a < tot; a++) {
- shade_input_initialize(&ssamp->shi[a], pa, rl, a);
- memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
- }
-
- get_sample_layers(pa, rl, ssamp->rlpp);
-}
-
-/* Do AO or (future) GI */
-void shade_samples_do_AO(ShadeSample *ssamp)
-{
- if (!(R.r.mode & R_SHADOW))
- return;
- if (!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
-
- if (R.wrld.mode & (WO_AMB_OCC | WO_ENV_LIGHT | WO_INDIRECT_LIGHT)) {
- ShadeInput *shi = &ssamp->shi[0];
- int sample;
-
- if (((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) ||
- (shi->passflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT)))
- {
- for (sample = 0; sample < ssamp->tot; shi++, sample++)
- if (!(shi->mode & MA_SHLESS))
- ambient_occlusion(shi); /* stores in shi->ao[] */
- }
- }
-}
-
-
-void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
-{
- ShadeInput *shi;
- float xs, ys;
-
- ssamp->tot = 0;
-
- for (shi = ssamp->shi; ps; ps = ps->next) {
- shade_input_set_triangle(shi, ps->obi, ps->facenr, 1);
-
- if (shi->vlr) { /* NULL happens for env material or for 'all z' */
- unsigned short curmask = ps->mask;
-
- /* full osa is only set for OSA renders */
- if (shi->vlr->flag & R_FULL_OSA) {
- short shi_cp = 0, samp;
-
- for (samp = 0; samp < R.osa; samp++) {
- if (curmask & (1 << samp)) {
- /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
- xs = (float)x + R.jit[samp][0] + 0.5f;
- ys = (float)y + R.jit[samp][1] + 0.5f;
-
- if (shi_cp)
- shade_input_copy_triangle(shi, shi - 1);
-
- shi->mask = (1 << samp);
-// shi->rl= ssamp->rlpp[samp];
- shi->samplenr = R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */
- shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
- shade_input_set_uv(shi);
- if (shi_cp == 0)
- shade_input_set_normals(shi);
- else /* XXX shi->flippednor messes up otherwise */
- shade_input_set_vertex_normals(shi);
-
- shi_cp = 1;
- shi++;
- }
- }
- }
- else {
- if (R.osa) {
- short b = R.samples->centmask[curmask];
- xs = (float)x + R.samples->centLut[b & 15] + 0.5f;
- ys = (float)y + R.samples->centLut[b >> 4] + 0.5f;
- }
- else if (R.i.curblur) {
- xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f;
- ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f;
- }
- else {
- xs = (float)x + 0.5f;
- ys = (float)y + 0.5f;
- }
-
- shi->mask = curmask;
- shi->samplenr = R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
- shi++;
- }
-
- /* total sample amount, shi->sample is static set in initialize */
- if (shi != ssamp->shi)
- ssamp->tot = (shi - 1)->sample + 1;
- }
- }
-}
-
-/* shades samples, returns true if anything happened */
-int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y)
-{
- shade_samples_fill_with_ps(ssamp, ps, x, y);
-
- if (ssamp->tot) {
- ShadeInput *shi = ssamp->shi;
- ShadeResult *shr = ssamp->shr;
- int samp;
-
- /* if shadow or AO? */
- shade_samples_do_AO(ssamp);
-
- /* if shade (all shadepinputs have same passflag) */
- if (ssamp->shi[0].passflag & ~(SCE_PASS_Z | SCE_PASS_INDEXOB | SCE_PASS_INDEXMA)) {
-
- for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) {
- shade_input_set_shade_texco(shi);
- shade_input_do_shade(shi, shr);
- }
- }
- else if (shi->passflag & SCE_PASS_Z) {
- for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++)
- shr->z = -shi->co[2];
- }
-
- return 1;
- }
- return 0;
-}
-
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
deleted file mode 100644
index f3e391672a9..00000000000
--- a/source/blender/render/intern/source/shadeoutput.c
+++ /dev/null
@@ -1,2162 +0,0 @@
-/*
- * ***** 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) 2006 Blender Foundation
- * All rights reserved.
- *
- * Contributors: Hos, Robert Wenzlaff.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadeoutput.c
- * \ingroup render
- */
-
-#include <stdio.h>
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_colorband.h"
-#include "BKE_colortools.h"
-#include "BKE_material.h"
-
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-
-/* local include */
-#include "occlusion.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "sss.h"
-#include "texture.h"
-
-#include "shading.h" /* own include */
-
-#include "IMB_colormanagement.h"
-
-/* could enable at some point but for now there are far too many conversions */
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
-#endif
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-ListBase *get_lights(ShadeInput *shi)
-{
-
- if (R.r.scemode & R_BUTS_PREVIEW)
- return &R.lights;
- if (shi->mat && shi->mat->group)
- return &shi->mat->group->gobject;
-
- return &R.lights;
-}
-
-#if 0
-static void fogcolor(const float colf[3], float *rco, float *view)
-{
- float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3];
- float div=0.0f, distfac;
-
- hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
- zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
-
- copy_v3_v3(vec, rco);
-
- /* we loop from cur coord to mist start in steps */
- stepsize= 1.0f;
-
- div= ABS(view[2]);
- dview[0]= view[0]/(stepsize*div);
- dview[1]= view[1]/(stepsize*div);
- dview[2]= -stepsize;
-
- startdist= -rco[2] + BLI_frand();
- for (dist= startdist; dist>R.wrld.miststa; dist-= stepsize) {
-
- hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
- alpha= 1.0f;
- do_sky_tex(vec, vec, NULL, hor, zen, &alpha);
-
- distfac= (dist-R.wrld.miststa)/R.wrld.mistdist;
-
- hor[3]= hor[0]*distfac*distfac;
-
- /* premul! */
- alpha= hor[3];
- hor[0]= hor[0]*alpha;
- hor[1]= hor[1]*alpha;
- hor[2]= hor[2]*alpha;
- addAlphaOverFloat(colf, hor);
-
- sub_v3_v3(vec, dview);
- }
-}
-#endif
-
-/* zcor is distance, co the 3d coordinate in eye space, return alpha */
-float mistfactor(float zcor, float const co[3])
-{
- float fac, hi;
-
- fac = zcor - R.wrld.miststa; /* zcor is calculated per pixel */
-
- /* fac= -co[2]-R.wrld.miststa; */
-
- if (fac > 0.0f) {
- if (fac < R.wrld.mistdist) {
-
- fac = (fac / R.wrld.mistdist);
-
- if (R.wrld.mistype == 0) {
- fac *= fac;
- }
- else if (R.wrld.mistype == 1) {
- /* pass */
- }
- else {
- fac = sqrtf(fac);
- }
- }
- else {
- fac = 1.0f;
- }
- }
- else {
- fac = 0.0f;
- }
-
- /* height switched off mist */
- if (R.wrld.misthi!=0.0f && fac!=0.0f) {
- /* at height misthi the mist is completely gone */
-
- hi = R.viewinv[0][2] * co[0] +
- R.viewinv[1][2] * co[1] +
- R.viewinv[2][2] * co[2] +
- R.viewinv[3][2];
-
- if (hi > R.wrld.misthi) {
- fac = 0.0f;
- }
- else if (hi>0.0f) {
- hi= (R.wrld.misthi-hi)/R.wrld.misthi;
- fac*= hi*hi;
- }
- }
-
- return (1.0f-fac)* (1.0f-R.wrld.misi);
-}
-
-static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
-{
- double a, b, c, disc, nray[3], npos[3];
- double t0, t1 = 0.0f, t2= 0.0f, t3;
- float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
- int cuts;
- bool do_clip = true, use_yco = false;
-
- *intens= 0.0f;
- haint= lar->haint;
-
- if (R.r.mode & R_ORTHO) {
- /* camera pos (view vector) cannot be used... */
- /* camera position (cox,coy,0) rotate around lamp */
- p1[0]= shi->co[0]-lar->co[0];
- p1[1]= shi->co[1]-lar->co[1];
- p1[2]= -lar->co[2];
- mul_m3_v3(lar->imat, p1);
- copy_v3db_v3fl(npos, p1); /* npos is double! */
-
- /* pre-scale */
- npos[2] *= (double)lar->sh_zfac;
- }
- else {
- copy_v3db_v3fl(npos, lar->sh_invcampos); /* in initlamp calculated */
- }
-
- /* rotate view */
- copy_v3db_v3fl(nray, shi->view);
- mul_m3_v3_double(lar->imat, nray);
-
- if (R.wrld.mode & WO_MIST) {
- /* patchy... */
- haint *= mistfactor(-lar->co[2], lar->co);
- if (haint==0.0f) {
- return;
- }
- }
-
-
- /* rotate maxz */
- if (shi->co[2]==0.0f) {
- do_clip = false; /* for when halo at sky */
- }
- else {
- p1[0]= shi->co[0]-lar->co[0];
- p1[1]= shi->co[1]-lar->co[1];
- p1[2]= shi->co[2]-lar->co[2];
-
- maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
- maxz*= lar->sh_zfac;
- maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
-
- if (fabs(nray[2]) < FLT_EPSILON) {
- use_yco = true;
- }
- }
-
- /* scale z to make sure volume is normalized */
- nray[2] *= (double)lar->sh_zfac;
- /* nray does not need normalization */
-
- ladist= lar->sh_zfac*lar->dist;
-
- /* solve */
- a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
- b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
- c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
-
- cuts= 0;
- if (fabs(a) < DBL_EPSILON) {
- /*
- * Only one intersection point...
- */
- return;
- }
- else {
- disc = b*b - a*c;
-
- if (disc==0.0) {
- t1=t2= (-b)/ a;
- cuts= 2;
- }
- else if (disc > 0.0) {
- disc = sqrt(disc);
- t1 = (-b + disc) / a;
- t2 = (-b - disc) / a;
- cuts= 2;
- }
- }
- if (cuts==2) {
- int ok1=0, ok2=0;
-
- /* sort */
- if (t1>t2) {
- a= t1; t1= t2; t2= a;
- }
-
- /* z of intersection points with diabolo */
- p1[2]= npos[2] + t1*nray[2];
- p2[2]= npos[2] + t2*nray[2];
-
- /* evaluate both points */
- if (p1[2]<=0.0f) ok1= 1;
- if (p2[2]<=0.0f && t1!=t2) ok2= 1;
-
- /* at least 1 point with negative z */
- if (ok1==0 && ok2==0) return;
-
- /* intersction point with -ladist, the bottom of the cone */
- if (use_yco == false) {
- t3= ((double)(-ladist)-npos[2])/nray[2];
-
- /* de we have to replace one of the intersection points? */
- if (ok1) {
- if (p1[2]<-ladist) t1= t3;
- }
- else {
- t1= t3;
- }
- if (ok2) {
- if (p2[2]<-ladist) t2= t3;
- }
- else {
- t2= t3;
- }
- }
- else if (ok1==0 || ok2==0) return;
-
- /* at least 1 visible interesction point */
- if (t1<0.0 && t2<0.0) return;
-
- if (t1<0.0) t1= 0.0;
- if (t2<0.0) t2= 0.0;
-
- if (t1==t2) return;
-
- /* sort again to be sure */
- if (t1>t2) {
- a= t1; t1= t2; t2= a;
- }
-
- /* calculate t0: is the maximum visible z (when halo is intersected by face) */
- if (do_clip) {
- if (use_yco == false) t0 = ((double)maxz - npos[2]) / nray[2];
- else t0 = ((double)maxy - npos[1]) / nray[1];
-
- if (t0 < t1) return;
- if (t0 < t2) t2= t0;
- }
-
- /* calc points */
- p1[0]= npos[0] + t1*nray[0];
- p1[1]= npos[1] + t1*nray[1];
- p1[2]= npos[2] + t1*nray[2];
- p2[0]= npos[0] + t2*nray[0];
- p2[1]= npos[1] + t2*nray[1];
- p2[2]= npos[2] + t2*nray[2];
-
-
- /* now we have 2 points, make three lengths with it */
-
- a = len_v3(p1);
- b = len_v3(p2);
- c = len_v3v3(p1, p2);
-
- a/= ladist;
- a= sqrt(a);
- b/= ladist;
- b= sqrt(b);
- c/= ladist;
-
- *intens= c*( (1.0-a)+(1.0-b) );
-
- /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows
- * at the edges (especially with narrow halos) */
- if (*intens<=0.0f) return;
-
- /* soft area */
- /* not needed because t0 has been used for p1/p2 as well */
- /* if (doclip && t0<t2) { */
- /* *intens *= (t0-t1)/(t2-t1); */
- /* } */
-
- *intens *= haint;
-
- if (lar->shb && lar->shb->shadhalostep) {
- *intens *= shadow_halo(lar, p1, p2);
- }
-
- }
-}
-
-void renderspothalo(ShadeInput *shi, float col[4], float alpha)
-{
- ListBase *lights;
- GroupObject *go;
- LampRen *lar;
- float i;
-
- if (alpha==0.0f) return;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- if (lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) {
-
- if (lar->mode & LA_LAYER)
- if (shi->vlr && (lar->lay & shi->obi->lay)==0)
- continue;
- if ((lar->lay & shi->lay)==0)
- continue;
-
- spothalo(lar, shi, &i);
- if (i > 0.0f) {
- const float i_alpha = i * alpha;
- col[0] += i_alpha * lar->r;
- col[1] += i_alpha * lar->g;
- col[2] += i_alpha * lar->b;
- col[3] += i_alpha; /* all premul */
- }
- }
- }
- /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */
- if (col[3]>1.0f) col[3]= 1.0f;
-}
-
-
-
-/* ---------------- shaders ----------------------- */
-
-static double Normalize_d(double *n)
-{
- double d;
-
- d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
-
- if (d>0.00000000000000001) {
- d= sqrt(d);
-
- n[0]/=d;
- n[1]/=d;
- n[2]/=d;
- }
- else {
- n[0]=n[1]=n[2]= 0.0;
- d= 0.0;
- }
- return d;
-}
-
-/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
-float fresnel_fac(const float view[3], const float vn[3], float grad, float fac)
-{
- float t1, t2;
-
- if (fac==0.0f) return 1.0f;
-
- t1 = dot_v3v3(view, vn);
- if (t1>0.0f) t2= 1.0f+t1;
- else t2= 1.0f-t1;
-
- t2= grad + (1.0f-grad)*powf(t2, fac);
-
- if (t2<0.0f) return 0.0f;
- else if (t2>1.0f) return 1.0f;
- return t2;
-}
-
-static double saacos_d(double fac)
-{
- if (fac<= -1.0) return M_PI;
- else if (fac>=1.0) return 0.0;
- else return acos(fac);
-}
-
-/* Stoke's form factor. Need doubles here for extreme small area sizes */
-static float area_lamp_energy(float (*area)[3], const float co[3], const float vn[3])
-{
- double fac;
- double vec[4][3]; /* vectors of rendered co to vertices lamp */
- double cross[4][3]; /* cross products of this */
- double rad[4]; /* angles between vecs */
-
- VECSUB(vec[0], co, area[0]);
- VECSUB(vec[1], co, area[1]);
- VECSUB(vec[2], co, area[2]);
- VECSUB(vec[3], co, area[3]);
-
- Normalize_d(vec[0]);
- Normalize_d(vec[1]);
- Normalize_d(vec[2]);
- Normalize_d(vec[3]);
-
- /* cross product */
-#define CROSS(dest, a, b) \
- { \
- dest[0]= a[1] * b[2] - a[2] * b[1]; \
- dest[1]= a[2] * b[0] - a[0] * b[2]; \
- dest[2]= a[0] * b[1] - a[1] * b[0]; \
- } (void)0
-
- CROSS(cross[0], vec[0], vec[1]);
- CROSS(cross[1], vec[1], vec[2]);
- CROSS(cross[2], vec[2], vec[3]);
- CROSS(cross[3], vec[3], vec[0]);
-
-#undef CROSS
-
- Normalize_d(cross[0]);
- Normalize_d(cross[1]);
- Normalize_d(cross[2]);
- Normalize_d(cross[3]);
-
- /* angles */
- rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
- rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
- rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
- rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
-
- rad[0]= saacos_d(rad[0]);
- rad[1]= saacos_d(rad[1]);
- rad[2]= saacos_d(rad[2]);
- rad[3]= saacos_d(rad[3]);
-
- /* Stoke formula */
- fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]);
- fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]);
- fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]);
- fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
-
- if (fac<=0.0) return 0.0;
- return fac;
-}
-
-static float area_lamp_energy_multisample(LampRen *lar, const float co[3], float *vn)
-{
- /* corner vectors are moved around according lamp jitter */
- float *jitlamp= lar->jitter, vec[3];
- float area[4][3], intens= 0.0f;
- int a= lar->ray_totsamp;
-
- /* test if co is behind lamp */
- sub_v3_v3v3(vec, co, lar->co);
- if (dot_v3v3(vec, lar->vec) < 0.0f)
- return 0.0f;
-
- while (a--) {
- vec[0]= jitlamp[0];
- vec[1]= jitlamp[1];
- vec[2]= 0.0f;
- mul_m3_v3(lar->mat, vec);
-
- add_v3_v3v3(area[0], lar->area[0], vec);
- add_v3_v3v3(area[1], lar->area[1], vec);
- add_v3_v3v3(area[2], lar->area[2], vec);
- add_v3_v3v3(area[3], lar->area[3], vec);
-
- intens+= area_lamp_energy(area, co, vn);
-
- jitlamp+= 2;
- }
- intens /= (float)lar->ray_totsamp;
-
- return pow(intens * lar->areasize, lar->k); /* corrected for buttons size and lar->dist^2 */
-}
-
-static float spec(float inp, int hard)
-{
- float b1;
-
- if (inp>=1.0f) return 1.0f;
- else if (inp<=0.0f) return 0.0f;
-
- b1= inp*inp;
- /* avoid FPE */
- if (b1<0.01f) b1= 0.01f;
-
- if ((hard & 1)==0) inp= 1.0f;
- if (hard & 2) inp*= b1;
- b1*= b1;
- if (hard & 4) inp*= b1;
- b1*= b1;
- if (hard & 8) inp*= b1;
- b1*= b1;
- if (hard & 16) inp*= b1;
- b1*= b1;
-
- /* avoid FPE */
- if (b1<0.001f) b1= 0.0f;
-
- if (hard & 32) inp*= b1;
- b1*= b1;
- if (hard & 64) inp*=b1;
- b1*= b1;
- if (hard & 128) inp*=b1;
-
- if (b1<0.001f) b1= 0.0f;
-
- if (hard & 256) {
- b1*= b1;
- inp*=b1;
- }
-
- return inp;
-}
-
-static float Phong_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent )
-{
- float h[3];
- float rslt;
-
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
- if (tangent) rslt= sasqrt(1.0f - rslt*rslt);
-
- if ( rslt > 0.0f ) rslt= spec(rslt, hard);
- else rslt = 0.0f;
-
- return rslt;
-}
-
-
-/* reduced cook torrance spec (for off-specular peak) */
-static float CookTorr_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent)
-{
- float i, nh, nv, h[3];
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
- if (tangent) nh= sasqrt(1.0f - nh*nh);
- else if (nh<0.0f) return 0.0f;
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
- if (tangent) nv= sasqrt(1.0f - nv*nv);
- else if (nv<0.0f) nv= 0.0f;
-
- i= spec(nh, hard);
-
- i= i/(0.1f+nv);
- return i;
-}
-
-/* Blinn spec */
-static float Blinn_Spec(const float n[3], const float l[3], const float v[3], float refrac, float spec_power, int tangent)
-{
- float i, nh, nv, nl, vh, h[3];
- float a, b, c, g=0.0f, p, f, ang;
-
- if (refrac < 1.0f) return 0.0f;
- if (spec_power == 0.0f) return 0.0f;
-
- /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
- if (spec_power<100.0f)
- spec_power = sqrtf(1.0f / spec_power);
- else spec_power= 10.0f/spec_power;
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
- if (tangent) nh= sasqrt(1.0f - nh*nh);
- else if (nh<0.0f) return 0.0f;
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (tangent) nv= sasqrt(1.0f - nv*nv);
- if (nv<=0.01f) nv= 0.01f; /* hrms... */
-
- nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (tangent) nl= sasqrt(1.0f - nl*nl);
- if (nl<=0.01f) {
- return 0.0f;
- }
-
- vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */
- if (vh<=0.0f) vh= 0.01f;
-
- a = 1.0f;
- b = (2.0f*nh*nv)/vh;
- c = (2.0f*nh*nl)/vh;
-
- if ( a < b && a < c ) g = a;
- else if ( b < a && b < c ) g = b;
- else if ( c < a && c < b ) g = c;
-
- p = sqrt((double)((refrac * refrac)+(vh * vh) - 1.0f));
- f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f))));
- ang = saacos(nh);
-
- i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power)));
- if (i<0.0f) i= 0.0f;
-
- return i;
-}
-
-/* cartoon render spec */
-static float Toon_Spec(const float n[3], const float l[3], const float v[3], float size, float smooth, int tangent)
-{
- float h[3];
- float ang;
- float rslt;
-
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
- if (tangent) rslt = sasqrt(1.0f - rslt*rslt);
-
- ang = saacos( rslt );
-
- if ( ang < size ) rslt = 1.0f;
- else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
- else rslt = 1.0f - ((ang - size) / smooth);
-
- return rslt;
-}
-
-/* Ward isotropic gaussian spec */
-static float WardIso_Spec(const float n[3], const float l[3], const float v[3], float rms, int tangent)
-{
- float i, nh, nv, nl, h[3], angle, alpha;
-
-
- /* half-way vector */
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
- if (tangent) nh = sasqrt(1.0f - nh*nh);
- if (nh<=0.0f) nh = 0.001f;
-
- nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (tangent) nv = sasqrt(1.0f - nv*nv);
- if (nv<=0.0f) nv = 0.001f;
-
- nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (tangent) nl = sasqrt(1.0f - nl*nl);
- if (nl<=0.0f) nl = 0.001f;
-
- angle = tanf(saacos(nh));
- alpha = MAX2(rms, 0.001f);
-
- i= nl * (1.0f/(4.0f*(float)M_PI*alpha*alpha)) * (expf( -(angle*angle)/(alpha*alpha))/(sqrtf(nv*nl)));
-
- return i;
-}
-
-/* cartoon render diffuse */
-static float Toon_Diff(const float n[3], const float l[3], const float UNUSED(v[3]), float size, float smooth)
-{
- float rslt, ang;
-
- rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
-
- ang = saacos(rslt);
-
- if ( ang < size ) rslt = 1.0f;
- else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
- else rslt = 1.0f - ((ang - size) / smooth);
-
- return rslt;
-}
-
-/* Oren Nayar diffuse */
-
-/* 'nl' is either dot product, or return value of area light */
-/* in latter case, only last multiplication uses 'nl' */
-static float OrenNayar_Diff(float nl, const float n[3], const float l[3], const float v[3], float rough )
-{
- float i/*, nh*/, nv /*, vh */, realnl, h[3];
- float a, b, t, A, B;
- float Lit_A, View_A, Lit_B[3], View_B[3];
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- /* nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; */ /* Dot product between surface normal and half-way vector */
- /* if (nh<0.0f) nh = 0.0f; */
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (nv<=0.0f) nv= 0.0f;
-
- realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (realnl<=0.0f) return 0.0f;
- if (nl<0.0f) return 0.0f; /* value from area light */
-
- /* vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; */ /* Dot product between view vector and halfway vector */
- /* if (vh<=0.0f) vh= 0.0f; */
-
- Lit_A = saacos(realnl);
- View_A = saacos( nv );
-
- Lit_B[0] = l[0] - (realnl * n[0]);
- Lit_B[1] = l[1] - (realnl * n[1]);
- Lit_B[2] = l[2] - (realnl * n[2]);
- normalize_v3(Lit_B);
-
- View_B[0] = v[0] - (nv * n[0]);
- View_B[1] = v[1] - (nv * n[1]);
- View_B[2] = v[2] - (nv * n[2]);
- normalize_v3(View_B);
-
- t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
- if ( t < 0 ) t = 0;
-
- if ( Lit_A > View_A ) {
- a = Lit_A;
- b = View_A;
- }
- else {
- a = View_A;
- b = Lit_A;
- }
-
- A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f)));
- B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f));
-
- b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */
- /* overflow only happens with extreme size area light, and higher roughness */
- i = nl * ( A + ( B * t * sinf(a) * tanf(b) ) );
-
- return i;
-}
-
-/* Minnaert diffuse */
-static float Minnaert_Diff(float nl, const float n[3], const float v[3], float darkness)
-{
- float i, nv;
-
- /* nl = dot product between surface normal and light vector */
- if (nl <= 0.0f)
- return 0.0f;
-
- /* nv = dot product between surface normal and view vector */
- nv = dot_v3v3(n, v);
- if (nv < 0.0f)
- nv = 0.0f;
-
- if (darkness <= 1.0f)
- i = nl * pow(max_ff(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
- else
- i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/
-
- return i;
-}
-
-static float Fresnel_Diff(float *vn, float *lv, float *UNUSED(view), float fac_i, float fac)
-{
- return fresnel_fac(lv, vn, fac_i, fac);
-}
-
-/* --------------------------------------------- */
-/* also called from texture.c */
-void calc_R_ref(ShadeInput *shi)
-{
- float i;
-
- /* shi->vn dot shi->view */
- i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
-
- shi->ref[0]= (shi->view[0]+i*shi->vn[0]);
- shi->ref[1]= (shi->view[1]+i*shi->vn[1]);
- shi->ref[2]= (shi->view[2]+i*shi->vn[2]);
- if (shi->osatex) {
- if (shi->vlr->flag & R_SMOOTH) {
- i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) +
- (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] );
-
- shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0]));
- shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1]));
- shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2]));
-
- i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+
- (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] );
-
- shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0]));
- shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1]));
- shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2]));
-
- }
- else {
-
- i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) +
- shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] );
-
- shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]);
- shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]);
- shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
-
- i= -2*( shi->vn[0]*shi->view[0]+
- shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] );
-
- shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]);
- shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]);
- shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
- }
- }
-
-}
-
-/* called from rayshade.c */
-void shade_color(ShadeInput *shi, ShadeResult *shr)
-{
- Material *ma= shi->mat;
-
- if (ma->mode & (MA_VERTEXCOLP)) {
- float neg_alpha = 1.0f - shi->vcol[3];
- shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
- shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
- shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
- }
-
- if (ma->texco)
- do_material_tex(shi, &R);
-
- if (ma->fresnel_tra!=0.0f)
- shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
-
- if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f;
-
- shr->diff[0]= shi->r;
- shr->diff[1]= shi->g;
- shr->diff[2]= shi->b;
- shr->alpha= shi->alpha;
-
- /* modulate by the object color */
- if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
- float obcol[4];
-
- copy_v4_v4(obcol, shi->obr->ob->col);
- CLAMP(obcol[3], 0.0f, 1.0f);
-
- shr->diff[0] *= obcol[0];
- shr->diff[1] *= obcol[1];
- shr->diff[2] *= obcol[2];
- if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
- }
-
- copy_v3_v3(shr->diffshad, shr->diff);
-}
-
-/* ramp for at end of shade */
-static void ramp_diffuse_result(float *diff, ShadeInput *shi)
-{
- Material *ma= shi->mat;
- float col[4];
-
- if (ma->ramp_col) {
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- float fac = IMB_colormanagement_get_luminance(diff);
- BKE_colorband_evaluate(ma->ramp_col, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_col;
-
- ramp_blend(ma->rampblend_col, diff, fac, col);
- }
- }
-}
-
-/* r,g,b denote energy, ramp is used with different values to make new material color */
-static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3])
-{
- Material *ma= shi->mat;
-
- if (ma->ramp_col && (ma->mode & MA_RAMP_COL)) {
-
- /* MA_RAMP_IN_RESULT is exceptional */
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- /* normal add */
- diff[0] += rgb[0] * shi->r;
- diff[1] += rgb[1] * shi->g;
- diff[2] += rgb[2] * shi->b;
- }
- else {
- float colt[3], col[4];
- float fac;
-
- /* input */
- switch (ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- fac = IMB_colormanagement_get_luminance(rgb);
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- fac = dot_v3v3(shi->view, shi->vn);
- break;
- default:
- fac = 0.0f;
- break;
- }
-
- BKE_colorband_evaluate(ma->ramp_col, fac, col);
-
- /* blending method */
- fac = col[3] * ma->rampfac_col;
- copy_v3_v3(colt, &shi->r);
-
- ramp_blend(ma->rampblend_col, colt, fac, col);
-
- /* output to */
- diff[0] += rgb[0] * colt[0];
- diff[1] += rgb[1] * colt[1];
- diff[2] += rgb[2] * colt[2];
- }
- }
- else {
- diff[0] += rgb[0] * shi->r;
- diff[1] += rgb[1] * shi->g;
- diff[2] += rgb[2] * shi->b;
- }
-}
-
-static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
-{
- Material *ma= shi->mat;
-
- if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
- float col[4];
- float fac = IMB_colormanagement_get_luminance(spec_col);
-
- BKE_colorband_evaluate(ma->ramp_spec, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_spec;
-
- ramp_blend(ma->rampblend_spec, spec_col, fac, col);
-
- }
-}
-
-/* is = dot product shade, t = spec energy */
-static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3])
-{
- Material *ma= shi->mat;
-
- spec[0]= shi->specr;
- spec[1]= shi->specg;
- spec[2]= shi->specb;
-
- /* MA_RAMP_IN_RESULT is exception */
- if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
- float fac;
- float col[4];
-
- /* input */
- switch (ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac= t;
- break;
- case MA_RAMP_IN_SHADER:
- fac= is;
- break;
- case MA_RAMP_IN_NOR:
- fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
- break;
- default:
- fac= 0.0f;
- break;
- }
-
- BKE_colorband_evaluate(ma->ramp_spec, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_spec;
-
- ramp_blend(ma->rampblend_spec, spec, fac, col);
- }
-}
-
-/* pure AO, check for raytrace and world should have been done */
-/* preprocess, textures were not done, don't use shi->amb for that reason */
-void ambient_occlusion(ShadeInput *shi)
-{
- if ((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) {
- sample_occ(&R, shi);
- }
- else if ((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
- ray_ao(shi, shi->ao, shi->env);
- }
- else {
- shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
- zero_v3(shi->env);
- zero_v3(shi->indirect);
- }
-}
-
-
-/* wrld mode was checked for */
-static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.aoenergy;
- float tmp[3], tmpspec[3];
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- if (R.wrld.aomix==WO_AOADD) {
- shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f;
- }
- else if (R.wrld.aomix==WO_AOMUL) {
- mul_v3_v3v3(tmp, shr->combined, shi->ao);
- mul_v3_v3v3(tmpspec, shr->spec, shi->ao);
-
- if (f == 1.0f) {
- copy_v3_v3(shr->combined, tmp);
- copy_v3_v3(shr->spec, tmpspec);
- }
- else {
- interp_v3_v3v3(shr->combined, shr->combined, tmp, f);
- interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f);
- }
- }
-}
-
-void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.ao_env_energy*shi->amb;
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- shr->combined[0] += shi->env[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->env[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->env[2]*shi->b*shi->refl*f;
-}
-
-static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.ao_indirect_energy;
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f;
-}
-
-/* result written in shadfac */
-void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real)
-{
- LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
-
- if (do_real || lss->samplenr!=shi->samplenr) {
-
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
-
- if (lar->shb) {
- if (lar->buftype==LA_SHADBUF_IRREGULAR)
- shadfac[3]= ISB_getshadow(shi, lar->shb);
- else
- shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias);
- }
- else if (lar->mode & LA_SHAD_RAY) {
- ray_shadow(shi, lar, shadfac);
- }
-
- if (shi->depth==0) {
- copy_v4_v4(lss->shadfac, shadfac);
- lss->samplenr= shi->samplenr;
- }
- }
- else {
- copy_v4_v4(shadfac, lss->shadfac);
- }
-}
-
-/* lampdistance and spot angle, writes in lv and dist */
-float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *dist)
-{
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- *dist= 1.0f;
- copy_v3_v3(lv, lar->vec);
- return 1.0f;
- }
- else {
- float visifac= 1.0f, visifac_r;
-
- sub_v3_v3v3(lv, co, lar->co);
- mul_v3_fl(lv, 1.0f / (*dist = len_v3(lv)));
-
- /* area type has no quad or sphere option */
- if (lar->type==LA_AREA) {
- /* area is single sided */
- //if (dot_v3v3(lv, lar->vec) > 0.0f)
- // visifac= 1.0f;
- //else
- // visifac= 0.0f;
- }
- else {
- switch (lar->falloff_type) {
- case LA_FALLOFF_CONSTANT:
- visifac = 1.0f;
- break;
- case LA_FALLOFF_INVLINEAR:
- visifac = lar->dist/(lar->dist + dist[0]);
- break;
- case LA_FALLOFF_INVSQUARE:
- /* NOTE: This seems to be a hack since commit r12045 says this
- * option is similar to old Quad, but with slight changes.
- * Correct inv square would be (which would be old Quad):
- * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]);
- */
- visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
- break;
- case LA_FALLOFF_SLIDERS:
- if (lar->ld1>0.0f)
- visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
- if (lar->ld2>0.0f)
- visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
- break;
- case LA_FALLOFF_INVCOEFFICIENTS:
- visifac_r = lar->coeff_const +
- lar->coeff_lin * dist[0] +
- lar->coeff_quad * dist[0] * dist[0];
- if (visifac_r > 0.0)
- visifac = 1.0 / visifac_r;
- else
- visifac = 0.0;
- break;
- case LA_FALLOFF_CURVE:
- /* curvemapping_initialize is called from #add_render_lamp */
- visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
- break;
- }
-
- if (lar->mode & LA_SPHERE) {
- float t= lar->dist - dist[0];
- if (t<=0.0f)
- visifac= 0.0f;
- else
- visifac*= t/lar->dist;
- }
-
- if (visifac > 0.0f) {
- if (lar->type==LA_SPOT) {
- float inpr, t;
-
- if (lar->mode & LA_SQUARE) {
- if (dot_v3v3(lv, lar->vec) > 0.0f) {
- float lvrot[3], x;
-
- /* rotate view to lampspace */
- copy_v3_v3(lvrot, lv);
- mul_m3_v3(lar->imat, lvrot);
-
- x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
- /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
-
- inpr = 1.0f / (sqrtf(1.0f + x * x));
- }
- else inpr= 0.0f;
- }
- else {
- inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
- }
-
- t= lar->spotsi;
- if (inpr<=t)
- visifac= 0.0f;
- else {
- t= inpr-t;
- if (t<lar->spotbl && lar->spotbl!=0.0f) {
- /* soft area */
- float i= t/lar->spotbl;
- t= i*i;
- inpr*= (3.0f*t-2.0f*t*i);
- }
- visifac*= inpr;
- }
- }
- }
- }
- if (visifac <= 0.001f) visifac = 0.0f;
- return visifac;
- }
-}
-
-/* function returns raw diff, spec and full shadowed diff in the 'shad' pass */
-static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag)
-{
- Material *ma= shi->mat;
- VlakRen *vlr= shi->vlr;
- float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3];
- float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
- float visifac;
-
- vn= shi->vn;
- view= shi->view;
-
-
- if (lar->energy == 0.0f) return;
- /* only shadow lamps shouldn't affect shadow-less materials at all */
- if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW)))
- return;
- /* optimization, don't render fully black lamps */
- if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
- return;
-
- /* lampdist, spot angle, area side, ... */
- visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
- if (visifac==0.0f)
- return;
-
- if (lar->type==LA_SPOT) {
- if (lar->mode & LA_OSATEX) {
- shi->osatex= 1; /* signal for multitex() */
-
- shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist;
- shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist;
- shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist;
-
- shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist;
- shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist;
- shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist;
- }
- }
-
- /* lamp color texture */
- lacol[0]= lar->r;
- lacol[1]= lar->g;
- lacol[2]= lar->b;
-
- lashdw[0]= lar->shdwr;
- lashdw[1]= lar->shdwg;
- lashdw[2]= lar->shdwb;
-
- if (lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
- if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX);
-
- /* tangent case; calculate fake face normal, aligned with lampvector */
- /* note, vnor==vn is used as tangent trigger for buffer shadow */
- if (vlr->flag & R_TANGENT) {
- float cross[3], nstrand[3], blend;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, shi->surfnor, vn);
- cross_v3_v3v3(nstrand, vn, cross);
-
- blend= dot_v3v3(nstrand, shi->surfnor);
- blend= 1.0f - blend;
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- cross_v3_v3v3(cross, lv, vn);
- cross_v3_v3v3(vnor, cross, vn);
- normalize_v3(vnor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > shi->surfdist) {
- blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, shi->surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
- vn= vnor;
- }
- else if (ma->mode & MA_TANGENT_V) {
- float cross[3];
- cross_v3_v3v3(cross, lv, shi->tang);
- cross_v3_v3v3(vnor, cross, shi->tang);
- normalize_v3(vnor);
- vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
- vn= vnor;
- }
-
- /* dot product and reflectivity */
- /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
- inp= dot_v3v3(vn, lv);
-
- /* phong threshold to prevent backfacing faces having artifacts on ray shadow (terminator problem) */
- /* this complex construction screams for a nicer implementation! (ton) */
- if (R.r.mode & R_SHADOW) {
- if (ma->mode & MA_SHADOW) {
- if (lar->type == LA_HEMI || lar->type == LA_AREA) {
- /* pass */
- }
- else if ((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
- float thresh= shi->obr->ob->smoothresh;
- if (inp>thresh)
- phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
- else
- phongcorr= 0.0f;
- }
- else if (ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) {
- if (inp>ma->sbias)
- phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias));
- else
- phongcorr= 0.0f;
- }
- }
- }
-
- /* diffuse shaders */
- if (lar->mode & LA_NO_DIFF) {
- is = 0.0f; /* skip shaders */
- }
- else if (lar->type==LA_HEMI) {
- is = 0.5f * inp + 0.5f;
- }
- else {
-
- if (lar->type==LA_AREA)
- inp= area_lamp_energy_multisample(lar, shi->co, vn);
-
- /* diffuse shaders (oren nayer gets inp from area light) */
- if (ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
- else if (ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
- else if (ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
- else if (ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
- else is= inp; /* Lambert */
- }
-
- /* 'is' is diffuse */
- if ((ma->shade_flag & MA_CUBIC) && is > 0.0f && is < 1.0f) {
- is= 3.0f * is * is - 2.0f * is * is * is; /* nicer termination of shades */
- }
-
- i= is*phongcorr;
-
- if (i>0.0f) {
- i*= visifac*shi->refl;
- }
- i_noshad= i;
-
- vn = shi->vn; /* bring back original vector, we use special specular shaders for tangent */
- if (ma->mode & MA_TANGENT_V)
- vn= shi->tang;
-
- /* init transp shadow */
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
-
- /* shadow and spec, (visifac==0 outside spot) */
- if (visifac> 0.0f) {
-
- if ((R.r.mode & R_SHADOW)) {
- if (ma->mode & MA_SHADOW) {
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
-
- if (vn==vnor) /* tangent trigger */
- lamp_get_shadow(lar, shi, dot_v3v3(shi->vn, lv), shadfac, shi->depth);
- else
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
-
- /* warning, here it skips the loop */
- if ((lar->mode & LA_ONLYSHADOW) && i>0.0f) {
-
- shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
- shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]);
- shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
- shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
-
- if (!(lar->mode & LA_NO_SPEC)) {
- shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
- shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
- shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
- }
-
- return;
- }
-
- i*= shadfac[3];
- shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
- }
- else {
- shr->shad[3] = 1.0f; /* No shadow at all! */
- }
- }
- }
-
- /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
- if (!(lar->mode & LA_NO_DIFF)) {
- if (i>0.0f) {
- if (ma->mode & MA_SHADOW_TRA) {
- const float tcol[3] = {
- i * shadfac[0] * lacol[0],
- i * shadfac[1] * lacol[1],
- i * shadfac[2] * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- else {
- const float tcol[3] = {
- i * lacol[0],
- i * lacol[1],
- i * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- }
- /* add light for colored shadow */
- if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
- const float tcol[3] = {
- lashdw[0] * (i_noshad - i) * lacol[0],
- lashdw[1] * (i_noshad - i) * lacol[1],
- lashdw[2] * (i_noshad - i) * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- if (i_noshad>0.0f) {
- if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) ||
- ((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW)))
- {
- const float tcol[3] = {
- i_noshad * lacol[0],
- i_noshad * lacol[1],
- i_noshad * lacol[2]
- };
- add_to_diffuse(shr->diff, shi, is, tcol);
- }
- else {
- copy_v3_v3(shr->diff, shr->shad);
- }
- }
- }
-
- /* specularity */
- shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
-
- if (shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
-
- if (!(passflag & (SCE_PASS_COMBINED | SCE_PASS_SPEC))) {
- /* pass */
- }
- else if (lar->type == LA_HEMI) {
- float t;
- /* hemi uses no spec shaders (yet) */
-
- lv[0]+= view[0];
- lv[1]+= view[1];
- lv[2]+= view[2];
-
- normalize_v3(lv);
-
- t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
-
- if (lar->type==LA_HEMI) {
- t= 0.5f*t+0.5f;
- }
-
- t= shadfac[3]*shi->spec*spec(t, shi->har);
-
- shr->spec[0]+= t*(lacol[0] * shi->specr);
- shr->spec[1]+= t*(lacol[1] * shi->specg);
- shr->spec[2]+= t*(lacol[2] * shi->specb);
- }
- else {
- /* specular shaders */
- float specfac, t;
-
- if (ma->spec_shader==MA_SPEC_PHONG)
- specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_COOKTORR)
- specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_BLINN)
- specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_WARDISO)
- specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else
- specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
-
- /* area lamp correction */
- if (lar->type==LA_AREA) specfac*= inp;
-
- t= shadfac[3]*shi->spec*visifac*specfac;
-
- if (ma->mode & MA_RAMP_SPEC) {
- float spec[3];
- do_specular_ramp(shi, specfac, t, spec);
- shr->spec[0]+= t*(lacol[0] * spec[0]);
- shr->spec[1]+= t*(lacol[1] * spec[1]);
- shr->spec[2]+= t*(lacol[2] * spec[2]);
- }
- else {
- shr->spec[0]+= t*(lacol[0] * shi->specr);
- shr->spec[1]+= t*(lacol[1] * shi->specg);
- shr->spec[2]+= t*(lacol[2] * shi->specb);
- }
- }
- }
- }
-}
-
-static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
-{
-
- if (R.r.mode & R_SHADOW) {
- ListBase *lights;
- LampRen *lar;
- GroupObject *go;
- float inpr, lv[3];
- float /* *view, */ shadfac[4];
- float ir, accum, visifac, lampdist;
- float shaded = 0.0f, lightness = 0.0f;
-
-
- /* view= shi->view; */ /* UNUSED */
- accum= ir= 0.0f;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
- if ((lar->lay & shi->lay)==0) continue;
-
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
- visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
- ir+= 1.0f;
-
- if (visifac <= 0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD)
- accum+= 1.0f;
-
- continue;
- }
- inpr= dot_v3v3(shi->vn, lv);
- if (inpr <= 0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD)
- accum+= 1.0f;
-
- continue;
- }
-
- lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
-
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- /* Old "Shadows Only" */
- accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3];
- }
- else {
- shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy;
-
- if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
- lightness += visifac * lar->energy;
- }
- }
- }
- }
-
- /* Apply shadows as alpha */
- if (ir>0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- accum = 1.0f - accum/ir;
- }
- else {
- if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
- if (lightness > 0.0f) {
- /* Get shadow value from between 0.0f and non-shadowed lightness */
- accum = (lightness - shaded) / (lightness);
- }
- else {
- accum = 0.0f;
- }
- }
- else { /* shadowonly_flag == MA_SO_SHADED */
- /* Use shaded value */
- accum = 1.0f - shaded;
- }
- }
-
- shr->alpha= (shi->alpha)*(accum);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- else {
- /* If "fully shaded", use full alpha even on areas that have no lights */
- if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha;
- else shr->alpha= 0.f;
- }
- }
-
- /* quite disputable this... also note it doesn't mirror-raytrace */
- if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
- float f;
-
- if (R.wrld.mode & WO_AMB_OCC) {
- f= R.wrld.aoenergy*shi->amb;
-
- if (R.wrld.aomix==WO_AOADD) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao));
- shr->alpha= (shr->alpha + f)*f;
- }
- else {
- shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- }
- else /* AO Multiply */
- shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao));
- }
-
- if (R.wrld.mode & WO_ENV_LIGHT) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env));
- shr->alpha= (shr->alpha + f)*f;
- }
- else {
- f= R.wrld.ao_env_energy*shi->amb;
- shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- }
- }
-}
-
-/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
-static void wrld_exposure_correct(float diff[3])
-{
-
- diff[0]= R.wrld.linfac*(1.0f-expf( diff[0]*R.wrld.logfac) );
- diff[1]= R.wrld.linfac*(1.0f-expf( diff[1]*R.wrld.logfac) );
- diff[2]= R.wrld.linfac*(1.0f-expf( diff[2]*R.wrld.logfac) );
-}
-
-void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
-{
- /* Passes which might need to know material color.
- *
- * It seems to be faster to just calculate material color
- * even if the pass doesn't really need it than trying to
- * figure out whether color is really needed or not.
- */
- const int color_passes =
- SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC |
- SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW;
-
- Material *ma= shi->mat;
- int passflag= shi->passflag;
-
- memset(shr, 0, sizeof(ShadeResult));
-
- if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
-
- /* separate loop */
- if (ma->mode & MA_ONLYSHADOW) {
- shade_lamp_loop_only_shadow(shi, shr);
- return;
- }
-
- /* envmap hack, always reset */
- shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
-
- /* material color itself */
- if (passflag & color_passes) {
- if (false) {
- /* pass */
- }
-#ifdef WITH_FREESTYLE
- else if (ma->vcol_alpha) {
- shi->r= shi->vcol[0];
- shi->g= shi->vcol[1];
- shi->b= shi->vcol[2];
- shi->alpha= shi->vcol[3];
- }
-#endif
- else if (ma->mode & (MA_VERTEXCOLP)) {
- float neg_alpha = 1.0f - shi->vcol[3];
- shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
- shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
- shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
- }
- if (ma->texco) {
- do_material_tex(shi, &R);
- if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
- }
-
- shr->col[0]= shi->r*shi->alpha;
- shr->col[1]= shi->g*shi->alpha;
- shr->col[2]= shi->b*shi->alpha;
- shr->col[3]= shi->alpha;
-
- if ((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) {
- if (ma->sss_texfac == 0.0f) {
- shi->r= shi->g= shi->b= shi->alpha= 1.0f;
- shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f;
- }
- else {
- shi->r= pow(max_ff(shi->r, 0.0f), ma->sss_texfac);
- shi->g= pow(max_ff(shi->g, 0.0f), ma->sss_texfac);
- shi->b= pow(max_ff(shi->b, 0.0f), ma->sss_texfac);
- shi->alpha= pow(max_ff(shi->alpha, 0.0f), ma->sss_texfac);
-
- shr->col[0]= pow(max_ff(shr->col[0], 0.0f), ma->sss_texfac);
- shr->col[1]= pow(max_ff(shr->col[1], 0.0f), ma->sss_texfac);
- shr->col[2]= pow(max_ff(shr->col[2], 0.0f), ma->sss_texfac);
- shr->col[3]= pow(max_ff(shr->col[3], 0.0f), ma->sss_texfac);
- }
- }
- }
-
- if (ma->mode & MA_SHLESS) {
- shr->combined[0]= shi->r;
- shr->combined[1]= shi->g;
- shr->combined[2]= shi->b;
- shr->alpha= shi->alpha;
- goto finally_shadeless;
- }
-
- if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */
- shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]*shi->vcol[3]);
- shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]*shi->vcol[3]);
- shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]*shi->vcol[3]);
- }
- else {
- shr->emit[0]= shi->r*shi->emit;
- shr->emit[1]= shi->g*shi->emit;
- shr->emit[2]= shi->b*shi->emit;
- }
-
- /* AO pass */
- if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) ||
- (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) {
- if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (R.r.mode & R_SHADOW)) {
- /* AO was calculated for scanline already */
- if (shi->depth || shi->volume_depth)
- ambient_occlusion(shi);
- copy_v3_v3(shr->ao, shi->ao);
- copy_v3_v3(shr->env, shi->env); /* XXX multiply */
- copy_v3_v3(shr->indirect, shi->indirect); /* XXX multiply */
- }
- else {
- shr->ao[0]= shr->ao[1]= shr->ao[2]= 1.0f;
- zero_v3(shr->env);
- zero_v3(shr->indirect);
- }
- }
-
- /* lighting pass */
- if (passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
- GroupObject *go;
- ListBase *lights;
- LampRen *lar;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- /* test for lamp layer */
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
- if ((lar->lay & shi->lay)==0) continue;
-
- /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
- shade_one_light(lar, shi, shr, passflag);
- }
-
- /* this check is to prevent only shadow lamps from producing negative
- * colors.*/
- if (shr->spec[0] < 0) shr->spec[0] = 0;
- if (shr->spec[1] < 0) shr->spec[1] = 0;
- if (shr->spec[2] < 0) shr->spec[2] = 0;
-
- if (shr->shad[0] < 0) shr->shad[0] = 0;
- if (shr->shad[1] < 0) shr->shad[1] = 0;
- if (shr->shad[2] < 0) shr->shad[2] = 0;
-
- if (ma->sss_flag & MA_DIFF_SSS) {
- float sss[3], col[3], invalpha, texfac= ma->sss_texfac;
-
- /* this will return false in the preprocess stage */
- if (sample_sss(&R, ma, shi->co, sss)) {
- invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f;
-
- if (texfac==0.0f) {
- copy_v3_v3(col, shr->col);
- mul_v3_fl(col, invalpha);
- }
- else if (texfac==1.0f) {
- col[0]= col[1]= col[2]= 1.0f;
- mul_v3_fl(col, invalpha);
- }
- else {
- copy_v3_v3(col, shr->col);
- mul_v3_fl(col, invalpha);
- col[0]= pow(max_ff(col[0], 0.0f), 1.0f-texfac);
- col[1]= pow(max_ff(col[1], 0.0f), 1.0f-texfac);
- col[2]= pow(max_ff(col[2], 0.0f), 1.0f-texfac);
- }
-
- shr->diff[0]= sss[0]*col[0];
- shr->diff[1]= sss[1]*col[1];
- shr->diff[2]= sss[2]*col[2];
-
- if (shi->combinedflag & SCE_PASS_SHADOW) {
- shr->shad[0]= shr->diff[0];
- shr->shad[1]= shr->diff[1];
- shr->shad[2]= shr->diff[2];
- }
- }
- }
-
- if (shi->combinedflag & SCE_PASS_SHADOW)
- copy_v3_v3(shr->diffshad, shr->shad);
- else
- copy_v3_v3(shr->diffshad, shr->diff);
-
- copy_v3_v3(shr->combined, shr->diffshad);
-
- /* calculate shadow pass, we use a multiplication mask */
- /* Even if diff = 0,0,0, it does matter what the shadow pass is, since we may want it 'for itself'! */
- if (passflag & SCE_PASS_SHADOW) {
- if (shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
- /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
- else if (shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
-
- if (shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
- else if (shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3];
-
- if (shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
- else if (shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3];
- }
-
- /* exposure correction */
- if ((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) {
- wrld_exposure_correct(shr->combined); /* has no spec! */
- wrld_exposure_correct(shr->spec);
- }
- }
-
- /* alpha in end, spec can influence it */
- if (passflag & (SCE_PASS_COMBINED)) {
- if ((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP))
- shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
-
- /* note: shi->mode! */
- if (shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
- if (shi->spectra!=0.0f) {
- float t = max_fff(shr->spec[0], shr->spec[1], shr->spec[2]);
- t *= shi->spectra;
- if (t>1.0f) t= 1.0f;
- shi->alpha= (1.0f-t)*shi->alpha+t;
- }
- }
- }
- shr->alpha= shi->alpha;
-
- /* from now stuff everything in shr->combined: ambient, AO, ramps, exposure */
- if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
- if (R.r.mode & R_SHADOW) {
- /* add AO in combined? */
- if (R.wrld.mode & WO_AMB_OCC)
- if (shi->combinedflag & SCE_PASS_AO)
- ambient_occlusion_apply(shi, shr);
-
- if (R.wrld.mode & WO_ENV_LIGHT)
- if (shi->combinedflag & SCE_PASS_ENVIRONMENT)
- environment_lighting_apply(shi, shr);
-
- if (R.wrld.mode & WO_INDIRECT_LIGHT)
- if (shi->combinedflag & SCE_PASS_INDIRECT)
- indirect_lighting_apply(shi, shr);
- }
-
- shr->combined[0]+= shi->ambr;
- shr->combined[1]+= shi->ambg;
- shr->combined[2]+= shi->ambb;
-
- if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
- }
-
- if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shi);
-
- /* refcol is for envmap only */
- if (shi->refcol[0]!=0.0f) {
- float result[3];
-
- result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0];
- result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1];
- result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2];
-
- if (passflag & SCE_PASS_REFLECT)
- sub_v3_v3v3(shr->refl, result, shr->combined);
-
- if (shi->combinedflag & SCE_PASS_REFLECT)
- copy_v3_v3(shr->combined, result);
-
- }
-
- /* and add emit and spec */
- if (shi->combinedflag & SCE_PASS_EMIT)
- add_v3_v3(shr->combined, shr->emit);
- if (shi->combinedflag & SCE_PASS_SPEC)
- add_v3_v3(shr->combined, shr->spec);
-
-
- /* Last section of this function applies to shadeless colors too */
-finally_shadeless:
-
- /* modulate by the object color */
- if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
- if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
- float obcol[4];
-
- copy_v4_v4(obcol, shi->obr->ob->col);
- CLAMP(obcol[3], 0.0f, 1.0f);
-
- shr->combined[0] *= obcol[0];
- shr->combined[1] *= obcol[1];
- shr->combined[2] *= obcol[2];
- if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
- }
- }
-
- shr->combined[3]= shr->alpha;
-}
-
-/* used for "Lamp Data" shader node */
-static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4])
-{
- LampRen *lar = go->lampren;
- float visifac, inp;
-
- if (!lar
- || ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
- || (lar->lay & shi->lay) == 0)
- return 0.0f;
-
- if (lar->mode & LA_TEXTURE)
- do_lamp_tex(lar, lv, shi, col, LA_TEXTURE);
-
- visifac = lamp_get_visibility(lar, shi->co, lv, dist);
-
- if (visifac == 0.0f
- || lar->type == LA_HEMI
- || (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY))
- || (R.r.scemode & R_BUTS_PREVIEW))
- return visifac;
-
- inp = dot_v3v3(shi->vn, lv);
-
- if (inp > 0.0f) {
- float shadfac[4];
-
- shadow[0] = lar->shdwr;
- shadow[1] = lar->shdwg;
- shadow[2] = lar->shdwb;
-
- if (lar->mode & LA_SHAD_TEX)
- do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
-
- if (R.r.mode & R_SHADOW) {
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
-
- shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
- shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
- shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
- }
- }
-
- return visifac;
-}
-
-float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4])
-{
- col[0] = col[1] = col[2] = 0.0f;
- col[3] = 1.0f;
- copy_v3_v3(lv, shi->vn);
- *dist = 1.0f;
- shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f;
-
- if (lamp_obj->type == OB_LAMP) {
- GroupObject *go;
- Lamp *lamp = (Lamp *)lamp_obj->data;
-
- col[0] = lamp->r * lamp->energy;
- col[1] = lamp->g * lamp->energy;
- col[2] = lamp->b * lamp->energy;
-
- if (R.r.scemode & R_BUTS_PREVIEW) {
- for (go = R.lights.first; go; go = go->next) {
- /* "Lamp.002" is main key light of material preview */
- if (STREQ(go->ob->id.name + 2, "Lamp.002"))
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- return 0.0f;
- }
-
- if (shi->mat && shi->mat->group) {
- for (go = shi->mat->group->gobject.first; go; go = go->next) {
- if (go->ob == lamp_obj)
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- }
-
- for (go = R.lights.first; go; go = go->next) {
- if (go->ob == lamp_obj)
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- }
-
- return 0.0f;
-}
-
-const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]
-{
- if (obi) {
- switch (matrix_id) {
- case RE_OBJECT_INSTANCE_MATRIX_OB:
- return (const float(*)[4])obi->obmat;
- case RE_OBJECT_INSTANCE_MATRIX_OBINV:
- return (const float(*)[4])obi->obinvmat;
- case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW:
- return (const float(*)[4])obi->localtoviewmat;
- case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV:
- return (const float(*)[4])obi->localtoviewinvmat;
- }
- }
- return NULL;
-}
-
-float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
-{
- return obi->ob->index;
-}
-
-float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
-{
- return obi->random_id;
-}
-
-const float (*RE_render_current_get_matrix(int matrix_id))[4]
-{
- switch (matrix_id) {
- case RE_VIEW_MATRIX:
- return (const float(*)[4])R.viewmat;
- case RE_VIEWINV_MATRIX:
- return (const float(*)[4])R.viewinv;
- }
- return NULL;
-}
-
-float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- float c = fabs(dot_v3v3(incoming, normal));
- float g = eta * eta - 1.0 + c * c;
- float result;
-
- if (g > 0.0) {
- g = sqrtf(g);
- float A = (g - c) / (g + c);
- float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
- result = 0.5 * A * A * (1.0 + B * B);
- }
- else {
- result = 1.0; /* TIR (no refracted component) */
- }
-
- return result;
-}
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
deleted file mode 100644
index c29da9b17c6..00000000000
--- a/source/blender/render/intern/source/sss.c
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/sss.c
- * \ingroup render
- */
-
-/* Possible Improvements:
- * - add fresnel terms
- * - adapt Rd table to scale, now with small scale there are a lot of misses?
- * - possible interesting method: perform sss on all samples in the tree,
- * and then use those values interpolated somehow later. can also do this
- * filtering on demand for speed. since we are doing things in screen
- * space now there is an exact correspondence
- * - avoid duplicate shading (filtering points in advance, irradiance cache
- * like lookup?)
- * - lower resolution samples
- */
-
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <string.h>
-
-/* external modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_memarena.h"
-
-#include "BLT_translation.h"
-
-
-#include "DNA_material_types.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_scene.h"
-
-
-/* this module */
-#include "render_types.h"
-#include "sss.h"
-
-/* Generic Multiple Scattering API */
-
-/* Relevant papers:
- * [1] A Practical Model for Subsurface Light Transport
- * [2] A Rapid Hierarchical Rendering Technique for Translucent Materials
- * [3] Efficient Rendering of Local Subsurface Scattering
- * [4] Implementing a skin BSSRDF (or several...)
- */
-
-/* Defines */
-
-#define RD_TABLE_RANGE 100.0f
-#define RD_TABLE_RANGE_2 10000.0f
-#define RD_TABLE_SIZE 10000
-
-#define MAX_OCTREE_NODE_POINTS 8
-#define MAX_OCTREE_DEPTH 15
-
-/* Struct Definitions */
-
-struct ScatterSettings {
- float eta; /* index of refraction */
- float sigma_a; /* absorption coefficient */
- float sigma_s_; /* reduced scattering coefficient */
- float sigma_t_; /* reduced extinction coefficient */
- float sigma; /* effective extinction coefficient */
- float Fdr; /* diffuse fresnel reflectance */
- float D; /* diffusion constant */
- float A;
- float alpha_; /* reduced albedo */
- float zr; /* distance of virtual lightsource above surface */
- float zv; /* distance of virtual lightsource below surface */
- float ld; /* mean free path */
- float ro; /* diffuse reflectance */
- float color;
- float invsigma_t_;
- float frontweight;
- float backweight;
-
- float *tableRd; /* lookup table to avoid computing Rd */
- float *tableRd2; /* lookup table to avoid computing Rd for bigger values */
-};
-
-typedef struct ScatterPoint {
- float co[3];
- float rad[3];
- float area;
- int back;
-} ScatterPoint;
-
-typedef struct ScatterNode {
- float co[3];
- float rad[3];
- float backrad[3];
- float area, backarea;
-
- int totpoint;
- ScatterPoint *points;
-
- float split[3];
- struct ScatterNode *child[8];
-} ScatterNode;
-
-struct ScatterTree {
- MemArena *arena;
-
- ScatterSettings *ss[3];
- float error, scale;
-
- ScatterNode *root;
- ScatterPoint *points;
- ScatterPoint **refpoints;
- ScatterPoint **tmppoints;
- int totpoint;
- float min[3], max[3];
-};
-
-typedef struct ScatterResult {
- float rad[3];
- float backrad[3];
- float rdsum[3];
- float backrdsum[3];
-} ScatterResult;
-
-/* Functions for BSSRDF reparametrization in to more intuitive parameters,
- * see [2] section 4 for more info. */
-
-static float f_Rd(float alpha_, float A, float ro)
-{
- float sq;
-
- sq = sqrtf(3.0f * (1.0f - alpha_));
- return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
-}
-
-static float compute_reduced_albedo(ScatterSettings *ss)
-{
- const float tolerance= 1e-8;
- const int max_iteration_count= 20;
- float d, fsub, xn_1= 0.0f, xn= 1.0f, fxn, fxn_1;
- int i;
-
- /* use secant method to compute reduced albedo using Rd function inverse
- * with a given reflectance */
- fxn= f_Rd(xn, ss->A, ss->ro);
- fxn_1= f_Rd(xn_1, ss->A, ss->ro);
-
- for (i= 0; i < max_iteration_count; i++) {
- fsub= (fxn - fxn_1);
- if (fabsf(fsub) < tolerance)
- break;
- d= ((xn - xn_1)/fsub)*fxn;
- if (fabsf(d) < tolerance)
- break;
-
- xn_1= xn;
- fxn_1= fxn;
- xn= xn - d;
-
- if (xn > 1.0f) xn= 1.0f;
- if (xn_1 > 1.0f) xn_1= 1.0f;
-
- fxn= f_Rd(xn, ss->A, ss->ro);
- }
-
- /* avoid division by zero later */
- if (xn <= 0.0f)
- xn= 0.00001f;
-
- return xn;
-}
-
-/* Exponential falloff functions */
-
-static float Rd_rsquare(ScatterSettings *ss, float rr)
-{
- float sr, sv, Rdr, Rdv;
-
- sr = sqrtf(rr + ss->zr * ss->zr);
- sv = sqrtf(rr + ss->zv * ss->zv);
-
- Rdr= ss->zr*(1.0f + ss->sigma*sr)*expf(-ss->sigma*sr)/(sr*sr*sr);
- Rdv= ss->zv*(1.0f + ss->sigma*sv)*expf(-ss->sigma*sv)/(sv*sv*sv);
-
- return /*ss->alpha_*/(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv);
-}
-
-static float Rd(ScatterSettings *ss, float r)
-{
- return Rd_rsquare(ss, r*r);
-}
-
-/* table lookups for Rd. this avoids expensive exp calls. we use two
- * separate tables as well for lower and higher numbers to improve
- * precision, since the number are poorly distributed because we do
- * a lookup with the squared distance for smaller distances, saving
- * another sqrt. */
-
-static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd)
-{
- float indexf, t, idxf;
- int index;
-
- if (rr > (RD_TABLE_RANGE_2 * RD_TABLE_RANGE_2)) {
- /* pass */
- }
- else if (rr > RD_TABLE_RANGE) {
- rr = sqrtf(rr);
- indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2);
- index= (int)indexf;
- idxf= (float)index;
- t= indexf - idxf;
-
- if (index >= 0 && index < RD_TABLE_SIZE) {
- rd[0]= (ss[0]->tableRd2[index]*(1-t) + ss[0]->tableRd2[index+1]*t);
- rd[1]= (ss[1]->tableRd2[index]*(1-t) + ss[1]->tableRd2[index+1]*t);
- rd[2]= (ss[2]->tableRd2[index]*(1-t) + ss[2]->tableRd2[index+1]*t);
- return;
- }
- }
- else {
- indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE);
- index= (int)indexf;
- idxf= (float)index;
- t= indexf - idxf;
-
- if (index >= 0 && index < RD_TABLE_SIZE) {
- rd[0]= (ss[0]->tableRd[index]*(1-t) + ss[0]->tableRd[index+1]*t);
- rd[1]= (ss[1]->tableRd[index]*(1-t) + ss[1]->tableRd[index+1]*t);
- rd[2]= (ss[2]->tableRd[index]*(1-t) + ss[2]->tableRd[index+1]*t);
- return;
- }
- }
-
- /* fallback to slow Rd computation */
- rd[0]= Rd_rsquare(ss[0], rr);
- rd[1]= Rd_rsquare(ss[1], rr);
- rd[2]= Rd_rsquare(ss[2], rr);
-}
-
-static void build_Rd_table(ScatterSettings *ss)
-{
- float r;
- int i, size = RD_TABLE_SIZE+1;
-
- ss->tableRd= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
- ss->tableRd2= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
-
- for (i= 0; i < size; i++) {
- r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
-#if 0
- if (r < ss->invsigma_t_*ss->invsigma_t_) {
- r= ss->invsigma_t_*ss->invsigma_t_;
- }
-#endif
- ss->tableRd[i]= Rd(ss, sqrtf(r));
-
- r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
-#if 0
- if (r < ss->invsigma_t_) {
- r= ss->invsigma_t_;
- }
-#endif
- ss->tableRd2[i]= Rd(ss, r);
- }
-}
-
-ScatterSettings *scatter_settings_new(float refl, float radius, float ior, float reflfac, float frontweight, float backweight)
-{
- ScatterSettings *ss;
-
- ss= MEM_callocN(sizeof(ScatterSettings), "ScatterSettings");
-
- /* see [1] and [3] for these formulas */
- ss->eta= ior;
- ss->Fdr= -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
- ss->A= (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
- ss->ld= radius;
- ss->ro= min_ff(refl, 0.99f);
- ss->color= ss->ro*reflfac + (1.0f-reflfac);
-
- ss->alpha_= compute_reduced_albedo(ss);
-
- ss->sigma= 1.0f/ss->ld;
- ss->sigma_t_= ss->sigma/sqrtf(3.0f*(1.0f - ss->alpha_));
- ss->sigma_s_= ss->alpha_*ss->sigma_t_;
- ss->sigma_a= ss->sigma_t_ - ss->sigma_s_;
-
- ss->D= 1.0f/(3.0f*ss->sigma_t_);
-
- ss->zr= 1.0f/ss->sigma_t_;
- ss->zv= ss->zr + 4.0f*ss->A*ss->D;
-
- ss->invsigma_t_= 1.0f/ss->sigma_t_;
-
- ss->frontweight= frontweight;
- ss->backweight= backweight;
-
- /* precompute a table of Rd values for quick lookup */
- build_Rd_table(ss);
-
- return ss;
-}
-
-void scatter_settings_free(ScatterSettings *ss)
-{
- MEM_freeN(ss->tableRd);
- MEM_freeN(ss->tableRd2);
- MEM_freeN(ss);
-}
-
-/* Hierarchical method as in [2]. */
-
-/* traversal */
-
-#define SUBNODE_INDEX(co, split) \
- ((co[0]>=split[0]) + (co[1]>=split[1])*2 + (co[2]>=split[2])*4)
-
-static void add_radiance(ScatterTree *tree, float *frontrad, float *backrad, float area, float backarea, float rr, ScatterResult *result)
-{
- float rd[3], frontrd[3], backrd[3];
-
- approximate_Rd_rgb(tree->ss, rr, rd);
-
- if (frontrad && area) {
- frontrd[0] = rd[0]*area;
- frontrd[1] = rd[1]*area;
- frontrd[2] = rd[2]*area;
-
- result->rad[0] += frontrad[0]*frontrd[0];
- result->rad[1] += frontrad[1]*frontrd[1];
- result->rad[2] += frontrad[2]*frontrd[2];
-
- result->rdsum[0] += frontrd[0];
- result->rdsum[1] += frontrd[1];
- result->rdsum[2] += frontrd[2];
- }
- if (backrad && backarea) {
- backrd[0] = rd[0]*backarea;
- backrd[1] = rd[1]*backarea;
- backrd[2] = rd[2]*backarea;
-
- result->backrad[0] += backrad[0]*backrd[0];
- result->backrad[1] += backrad[1]*backrd[1];
- result->backrad[2] += backrad[2]*backrd[2];
-
- result->backrdsum[0] += backrd[0];
- result->backrdsum[1] += backrd[1];
- result->backrdsum[2] += backrd[2];
- }
-}
-
-static void traverse_octree(ScatterTree *tree, ScatterNode *node, const float co[3], int self, ScatterResult *result)
-{
- float sub[3], dist;
- int i, index = 0;
-
- if (node->totpoint > 0) {
- /* leaf - add radiance from all samples */
- for (i=0; i<node->totpoint; i++) {
- ScatterPoint *p= &node->points[i];
-
- sub_v3_v3v3(sub, co, p->co);
- dist= dot_v3v3(sub, sub);
-
- if (p->back)
- add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result);
- else
- add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result);
- }
- }
- else {
- /* branch */
- if (self)
- index = SUBNODE_INDEX(co, node->split);
-
- for (i=0; i<8; i++) {
- if (node->child[i]) {
- ScatterNode *subnode= node->child[i];
-
- if (self && index == i) {
- /* always traverse node containing the point */
- traverse_octree(tree, subnode, co, 1, result);
- }
- else {
- /* decide subnode traversal based on maximum solid angle */
- sub_v3_v3v3(sub, co, subnode->co);
- dist= dot_v3v3(sub, sub);
-
- /* actually area/dist > error, but this avoids division */
- if (subnode->area+subnode->backarea>tree->error*dist) {
- traverse_octree(tree, subnode, co, 0, result);
- }
- else {
- add_radiance(tree, subnode->rad, subnode->backrad,
- subnode->area, subnode->backarea, dist, result);
- }
- }
- }
- }
- }
-}
-
-static void compute_radiance(ScatterTree *tree, const float co[3], float *rad)
-{
- ScatterResult result;
- float rdsum[3], backrad[3], backrdsum[3];
-
- memset(&result, 0, sizeof(result));
-
- traverse_octree(tree, tree->root, co, 1, &result);
-
- /* the original paper doesn't do this, but we normalize over the
- * sampled area and multiply with the reflectance. this is because
- * our point samples are incomplete, there are no samples on parts
- * of the mesh not visible from the camera. this can not only make
- * it darker, but also lead to ugly color shifts */
-
- mul_v3_fl(result.rad, tree->ss[0]->frontweight);
- mul_v3_fl(result.backrad, tree->ss[0]->backweight);
-
- copy_v3_v3(rad, result.rad);
- add_v3_v3v3(backrad, result.rad, result.backrad);
-
- copy_v3_v3(rdsum, result.rdsum);
- add_v3_v3v3(backrdsum, result.rdsum, result.backrdsum);
-
- if (rdsum[0] > 1e-16f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0];
- if (rdsum[1] > 1e-16f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1];
- if (rdsum[2] > 1e-16f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2];
-
- if (backrdsum[0] > 1e-16f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0];
- if (backrdsum[1] > 1e-16f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1];
- if (backrdsum[2] > 1e-16f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2];
-
- rad[0]= MAX2(rad[0], backrad[0]);
- rad[1]= MAX2(rad[1], backrad[1]);
- rad[2]= MAX2(rad[2], backrad[2]);
-}
-
-/* building */
-
-static void sum_leaf_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
-{
- ScatterPoint *p;
- float rad, totrad= 0.0f, inv;
- int i;
-
- node->co[0]= node->co[1]= node->co[2]= 0.0;
- node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
- node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
-
- /* compute total rad, rad weighted average position,
- * and total area */
- for (i=0; i<node->totpoint; i++) {
- p= &node->points[i];
-
- rad= p->area*fabsf(p->rad[0] + p->rad[1] + p->rad[2]);
- totrad += rad;
-
- node->co[0] += rad*p->co[0];
- node->co[1] += rad*p->co[1];
- node->co[2] += rad*p->co[2];
-
- if (p->back) {
- node->backrad[0] += p->rad[0]*p->area;
- node->backrad[1] += p->rad[1]*p->area;
- node->backrad[2] += p->rad[2]*p->area;
-
- node->backarea += p->area;
- }
- else {
- node->rad[0] += p->rad[0]*p->area;
- node->rad[1] += p->rad[1]*p->area;
- node->rad[2] += p->rad[2]*p->area;
-
- node->area += p->area;
- }
- }
-
- if (node->area > 1e-16f) {
- inv= 1.0f/node->area;
- node->rad[0] *= inv;
- node->rad[1] *= inv;
- node->rad[2] *= inv;
- }
- if (node->backarea > 1e-16f) {
- inv= 1.0f/node->backarea;
- node->backrad[0] *= inv;
- node->backrad[1] *= inv;
- node->backrad[2] *= inv;
- }
-
- if (totrad > 1e-16f) {
- inv= 1.0f/totrad;
- node->co[0] *= inv;
- node->co[1] *= inv;
- node->co[2] *= inv;
- }
- else {
- /* make sure that if radiance is 0.0f, we still have these points in
- * the tree at a good position, they count for rdsum too */
- for (i=0; i<node->totpoint; i++) {
- p= &node->points[i];
-
- node->co[0] += p->co[0];
- node->co[1] += p->co[1];
- node->co[2] += p->co[2];
- }
-
- node->co[0] /= node->totpoint;
- node->co[1] /= node->totpoint;
- node->co[2] /= node->totpoint;
- }
-}
-
-static void sum_branch_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
-{
- ScatterNode *subnode;
- float rad, totrad= 0.0f, inv;
- int i, totnode;
-
- node->co[0]= node->co[1]= node->co[2]= 0.0;
- node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
- node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
-
- /* compute total rad, rad weighted average position,
- * and total area */
- for (i=0; i<8; i++) {
- if (node->child[i] == NULL)
- continue;
-
- subnode= node->child[i];
-
- rad= subnode->area*fabsf(subnode->rad[0] + subnode->rad[1] + subnode->rad[2]);
- rad += subnode->backarea*fabsf(subnode->backrad[0] + subnode->backrad[1] + subnode->backrad[2]);
- totrad += rad;
-
- node->co[0] += rad*subnode->co[0];
- node->co[1] += rad*subnode->co[1];
- node->co[2] += rad*subnode->co[2];
-
- node->rad[0] += subnode->rad[0]*subnode->area;
- node->rad[1] += subnode->rad[1]*subnode->area;
- node->rad[2] += subnode->rad[2]*subnode->area;
-
- node->backrad[0] += subnode->backrad[0]*subnode->backarea;
- node->backrad[1] += subnode->backrad[1]*subnode->backarea;
- node->backrad[2] += subnode->backrad[2]*subnode->backarea;
-
- node->area += subnode->area;
- node->backarea += subnode->backarea;
- }
-
- if (node->area > 1e-16f) {
- inv= 1.0f/node->area;
- node->rad[0] *= inv;
- node->rad[1] *= inv;
- node->rad[2] *= inv;
- }
- if (node->backarea > 1e-16f) {
- inv= 1.0f/node->backarea;
- node->backrad[0] *= inv;
- node->backrad[1] *= inv;
- node->backrad[2] *= inv;
- }
-
- if (totrad > 1e-16f) {
- inv= 1.0f/totrad;
- node->co[0] *= inv;
- node->co[1] *= inv;
- node->co[2] *= inv;
- }
- else {
- /* make sure that if radiance is 0.0f, we still have these points in
- * the tree at a good position, they count for rdsum too */
- totnode= 0;
-
- for (i=0; i<8; i++) {
- if (node->child[i]) {
- subnode= node->child[i];
-
- node->co[0] += subnode->co[0];
- node->co[1] += subnode->co[1];
- node->co[2] += subnode->co[2];
-
- totnode++;
- }
- }
-
- node->co[0] /= totnode;
- node->co[1] /= totnode;
- node->co[2] /= totnode;
- }
-}
-
-static void sum_radiance(ScatterTree *tree, ScatterNode *node)
-{
- if (node->totpoint > 0) {
- sum_leaf_radiance(tree, node);
- }
- else {
- int i;
-
- for (i=0; i<8; i++)
- if (node->child[i])
- sum_radiance(tree, node->child[i]);
-
- sum_branch_radiance(tree, node);
- }
-}
-
-static void subnode_middle(int i, float *mid, float *subsize, float *submid)
-{
- int x= i & 1, y= i & 2, z= i & 4;
-
- submid[0]= mid[0] + ((x)? subsize[0]: -subsize[0]);
- submid[1]= mid[1] + ((y)? subsize[1]: -subsize[1]);
- submid[2]= mid[2] + ((z)? subsize[2]: -subsize[2]);
-}
-
-static void create_octree_node(ScatterTree *tree, ScatterNode *node, float *mid, float *size, ScatterPoint **refpoints, int depth)
-{
- ScatterNode *subnode;
- ScatterPoint **subrefpoints, **tmppoints= tree->tmppoints;
- int index, nsize[8], noffset[8], i, subco, used_nodes, usedi;
- float submid[3], subsize[3];
-
- /* stopping condition */
- if (node->totpoint <= MAX_OCTREE_NODE_POINTS || depth == MAX_OCTREE_DEPTH) {
- for (i=0; i<node->totpoint; i++)
- node->points[i]= *(refpoints[i]);
-
- return;
- }
-
- subsize[0]= size[0]*0.5f;
- subsize[1]= size[1]*0.5f;
- subsize[2]= size[2]*0.5f;
-
- node->split[0]= mid[0];
- node->split[1]= mid[1];
- node->split[2]= mid[2];
-
- memset(nsize, 0, sizeof(nsize));
- memset(noffset, 0, sizeof(noffset));
-
- /* count points in subnodes */
- for (i=0; i<node->totpoint; i++) {
- index= SUBNODE_INDEX(refpoints[i]->co, node->split);
- tmppoints[i]= refpoints[i];
- nsize[index]++;
- }
-
- /* here we check if only one subnode is used. if this is the case, we don't
- * create a new node, but rather call this function again, with different
- * size and middle position for the same node. */
- for (usedi=0, used_nodes=0, i=0; i<8; i++) {
- if (nsize[i]) {
- used_nodes++;
- usedi = i;
- }
- if (i != 0)
- noffset[i]= noffset[i-1]+nsize[i-1];
- }
-
- if (used_nodes <= 1) {
- subnode_middle(usedi, mid, subsize, submid);
- create_octree_node(tree, node, submid, subsize, refpoints, depth+1);
- return;
- }
-
- /* reorder refpoints by subnode */
- for (i=0; i<node->totpoint; i++) {
- index= SUBNODE_INDEX(tmppoints[i]->co, node->split);
- refpoints[noffset[index]]= tmppoints[i];
- noffset[index]++;
- }
-
- /* create subnodes */
- for (subco=0, i=0; i<8; subco+=nsize[i], i++) {
- if (nsize[i] > 0) {
- subnode= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
- node->child[i]= subnode;
- subnode->points= node->points + subco;
- subnode->totpoint= nsize[i];
- subrefpoints= refpoints + subco;
-
- subnode_middle(i, mid, subsize, submid);
-
- create_octree_node(tree, subnode, submid, subsize, subrefpoints,
- depth+1);
- }
- else
- node->child[i]= NULL;
- }
-
- node->points= NULL;
- node->totpoint= 0;
-}
-
-/* public functions */
-
-ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
- float (*co)[3], float (*color)[3], float *area, int totpoint)
-{
- ScatterTree *tree;
- ScatterPoint *points, **refpoints;
- int i;
-
- /* allocate tree */
- tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree");
- tree->scale= scale;
- tree->error= error;
- tree->totpoint= totpoint;
-
- tree->ss[0]= ss[0];
- tree->ss[1]= ss[1];
- tree->ss[2]= ss[2];
-
- points = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
- refpoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterRefPoints");
-
- tree->points= points;
- tree->refpoints= refpoints;
-
- /* build points */
- INIT_MINMAX(tree->min, tree->max);
-
- for (i=0; i<totpoint; i++) {
- copy_v3_v3(points[i].co, co[i]);
- copy_v3_v3(points[i].rad, color[i]);
- points[i].area= fabsf(area[i])/(tree->scale*tree->scale);
- points[i].back= (area[i] < 0.0f);
-
- mul_v3_fl(points[i].co, 1.0f / tree->scale);
- minmax_v3v3_v3(tree->min, tree->max, points[i].co);
-
- refpoints[i]= points + i;
- }
-
- return tree;
-}
-
-void scatter_tree_build(ScatterTree *tree)
-{
- ScatterPoint *newpoints, **tmppoints;
- float mid[3], size[3];
- int totpoint= tree->totpoint;
-
- newpoints = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
- tmppoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterTmpPoints");
- tree->tmppoints= tmppoints;
-
- tree->arena= BLI_memarena_new(0x8000 * sizeof(ScatterNode), "sss tree arena");
- BLI_memarena_use_calloc(tree->arena);
-
- /* build tree */
- tree->root= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
- tree->root->points= newpoints;
- tree->root->totpoint= totpoint;
-
- mid[0]= (tree->min[0]+tree->max[0])*0.5f;
- mid[1]= (tree->min[1]+tree->max[1])*0.5f;
- mid[2]= (tree->min[2]+tree->max[2])*0.5f;
-
- size[0]= (tree->max[0]-tree->min[0])*0.5f;
- size[1]= (tree->max[1]-tree->min[1])*0.5f;
- size[2]= (tree->max[2]-tree->min[2])*0.5f;
-
- create_octree_node(tree, tree->root, mid, size, tree->refpoints, 0);
-
- MEM_freeN(tree->points);
- MEM_freeN(tree->refpoints);
- MEM_freeN(tree->tmppoints);
- tree->refpoints= NULL;
- tree->tmppoints= NULL;
- tree->points= newpoints;
-
- /* sum radiance at nodes */
- sum_radiance(tree, tree->root);
-}
-
-void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3])
-{
- float sco[3];
-
- copy_v3_v3(sco, co);
- mul_v3_fl(sco, 1.0f / tree->scale);
-
- compute_radiance(tree, sco, color);
-}
-
-void scatter_tree_free(ScatterTree *tree)
-{
- if (tree->arena) BLI_memarena_free(tree->arena);
- if (tree->points) MEM_freeN(tree->points);
- if (tree->refpoints) MEM_freeN(tree->refpoints);
-
- MEM_freeN(tree);
-}
-
-/* Internal Renderer API */
-
-/* sss tree building */
-
-typedef struct SSSData {
- ScatterTree *tree;
- ScatterSettings *ss[3];
-} SSSData;
-
-typedef struct SSSPoints {
- struct SSSPoints *next, *prev;
-
- float (*co)[3];
- float (*color)[3];
- float *area;
- int totpoint;
-} SSSPoints;
-
-static void sss_create_tree_mat(Render *re, Material *mat)
-{
- SSSPoints *p;
- RenderResult *rr;
- ListBase points;
- float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL;
- int totpoint = 0, osa, osaflag, frsflag, partsdone;
-
- if (re->test_break(re->tbh))
- return;
-
- points.first= points.last= NULL;
-
- /* TODO: this is getting a bit ugly, copying all those variables and
- * setting them back, maybe we need to create our own Render? */
-
- /* do SSS preprocessing render */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rr= re->result;
- osa= re->osa;
- osaflag= re->r.mode & R_OSA;
- frsflag= re->r.mode & R_EDGE_FRS;
- partsdone= re->i.partsdone;
-
- re->osa= 0;
- re->r.mode &= ~(R_OSA | R_EDGE_FRS);
- re->sss_points= &points;
- re->sss_mat= mat;
- re->i.partsdone = 0;
-
- if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)))
- re->result= NULL;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- RE_TileProcessor(re);
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- RE_FreeRenderResult(re->result);
- re->result= rr;
- }
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->i.partsdone= partsdone;
- re->sss_mat= NULL;
- re->sss_points= NULL;
- re->osa= osa;
- if (osaflag) re->r.mode |= R_OSA;
- if (frsflag) re->r.mode |= R_EDGE_FRS;
-
- /* no points? no tree */
- if (!points.first)
- return;
-
- /* merge points together into a single buffer */
- if (!re->test_break(re->tbh)) {
- for (totpoint=0, p=points.first; p; p=p->next)
- totpoint += p->totpoint;
-
- co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo");
- color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor");
- area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea");
-
- for (totpoint=0, p=points.first; p; p=p->next) {
- memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint);
- memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint);
- memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint);
- totpoint += p->totpoint;
- }
- }
-
- /* free points */
- for (p=points.first; p; p=p->next) {
- MEM_freeN(p->co);
- MEM_freeN(p->color);
- MEM_freeN(p->area);
- }
- BLI_freelistN(&points);
-
- /* build tree */
- if (!re->test_break(re->tbh)) {
- SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData");
- float ior= mat->sss_ior, cfac= mat->sss_colfac;
- const float *radius = mat->sss_radius;
- float fw= mat->sss_front, bw= mat->sss_back;
- float error = mat->sss_error;
-
- error= get_render_aosss_error(&re->r, error);
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) && error < 0.5f)
- error= 0.5f;
-
- sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw);
- sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw);
- sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw);
- sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error,
- co, color, area, totpoint);
-
- MEM_freeN(co);
- MEM_freeN(color);
- MEM_freeN(area);
-
- scatter_tree_build(sss->tree);
-
- BLI_ghash_insert(re->sss_hash, mat, sss);
- }
- else {
- if (co) MEM_freeN(co);
- if (color) MEM_freeN(color);
- if (area) MEM_freeN(area);
- }
-}
-
-void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint)
-{
- SSSPoints *p;
-
- if (totpoint > 0) {
- p= MEM_callocN(sizeof(SSSPoints), "SSSPoints");
-
- p->co= co;
- p->color= color;
- p->area= area;
- p->totpoint= totpoint;
-
- BLI_thread_lock(LOCK_CUSTOM1);
- BLI_addtail(re->sss_points, p);
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-}
-
-static void sss_free_tree(SSSData *sss)
-{
- scatter_tree_free(sss->tree);
- scatter_settings_free(sss->ss[0]);
- scatter_settings_free(sss->ss[1]);
- scatter_settings_free(sss->ss[2]);
- MEM_freeN(sss);
-}
-
-/* public functions */
-
-void make_sss_tree(Render *re)
-{
- Material *mat;
- bool infostr_set = false;
- const char *prevstr = NULL;
-
- free_sss(re);
-
- re->sss_hash= BLI_ghash_ptr_new("make_sss_tree gh");
-
- re->stats_draw(re->sdh, &re->i);
-
- for (mat= re->main->mat.first; mat; mat= mat->id.next) {
- if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
- if (!infostr_set) {
- prevstr = re->i.infostr;
- re->i.infostr = IFACE_("SSS preprocessing");
- infostr_set = true;
- }
-
- sss_create_tree_mat(re, mat);
- }
- }
-
- /* XXX preview exception */
- /* localizing preview render data is not fun for node trees :( */
- if (re->main!=G.main) {
- for (mat= G.main->mat.first; mat; mat= mat->id.next) {
- if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
- if (!infostr_set) {
- prevstr = re->i.infostr;
- re->i.infostr = IFACE_("SSS preprocessing");
- infostr_set = true;
- }
-
- sss_create_tree_mat(re, mat);
- }
- }
- }
-
- if (infostr_set)
- re->i.infostr = prevstr;
-}
-
-void free_sss(Render *re)
-{
- if (re->sss_hash) {
- GHashIterator gh_iter;
-
- GHASH_ITER (gh_iter, re->sss_hash) {
- sss_free_tree(BLI_ghashIterator_getValue(&gh_iter));
- }
-
- BLI_ghash_free(re->sss_hash, NULL, NULL);
- re->sss_hash= NULL;
- }
-}
-
-int sample_sss(Render *re, Material *mat, const float co[3], float color[3])
-{
- if (re->sss_hash) {
- SSSData *sss= BLI_ghash_lookup(re->sss_hash, mat);
-
- if (sss) {
- scatter_tree_sample(sss->tree, co, color);
- return 1;
- }
- else {
- color[0]= 0.0f;
- color[1]= 0.0f;
- color[2]= 0.0f;
- }
- }
-
- return 0;
-}
-
-int sss_pass_done(struct Render *re, struct Material *mat)
-{
- return ((re->flag & R_BAKING) || !(re->r.mode & R_SSS) || (re->sss_hash && BLI_ghash_lookup(re->sss_hash, mat)));
-}
-
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
deleted file mode 100644
index 6b52d4aa419..00000000000
--- a/source/blender/render/intern/source/strand.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/strand.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_key_types.h"
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_memarena.h"
-#include "BLI_rand.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_key.h"
-
-
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "strand.h"
-#include "zbuf.h"
-
-/* *************** */
-
-static float strand_eval_width(Material *ma, float strandco)
-{
- float fac;
-
- strandco= 0.5f*(strandco + 1.0f);
-
- if (ma->strand_ease!=0.0f) {
- if (ma->strand_ease<0.0f)
- fac= pow(strandco, 1.0f+ma->strand_ease);
- else
- fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease));
- }
- else fac= strandco;
-
- return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
-}
-
-void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
-{
- Material *ma;
- StrandBuffer *strandbuf;
- const float *simplify;
- float p[4][3], data[4], cross[3], w, dx, dy, t;
- int type;
-
- strandbuf= sseg->buffer;
- ma= sseg->buffer->ma;
- t= spoint->t;
- type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL;
-
- copy_v3_v3(p[0], sseg->v[0]->co);
- copy_v3_v3(p[1], sseg->v[1]->co);
- copy_v3_v3(p[2], sseg->v[2]->co);
- copy_v3_v3(p[3], sseg->v[3]->co);
-
- if (sseg->obi->flag & R_TRANSFORMED) {
- mul_m4_v3(sseg->obi->mat, p[0]);
- mul_m4_v3(sseg->obi->mat, p[1]);
- mul_m4_v3(sseg->obi->mat, p[2]);
- mul_m4_v3(sseg->obi->mat, p[3]);
- }
-
- if (t == 0.0f) {
- copy_v3_v3(spoint->co, p[1]);
- spoint->strandco= sseg->v[1]->strandco;
-
- spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco);
- if (sseg->v[0] != sseg->v[1])
- spoint->dtstrandco *= 0.5f;
- }
- else if (t == 1.0f) {
- copy_v3_v3(spoint->co, p[2]);
- spoint->strandco= sseg->v[2]->strandco;
-
- spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco);
- if (sseg->v[3] != sseg->v[2])
- spoint->dtstrandco *= 0.5f;
- }
- else {
- key_curve_position_weights(t, data, type);
- spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
- spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
- spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
- spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco;
- }
-
- key_curve_tangent_weights(t, data, type);
- spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
- spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
- spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
-
- normalize_v3_v3(spoint->tan, spoint->dtco);
- normalize_v3_v3(spoint->nor, spoint->co);
- negate_v3(spoint->nor);
-
- spoint->width= strand_eval_width(ma, spoint->strandco);
-
- /* simplification */
- simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0);
- spoint->alpha= (simplify)? simplify[1]: 1.0f;
-
- /* outer points */
- cross_v3_v3v3(cross, spoint->co, spoint->tan);
-
- w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
- dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
- dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
- w = sqrtf(dx * dx + dy * dy);
-
- if (w > 0.0f) {
- if (strandbuf->flag & R_STRAND_B_UNITS) {
- const float crosslen= len_v3(cross);
- w= 2.0f*crosslen*strandbuf->minwidth/w;
-
- if (spoint->width < w) {
- spoint->alpha= spoint->width/w;
- spoint->width= w;
- }
-
- if (simplify)
- /* squared because we only change width, not length */
- spoint->width *= simplify[0]*simplify[0];
-
- mul_v3_fl(cross, spoint->width*0.5f/crosslen);
- }
- else
- mul_v3_fl(cross, spoint->width/w);
- }
-
- sub_v3_v3v3(spoint->co1, spoint->co, cross);
- add_v3_v3v3(spoint->co2, spoint->co, cross);
-
- copy_v3_v3(spoint->dsco, cross);
-}
-
-/* *************** */
-
-static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
-}
-
-static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
- v[1]= negt*v1[1] + t*v2[1];
- v[2]= negt*v1[2] + t*v2[2];
-}
-
-static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
- v[1]= negt*v1[1] + t*v2[1];
- v[2]= negt*v1[2] + t*v2[2];
- v[3]= negt*v1[3] + t*v2[3];
-}
-
-static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
-{
- float negt= 1.0f - t;
-
- interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined);
-
- if (addpassflag & SCE_PASS_VECTOR) {
- interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed);
- }
- /* optim... */
- if (addpassflag & ~(SCE_PASS_VECTOR)) {
- if (addpassflag & SCE_PASS_Z)
- interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z);
- if (addpassflag & SCE_PASS_RGBA)
- interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col);
- if (addpassflag & SCE_PASS_NORMAL) {
- interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor);
- normalize_v3(shr->nor);
- }
- if (addpassflag & SCE_PASS_EMIT)
- interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit);
- if (addpassflag & SCE_PASS_DIFFUSE) {
- interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff);
- interpolate_vec3(shr1->diffshad, shr2->diffshad, t, negt, shr->diffshad);
- }
- if (addpassflag & SCE_PASS_SPEC)
- interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec);
- if (addpassflag & SCE_PASS_SHADOW)
- interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad);
- if (addpassflag & SCE_PASS_AO)
- interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao);
- if (addpassflag & SCE_PASS_ENVIRONMENT)
- interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env);
- if (addpassflag & SCE_PASS_INDIRECT)
- interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect);
- if (addpassflag & SCE_PASS_REFLECT)
- interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl);
- if (addpassflag & SCE_PASS_REFRACT)
- interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
- if (addpassflag & SCE_PASS_MIST)
- interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist);
- }
-}
-
-static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha)
-{
- if (alpha < 1.0f) {
- shr->combined[0] *= alpha;
- shr->combined[1] *= alpha;
- shr->combined[2] *= alpha;
- shr->combined[3] *= alpha;
-
- shr->col[0] *= alpha;
- shr->col[1] *= alpha;
- shr->col[2] *= alpha;
- shr->col[3] *= alpha;
-
- shr->alpha *= alpha;
- }
-}
-
-static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint)
-{
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
- VlakRen vlr;
- int seed;
-
- memset(&vlr, 0, sizeof(vlr));
- vlr.flag= R_SMOOTH;
- if (sseg->buffer->ma->mode & MA_TANGENT_STR)
- vlr.flag |= R_TANGENT;
-
- shi->vlr= &vlr;
- shi->v1= NULL;
- shi->v2= NULL;
- shi->v3= NULL;
- shi->strand= sseg->strand;
- shi->obi= sseg->obi;
- shi->obr= sseg->obi->obr;
-
- /* cache for shadow */
- shi->samplenr= re->shadowsamplenr[shi->thread]++;
-
- /* all samples */
- shi->mask= 0xFFFF;
-
- /* seed RNG for consistent results across tiles */
- seed = shi->strand->index + (svert - shi->strand->vert);
- BLI_thread_srandom(shi->thread, seed);
-
- shade_input_set_strand(shi, sseg->strand, spoint);
- shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* shade */
- shade_samples_do_AO(ssamp);
- shade_input_do_shade(shi, shr);
-
- /* apply simplification */
- strand_apply_shaderesult_alpha(shr, spoint->alpha);
-
- /* include lamphalos for strand, since halo layer was added already */
- if (re->flag & R_LAMPHALO)
- if (shi->layflag & SCE_LAY_HALO)
- renderspothalo(shi, shr->combined, shr->combined[3]);
-
- shi->strand= NULL;
-}
-
-/* *************** */
-
-struct StrandShadeCache {
- GHash *resulthash;
- GHash *refcounthash;
- MemArena *memarena;
-};
-
-typedef struct StrandCacheEntry {
- GHashPair pair;
- ShadeResult shr;
-} StrandCacheEntry;
-
-StrandShadeCache *strand_shade_cache_create(void)
-{
- StrandShadeCache *cache;
-
- cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache");
- cache->resulthash= BLI_ghash_pair_new("strand_shade_cache_create1 gh");
- cache->refcounthash= BLI_ghash_pair_new("strand_shade_cache_create2 gh");
- cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena");
-
- return cache;
-}
-
-void strand_shade_cache_free(StrandShadeCache *cache)
-{
- BLI_ghash_free(cache->refcounthash, NULL, NULL);
- BLI_ghash_free(cache->resulthash, MEM_freeN, NULL);
- BLI_memarena_free(cache->memarena);
- MEM_freeN(cache);
-}
-
-static GHashPair strand_shade_hash_pair(ObjectInstanceRen *obi, StrandVert *svert)
-{
- GHashPair pair = {obi, svert};
- return pair;
-}
-
-static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert)
-{
- StrandCacheEntry *entry;
- StrandPoint p;
- int *refcount;
- GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
-
- entry= BLI_ghash_lookup(cache->resulthash, &pair);
- refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- if (!entry) {
- /* not shaded yet, shade and insert into hash */
- p.t= (sseg->v[1] == svert)? 0.0f: 1.0f;
- strand_eval_point(sseg, &p);
- strand_shade_point(re, ssamp, sseg, svert, &p);
-
- entry= MEM_callocN(sizeof(StrandCacheEntry), "StrandCacheEntry");
- entry->pair = pair;
- entry->shr = ssamp->shr[0];
- BLI_ghash_insert(cache->resulthash, entry, entry);
- }
- else
- /* already shaded, just copy previous result from hash */
- ssamp->shr[0]= entry->shr;
-
- /* lower reference count and remove if not needed anymore by any samples */
- (*refcount)--;
- if (*refcount == 0) {
- BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
- BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
- }
-}
-
-void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag)
-{
- ShadeResult shr1, shr2;
-
- /* get shading for two endpoints and interpolate */
- strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]);
- shr1= ssamp->shr[0];
- strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]);
- shr2= ssamp->shr[0];
-
- interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag);
-
- /* apply alpha along width */
- if (sseg->buffer->widthfade != -1.0f) {
- s = 1.0f - powf(fabsf(s), sseg->buffer->widthfade);
-
- strand_apply_shaderesult_alpha(ssamp->shr, s);
- }
-}
-
-void strand_shade_unref(StrandShadeCache *cache, ObjectInstanceRen *obi, StrandVert *svert)
-{
- GHashPair pair = strand_shade_hash_pair(obi, svert);
- int *refcount;
-
- /* lower reference count and remove if not needed anymore by any samples */
- refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- (*refcount)--;
- if (*refcount == 0) {
- BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
- BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
- }
-}
-
-static void strand_shade_refcount(StrandShadeCache *cache, StrandSegment *sseg, StrandVert *svert)
-{
- GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
- GHashPair *key;
- int *refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- if (!refcount) {
- key= BLI_memarena_alloc(cache->memarena, sizeof(GHashPair));
- *key = pair;
- refcount= BLI_memarena_alloc(cache->memarena, sizeof(int));
- *refcount= 1;
- BLI_ghash_insert(cache->refcounthash, key, refcount);
- }
- else
- (*refcount)++;
-}
-
-/* *************** */
-
-typedef struct StrandPart {
- Render *re;
- ZSpan *zspan;
-
- APixstrand *apixbuf;
- int *totapixbuf;
- int *rectz;
- int *rectmask;
- intptr_t *rectdaps;
- int rectx, recty;
- int sample;
- int shadow;
- float (*jit)[2];
- int samples;
-
- StrandSegment *segment;
- float t[3], s[3];
-
- StrandShadeCache *cache;
-} StrandPart;
-
-typedef struct StrandSortSegment {
- struct StrandSortSegment *next;
- int obi, strand, segment;
- float z;
-} StrandSortSegment;
-
-static int compare_strand_segment(const void *poin1, const void *poin2)
-{
- const StrandSortSegment *seg1= (const StrandSortSegment*)poin1;
- const StrandSortSegment *seg2= (const StrandSortSegment*)poin2;
-
- if (seg1->z < seg2->z)
- return -1;
- else if (seg1->z == seg2->z)
- return 0;
- else
- return 1;
-}
-
-static void do_strand_point_project(float winmat[4][4], ZSpan *zspan, float *co, float *hoco, float *zco)
-{
- projectvert(co, winmat, hoco);
- hoco_to_zco(zspan, zco, hoco);
-}
-
-static void strand_project_point(float winmat[4][4], float winx, float winy, StrandPoint *spoint)
-{
- float div;
-
- projectvert(spoint->co, winmat, spoint->hoco);
-
- div= 1.0f/spoint->hoco[3];
- spoint->x= spoint->hoco[0]*div*winx*0.5f;
- spoint->y= spoint->hoco[1]*div*winy*0.5f;
-}
-
-static APixstrand *addpsmainAstrand(ListBase *lb)
-{
- APixstrMain *psm;
-
- psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
- BLI_addtail(lb, psm);
- psm->ps = MEM_callocN(4096 * sizeof(APixstrand), "pixstr");
-
- return psm->ps;
-}
-
-static APixstrand *addpsAstrand(ZSpan *zspan)
-{
- /* make new PS */
- if (zspan->apstrandmcounter==0) {
- zspan->curpstrand= addpsmainAstrand(zspan->apsmbase);
- zspan->apstrandmcounter= 4095;
- }
- else {
- zspan->curpstrand++;
- zspan->apstrandmcounter--;
- }
- return zspan->curpstrand;
-}
-
-#define MAX_ZROW 2000
-
-static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z)
-{
- StrandPart *spart= (StrandPart *)handle;
- StrandShadeCache *cache= spart->cache;
- StrandSegment *sseg= spart->segment;
- APixstrand *apn, *apnew;
- float t, s;
- int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0;
-
- offset = y*spart->rectx + x;
- obi= sseg->obi - spart->re->objectinstance;
- strnr= sseg->strand->index + 1;
- seg= sseg->v[1] - sseg->strand->vert;
- mask= (1<<spart->sample);
-
- /* check against solid z-buffer */
- zverg= (int)z;
-
- if (spart->rectdaps) {
- /* find the z of the sample */
- PixStr *ps;
- intptr_t *rd= spart->rectdaps + offset;
-
- bufferz= 0x7FFFFFFF;
- if (spart->rectmask) maskz= 0x7FFFFFFF;
-
- if (*rd) {
- for (ps= (PixStr *)(*rd); ps; ps= ps->next) {
- if (mask & ps->mask) {
- bufferz= ps->z;
- if (spart->rectmask)
- maskz= ps->maskz;
- break;
- }
- }
- }
- }
- else {
- bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF;
- if (spart->rectmask)
- maskz= spart->rectmask[offset];
- }
-
-#define CHECK_ADD(n) \
- if (apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \
- { if (!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } (void)0
-#define CHECK_ASSIGN(n) \
- if (apn->p[n]==0) \
- {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } (void)0
-
- /* add to pixel list */
- if (zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) {
- if (!spart->rectmask || zverg > maskz) {
- t = u * spart->t[0] + v * spart->t[1] + (1.0f - u - v) * spart->t[2];
- s = fabsf(u * spart->s[0] + v * spart->s[1] + (1.0f - u - v) * spart->s[2]);
-
- apn= spart->apixbuf + offset;
- while (apn) {
- CHECK_ADD(0);
- CHECK_ADD(1);
- CHECK_ADD(2);
- CHECK_ADD(3);
- CHECK_ASSIGN(0);
- CHECK_ASSIGN(1);
- CHECK_ASSIGN(2);
- CHECK_ASSIGN(3);
-
- apnew= addpsAstrand(spart->zspan);
- SWAP(APixstrand, *apnew, *apn);
- apn->next= apnew;
- CHECK_ASSIGN(0);
- }
-
- if (cache) {
- strand_shade_refcount(cache, sseg, sseg->v[1]);
- strand_shade_refcount(cache, sseg, sseg->v[2]);
- }
- spart->totapixbuf[offset]++;
- }
- }
-}
-
-/* width is calculated in hoco space, to ensure strands are visible */
-static int strand_test_clip(float winmat[4][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy)
-{
- float hoco[4];
- int clipflag= 0;
-
- projectvert(co, winmat, hoco);
-
- /* we compare z without perspective division for segment sorting */
- *zcomp= hoco[2];
-
- if (hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1;
- else if (hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2;
-
- if (hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4;
- else if (hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8;
-
- clipflag |= testclip(hoco);
-
- return clipflag;
-}
-
-static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample)
-{
- float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy;
-
- copy_v3_v3(jco1, co1);
- copy_v3_v3(jco2, co2);
- copy_v3_v3(jco3, co3);
- copy_v3_v3(jco4, co4);
-
- if (spart->jit) {
- jx= -spart->jit[sample][0];
- jy= -spart->jit[sample][1];
-
- jco1[0] += jx; jco1[1] += jy;
- jco2[0] += jx; jco2[1] += jy;
- jco3[0] += jx; jco3[1] += jy;
- jco4[0] += jx; jco4[1] += jy;
-
- /* XXX mblur? */
- }
-
- spart->sample= sample;
-
- spart->t[0]= t-dt;
- spart->s[0]= -1.0f;
- spart->t[1]= t-dt;
- spart->s[1]= 1.0f;
- spart->t[2]= t;
- spart->s[2]= 1.0f;
- zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac);
- spart->t[0]= t-dt;
- spart->s[0]= -1.0f;
- spart->t[1]= t;
- spart->s[1]= 1.0f;
- spart->t[2]= t;
- spart->s[2]= -1.0f;
- zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac);
-}
-
-static void strand_render(Render *re, StrandSegment *sseg, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2)
-{
- if (spart) {
- float t= p2->t;
- float dt= p2->t - p1->t;
- int a;
-
- for (a=0; a<spart->samples; a++)
- do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a);
- }
- else {
- float hoco1[4], hoco2[4];
- int a, obi, index;
-
- obi= sseg->obi - re->objectinstance;
- index= sseg->strand->index;
-
- projectvert(p1->co, winmat, hoco1);
- projectvert(p2->co, winmat, hoco2);
-
-
- for (a=0; a<totzspan; a++) {
-#if 0
- /* render both strand and single pixel wire to counter aliasing */
- zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2);
-#endif
- /* only render a line for now, which makes the shadow map more
- * similar across frames, and so reduces flicker */
- zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2);
- }
- }
-}
-
-static int strand_segment_recursive(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
-{
- StrandPoint p;
- StrandBuffer *buffer= sseg->buffer;
- float dot, d1[2], d2[2], len1, len2;
-
- if (depth == buffer->maxdepth)
- return 0;
-
- p.t= (p1->t + p2->t)*0.5f;
- strand_eval_point(sseg, &p);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p);
-
- d1[0]= (p.x - p1->x);
- d1[1]= (p.y - p1->y);
- len1= d1[0]*d1[0] + d1[1]*d1[1];
-
- d2[0]= (p2->x - p.x);
- d2[1]= (p2->y - p.y);
- len2= d2[0]*d2[0] + d2[1]*d2[1];
-
- if (len1 == 0.0f || len2 == 0.0f)
- return 0;
-
- dot= d1[0]*d2[0] + d1[1]*d2[1];
- if (dot*dot > sseg->sqadaptcos*len1*len2)
- return 0;
-
- if (spart) {
- do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1);
- do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2);
- }
- else {
-#if 0
- projectvert(p.co1, winmat, p.hoco1);
- projectvert(p.co2, winmat, p.hoco2);
- p.clip1= testclip(p.hoco1);
- p.clip2= testclip(p.hoco2);
-#endif
- }
-
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p);
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2);
-
- return 1;
-}
-
-void render_strand_segment(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg)
-{
- StrandBuffer *buffer= sseg->buffer;
- StrandPoint *p1= &sseg->point1;
- StrandPoint *p2= &sseg->point2;
-
- p1->t= 0.0f;
- p2->t= 1.0f;
-
- strand_eval_point(sseg, p1);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1);
- strand_eval_point(sseg, p2);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2);
-
- if (spart) {
- do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1);
- do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2);
- do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1);
- do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2);
- }
- else {
-#if 0
- projectvert(p1->co1, winmat, p1->hoco1);
- projectvert(p1->co2, winmat, p1->hoco2);
- projectvert(p2->co1, winmat, p2->hoco1);
- projectvert(p2->co2, winmat, p2->hoco2);
- p1->clip1= testclip(p1->hoco1);
- p1->clip2= testclip(p1->hoco2);
- p2->clip1= testclip(p2->hoco1);
- p2->clip2= testclip(p2->hoco2);
-#endif
- }
-
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2);
-}
-
-/* render call to fill in strands */
-int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- ZSpan zspan;
- StrandRen *strand = NULL;
- StrandVert *svert;
- StrandBound *sbound;
- StrandPart spart;
- StrandSegment sseg;
- StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
- MemArena *memarena;
- float z[4], bounds[4], obwinmat[4][4];
- int a, b, c, i, totsegment, clip[4];
-
- if (re->test_break(re->tbh))
- return 0;
- if (re->totstrand == 0)
- return 0;
-
- /* setup StrandPart */
- memset(&spart, 0, sizeof(spart));
-
- spart.re= re;
- spart.rectx= pa->rectx;
- spart.recty= pa->recty;
- spart.apixbuf= apixbuf;
- spart.zspan= &zspan;
- spart.rectdaps= pa->rectdaps;
- spart.rectz= pa->rectz;
- spart.rectmask= pa->rectmask;
- spart.cache= cache;
- spart.shadow= shadow;
- spart.jit= jit;
- spart.samples= samples;
-
- zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan.zmulx= ((float)winx)/2.0f;
- zspan.zmuly= ((float)winy)/2.0f;
-
- zspan.zofsx= -pa->disprect.xmin;
- zspan.zofsy= -pa->disprect.ymin;
-
- /* to center the sample position */
- if (!shadow) {
- zspan.zofsx -= 0.5f;
- zspan.zofsy -= 0.5f;
- }
-
- zspan.apsmbase= apsmbase;
-
- /* clipping setup */
- bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
- bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
- bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
- bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
-
- memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena");
- firstseg= NULL;
- totsegment= 0;
-
- /* for all object instances */
- for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
- Material *ma;
- float widthx, widthy;
-
- obr= obi->obr;
-
- if (!obr->strandbuf || !(obr->strandbuf->lay & lay))
- continue;
-
- /* compute matrix and try clipping whole object */
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- /* test if we should skip it */
- ma = obr->strandbuf->ma;
-
- if (shadow && (!(ma->mode2 & MA_CASTSHADOW) || !(ma->mode & MA_SHADBUF)))
- continue;
- else if (!shadow && (ma->mode & MA_ONLYCAST))
- continue;
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
- widthy= obr->strandbuf->maxwidth*obwinmat[1][1];
-
- /* for each bounding box containing a number of strands */
- sbound= obr->strandbuf->bound;
- for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
- if (clip_render_object(sbound->boundbox, bounds, obwinmat))
- continue;
-
- /* for each strand in this bounding box */
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
- svert= strand->vert;
-
- /* keep clipping and z depth for 4 control points */
- clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
- clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
- clip[0]= clip[1]; z[0]= z[1];
-
- for (b=0; b<strand->totvert-1; b++, svert++) {
- /* compute 4th point clipping and z depth */
- if (b < strand->totvert-2) {
- clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
- }
- else {
- clip[3]= clip[2]; z[3]= z[2];
- }
-
- /* check clipping and add to sortsegments buffer */
- if (!(clip[0] & clip[1] & clip[2] & clip[3])) {
- sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
- sortseg->obi= i;
- sortseg->strand= strand->index;
- sortseg->segment= b;
-
- sortseg->z= 0.5f*(z[1] + z[2]);
-
- sortseg->next= firstseg;
- firstseg= sortseg;
- totsegment++;
- }
-
- /* shift clipping and z depth */
- clip[0]= clip[1]; z[0]= z[1];
- clip[1]= clip[2]; z[1]= z[2];
- clip[2]= clip[3]; z[2]= z[3];
- }
- }
- }
- }
-
- if (!re->test_break(re->tbh)) {
- /* convert list to array and sort */
- sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
- for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
- sortsegments[a]= *sortseg;
- qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
- }
-
- BLI_memarena_free(memarena);
-
- spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");
-
- if (!re->test_break(re->tbh)) {
- /* render segments in sorted order */
- sortseg= sortsegments;
- for (a=0; a<totsegment; a++, sortseg++) {
- if (re->test_break(re->tbh))
- break;
-
- obi= &re->objectinstance[sortseg->obi];
- obr= obi->obr;
-
- sseg.obi= obi;
- sseg.strand= RE_findOrAddStrand(obr, sortseg->strand);
- sseg.buffer= sseg.strand->buffer;
- sseg.sqadaptcos= sseg.buffer->adaptcos;
- sseg.sqadaptcos *= sseg.sqadaptcos;
-
- svert= sseg.strand->vert + sortseg->segment;
- sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
- sseg.shaded= 0;
-
- spart.segment= &sseg;
-
- render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
- }
- }
-
- if (sortsegments)
- MEM_freeN(sortsegments);
- MEM_freeN(spart.totapixbuf);
-
- zbuf_free_span(&zspan);
-
- return totsegment;
-}
-
-/* *************** */
-
-StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[4][4], int timeoffset)
-{
- StrandSurface *mesh;
- MFace *mface;
- MVert *mvert;
- float (*co)[3];
- int a, totvert, totface;
-
- totvert= dm->getNumVerts(dm);
- totface= dm->getNumTessFaces(dm);
-
- for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
- if ((mesh->obr.ob == obr->ob) &&
- (mesh->obr.par == obr->par) &&
- (mesh->obr.index == obr->index) &&
- (mesh->totvert == totvert) &&
- (mesh->totface == totface))
- {
- break;
- }
- }
-
- if (!mesh) {
- mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface");
- mesh->obr= *obr;
- mesh->totvert= totvert;
- mesh->totface= totface;
- mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces");
- mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO");
- mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv");
- mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect");
- BLI_addtail(&re->strandsurface, mesh);
- }
-
- if (timeoffset == -1 && !mesh->prevco)
- mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else if (timeoffset == 0 && !mesh->co)
- mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else if (timeoffset == 1 && !mesh->nextco)
- mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else
- return mesh;
-
- mvert= dm->getVertArray(dm);
- for (a=0; a<mesh->totvert; a++, mvert++) {
- copy_v3_v3(co[a], mvert->co);
- mul_m4_v3(mat, co[a]);
- }
-
- mface= dm->getTessFaceArray(dm);
- for (a=0; a<mesh->totface; a++, mface++) {
- mesh->face[a][0]= mface->v1;
- mesh->face[a][1]= mface->v2;
- mesh->face[a][2]= mface->v3;
- mesh->face[a][3]= mface->v4;
- }
-
- return mesh;
-}
-
-void free_strand_surface(Render *re)
-{
- StrandSurface *mesh;
-
- for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
- if (mesh->co) MEM_freeN(mesh->co);
- if (mesh->prevco) MEM_freeN(mesh->prevco);
- if (mesh->nextco) MEM_freeN(mesh->nextco);
- if (mesh->ao) MEM_freeN(mesh->ao);
- if (mesh->env) MEM_freeN(mesh->env);
- if (mesh->indirect) MEM_freeN(mesh->indirect);
- if (mesh->face) MEM_freeN(mesh->face);
- }
-
- BLI_freelistN(&re->strandsurface);
-}
-
-void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width)
-{
- StrandVert *svert;
- const float width2 = width * 2.0f;
- float vec[3];
- int a;
-
- for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
- copy_v3_v3(vec, svert->co);
- minmax_v3v3_v3(min, max, vec);
-
- if (width!=0.0f) {
- add_v3_fl(vec, width);
- minmax_v3v3_v3(min, max, vec);
- add_v3_fl(vec, -width2);
- minmax_v3v3_v3(min, max, vec);
- }
- }
-}
-
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
deleted file mode 100644
index f0cf29e98ca..00000000000
--- a/source/blender/render/intern/source/sunsky.c
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * ***** 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.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/sunsky.c
- * \ingroup render
- *
- * This feature comes from Preetham paper on "A Practical Analytic Model for Daylight"
- * and example code from Brian Smits, another author of that paper in
- * http://www.cs.utah.edu/vissim/papers/sunsky/code/
- */
-
-#include "sunsky.h"
-#include "BLI_math.h"
-
-/**
- * These macros are defined for vector operations
- * */
-
-/**
- * compute v1 = v2 op v3
- * v1, v2 and v3 are vectors contains 3 float
- * */
-#define VEC3OPV(v1, v2, op, v3) \
- { \
- v1[0] = (v2[0] op v3[0]); \
- v1[1] = (v2[1] op v3[1]); \
- v1[2] = (v2[2] op v3[2]); \
- } (void)0
-
-/**
- * compute v1 = v2 op f1
- * v1, v2 are vectors contains 3 float
- * and f1 is a float
- * */
-#define VEC3OPF(v1, v2, op, f1) \
- { \
- v1[0] = (v2[0] op(f1)); \
- v1[1] = (v2[1] op(f1)); \
- v1[2] = (v2[2] op(f1)); \
- } (void)0
-
-/**
- * compute v1 = f1 op v2
- * v1, v2 are vectors contains 3 float
- * and f1 is a float
- * */
-#define FOPVEC3(v1, f1, op, v2) \
- { \
- v1[0] = ((f1) op v2[0]); \
- v1[1] = ((f1) op v2[1]); \
- v1[2] = ((f1) op v2[2]); \
- } (void)0
-
-/**
- * ClipColor:
- * clip a color to range [0, 1];
- * */
-void ClipColor(float c[3])
-{
- if (c[0] > 1.0f) c[0] = 1.0f;
- if (c[0] < 0.0f) c[0] = 0.0f;
- if (c[1] > 1.0f) c[1] = 1.0f;
- if (c[1] < 0.0f) c[1] = 0.0f;
- if (c[2] > 1.0f) c[2] = 1.0f;
- if (c[2] < 0.0f) c[2] = 0.0f;
-}
-
-/**
- * AngleBetween:
- * compute angle between to direction
- * all angles are in radians
- * */
-static float AngleBetween(float thetav, float phiv, float theta, float phi)
-{
- float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
-
- if (cospsi > 1.0f)
- return 0;
- if (cospsi < -1.0f)
- return M_PI;
-
- return acosf(cospsi);
-}
-
-/**
- * DirectionToThetaPhi:
- * this function convert a direction to it's theta and phi value
- * parameters:
- * toSun: contains direction information
- * theta, phi, are return values from this conversion
- * */
-static void DirectionToThetaPhi(float *toSun, float *theta, float *phi)
-{
- *theta = acosf(toSun[2]);
- if (fabsf(*theta) < 1e-5f)
- *phi = 0;
- else
- *phi = atan2f(toSun[1], toSun[0]);
-}
-
-/**
- * PerezFunction:
- * compute perez function value based on input parameters
- */
-static float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz)
-{
- float den, num;
-
- den = ((1 + lam[0] * expf(lam[1])) *
- (1 + lam[2] * expf(lam[3] * sunsky->theta) + lam[4] * cosf(sunsky->theta) * cosf(sunsky->theta)));
-
- num = ((1 + lam[0] * expf(lam[1] / cosf(theta))) *
- (1 + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma)));
-
- return(lvz * num / den);
-}
-
-/**
- * InitSunSky:
- * this function compute some sun,sky parameters according to input parameters and also initiate some other sun, sky parameters
- * parameters:
- * sunSky, is a structure that contains information about sun, sky and atmosphere, in this function, most of its values initiated
- * turb, is atmosphere turbidity
- * toSun, contains sun direction
- * horizon_brighness, controls the brightness of the horizon colors
- * spread, controls colors spreed at horizon
- * sun_brightness, controls sun's brightness
- * sun_size, controls sun's size
- * back_scatter, controls back scatter light
- * */
-void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
- float spread, float sun_brightness, float sun_size, float back_scatter,
- float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace)
-{
- float theta2;
- float theta3;
- float T;
- float T2;
- float chi;
-
- sunsky->turbidity = turb;
-
- sunsky->horizon_brightness = horizon_brightness;
- sunsky->spread = spread;
- sunsky->sun_brightness = sun_brightness;
- sunsky->sun_size = sun_size;
- sunsky->backscattered_light = back_scatter;
- sunsky->skyblendfac = skyblendfac;
- sunsky->skyblendtype = skyblendtype;
- sunsky->sky_exposure = -sky_exposure;
- sunsky->sky_colorspace = sky_colorspace;
-
- sunsky->toSun[0] = toSun[0];
- sunsky->toSun[1] = toSun[1];
- sunsky->toSun[2] = toSun[2];
-
- DirectionToThetaPhi(sunsky->toSun, &sunsky->theta, &sunsky->phi);
-
- sunsky->sunSolidAngle = 0.25 * M_PI * 1.39 * 1.39 / (150 * 150); /* = 6.7443e-05 */
-
- theta2 = sunsky->theta * sunsky->theta;
- theta3 = theta2 * sunsky->theta;
- T = turb;
- T2 = turb * turb;
-
- chi = (4.0f / 9.0f - T / 120.0f) * ((float)M_PI - 2.0f * sunsky->theta);
- sunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
- sunsky->zenith_Y *= 1000; /* conversion from kcd/m^2 to cd/m^2 */
-
- if (sunsky->zenith_Y <= 0)
- sunsky->zenith_Y = 1e-6;
-
- sunsky->zenith_x =
- (+0.00165f * theta3 - 0.00374f * theta2 + 0.00208f * sunsky->theta + 0.0f) * T2 +
- (-0.02902f * theta3 + 0.06377f * theta2 - 0.03202f * sunsky->theta + 0.00394f) * T +
- (+0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * sunsky->theta + 0.25885f);
-
- sunsky->zenith_y =
- (+0.00275f * theta3 - 0.00610f * theta2 + 0.00316f * sunsky->theta + 0.0f) * T2 +
- (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * sunsky->theta + 0.00515f) * T +
- (+0.15346f * theta3 - 0.26756f * theta2 + 0.06669f * sunsky->theta + 0.26688f);
-
-
- sunsky->perez_Y[0] = 0.17872f * T - 1.46303f;
- sunsky->perez_Y[1] = -0.35540f * T + 0.42749f;
- sunsky->perez_Y[2] = -0.02266f * T + 5.32505f;
- sunsky->perez_Y[3] = 0.12064f * T - 2.57705f;
- sunsky->perez_Y[4] = -0.06696f * T + 0.37027f;
-
- sunsky->perez_x[0] = -0.01925f * T - 0.25922f;
- sunsky->perez_x[1] = -0.06651f * T + 0.00081f;
- sunsky->perez_x[2] = -0.00041f * T + 0.21247f;
- sunsky->perez_x[3] = -0.06409f * T - 0.89887f;
- sunsky->perez_x[4] = -0.00325f * T + 0.04517f;
-
- sunsky->perez_y[0] = -0.01669f * T - 0.26078f;
- sunsky->perez_y[1] = -0.09495f * T + 0.00921f;
- sunsky->perez_y[2] = -0.00792f * T + 0.21023f;
- sunsky->perez_y[3] = -0.04405f * T - 1.65369f;
- sunsky->perez_y[4] = -0.01092f * T + 0.05291f;
-
- /* suggested by glome in patch [#8063] */
- sunsky->perez_Y[0] *= sunsky->horizon_brightness;
- sunsky->perez_x[0] *= sunsky->horizon_brightness;
- sunsky->perez_y[0] *= sunsky->horizon_brightness;
-
- sunsky->perez_Y[1] *= sunsky->spread;
- sunsky->perez_x[1] *= sunsky->spread;
- sunsky->perez_y[1] *= sunsky->spread;
-
- sunsky->perez_Y[2] *= sunsky->sun_brightness;
- sunsky->perez_x[2] *= sunsky->sun_brightness;
- sunsky->perez_y[2] *= sunsky->sun_brightness;
-
- sunsky->perez_Y[3] *= sunsky->sun_size;
- sunsky->perez_x[3] *= sunsky->sun_size;
- sunsky->perez_y[3] *= sunsky->sun_size;
-
- sunsky->perez_Y[4] *= sunsky->backscattered_light;
- sunsky->perez_x[4] *= sunsky->backscattered_light;
- sunsky->perez_y[4] *= sunsky->backscattered_light;
-}
-
-/**
- * GetSkyXYZRadiance:
- * this function compute sky radiance according to a view parameters `theta' and `phi'and sunSky values
- * parameters:
- * sunSky, sontains sun and sky parameters
- * theta, is sun's theta
- * phi, is sun's phi
- * color_out, is computed color that shows sky radiance in XYZ color format
- * */
-void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3])
-{
- float gamma;
- float x, y, Y, X, Z;
- float hfade = 1, nfade = 1;
-
-
- if (theta > (float)M_PI_2) {
- hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f;
- hfade = hfade * hfade * (3.0f - 2.0f * hfade);
- theta = M_PI_2;
- }
-
- if (sunsky->theta > (float)M_PI_2) {
- if (theta <= (float)M_PI_2) {
- nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f;
- nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f;
- nfade = nfade * nfade * (3.0f - 2.0f * nfade);
- }
- }
-
- gamma = AngleBetween(theta, phi, sunsky->theta, sunsky->phi);
-
- /* Compute xyY values */
- x = PerezFunction(sunsky, sunsky->perez_x, theta, gamma, sunsky->zenith_x);
- y = PerezFunction(sunsky, sunsky->perez_y, theta, gamma, sunsky->zenith_y);
- Y = 6.666666667e-5f * nfade * hfade * PerezFunction(sunsky, sunsky->perez_Y, theta, gamma, sunsky->zenith_Y);
-
- if (sunsky->sky_exposure != 0.0f)
- Y = 1.0 - exp(Y * sunsky->sky_exposure);
-
- X = (x / y) * Y;
- Z = ((1 - x - y) / y) * Y;
-
- color_out[0] = X;
- color_out[1] = Y;
- color_out[2] = Z;
-}
-
-/**
- * GetSkyXYZRadiancef:
- * this function compute sky radiance according to a view direction `varg' and sunSky values
- * parameters:
- * sunSky, sontains sun and sky parameters
- * varg, shows direction
- * color_out, is computed color that shows sky radiance in XYZ color format
- * */
-void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3])
-{
- float theta, phi;
- float v[3];
-
- normalize_v3_v3(v, varg);
-
- if (v[2] < 0.001f) {
- v[2] = 0.001f;
- normalize_v3(v);
- }
-
- DirectionToThetaPhi(v, &theta, &phi);
- GetSkyXYZRadiance(sunsky, theta, phi, color_out);
-}
-
-/**
- * ComputeAttenuatedSunlight:
- * this function compute attenuated sun light based on sun's theta and atmosphere turbidity
- * parameters:
- * theta, is sun's theta
- * turbidity: is atmosphere turbidity
- * fTau: contains computed attenuated sun light
- * */
-static void ComputeAttenuatedSunlight(float theta, int turbidity, float fTau[3])
-{
- float fBeta;
- float fTauR, fTauA;
- float m;
- float fAlpha;
-
- int i;
- float fLambda[3];
- fLambda[0] = 0.65f;
- fLambda[1] = 0.57f;
- fLambda[2] = 0.475f;
-
- fAlpha = 1.3f;
- fBeta = 0.04608365822050f * turbidity - 0.04586025928522f;
-
- m = 1.0f / (cosf(theta) + 0.15f * powf(93.885f - theta / (float)M_PI * 180.0f, -1.253f));
-
- for (i = 0; i < 3; i++) {
- /* Rayleigh Scattering */
- fTauR = expf(-m * 0.008735f * powf(fLambda[i], (float)(-4.08f)));
-
- /* Aerosal (water + dust) attenuation */
- fTauA = exp(-m * fBeta * powf(fLambda[i], -fAlpha));
-
- fTau[i] = fTauR * fTauA;
- }
-}
-
-/**
- * InitAtmosphere:
- * this function initiate sunSky structure with user input parameters.
- * parameters:
- * sunSky, contains information about sun, and in this function some atmosphere parameters will initiated
- * sun_intens, shows sun intensity value
- * mief, Mie scattering factor this factor currently call with 1.0
- * rayf, Rayleigh scattering factor, this factor currently call with 1.0
- * inscattf, inscatter light factor that range from 0.0 to 1.0, 0.0 means no inscatter light and 1.0 means full inscatter light
- * extincf, extinction light factor that range from 0.0 to 1.0, 0.0 means no extinction and 1.0 means full extinction
- * disf, is distance factor, multiplied to pixle's z value to compute each pixle's distance to camera,
- * */
-void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf,
- float inscattf, float extincf, float disf)
-{
- const float pi = M_PI;
- const float n = 1.003f; /* refractive index */
- const float N = 2.545e25;
- const float pn = 0.035f;
- const float T = 2.0f;
- float fTemp, fTemp2, fTemp3, fBeta, fBetaDash;
- float c = (6.544f * T - 6.51f) * 1e-17f;
- float K[3] = {0.685f, 0.679f, 0.670f};
- float vBetaMieTemp[3];
-
- float fLambda[3], fLambda2[3], fLambda4[3];
- float vLambda2[3];
- float vLambda4[3];
-
- int i;
-
- sunSky->atm_SunIntensity = sun_intens;
- sunSky->atm_BetaMieMultiplier = mief;
- sunSky->atm_BetaRayMultiplier = rayf;
- sunSky->atm_InscatteringMultiplier = inscattf;
- sunSky->atm_ExtinctionMultiplier = extincf;
- sunSky->atm_DistanceMultiplier = disf;
-
- sunSky->atm_HGg = 0.8;
-
- fLambda[0] = 1 / 650e-9f;
- fLambda[1] = 1 / 570e-9f;
- fLambda[2] = 1 / 475e-9f;
- for (i = 0; i < 3; i++) {
- fLambda2[i] = fLambda[i] * fLambda[i];
- fLambda4[i] = fLambda2[i] * fLambda2[i];
- }
-
- vLambda2[0] = fLambda2[0];
- vLambda2[1] = fLambda2[1];
- vLambda2[2] = fLambda2[2];
-
- vLambda4[0] = fLambda4[0];
- vLambda4[1] = fLambda4[1];
- vLambda4[2] = fLambda4[2];
-
- /* Rayleigh scattering constants. */
- fTemp = pi * pi * (n * n - 1) * (n * n - 1) * (6 + 3 * pn) / (6 - 7 * pn) / N;
- fBeta = 8 * fTemp * pi / 3;
-
- VEC3OPF(sunSky->atm_BetaRay, vLambda4, *, fBeta);
- fBetaDash = fTemp / 2;
- VEC3OPF(sunSky->atm_BetaDashRay, vLambda4, *, fBetaDash);
-
-
- /* Mie scattering constants. */
- fTemp2 = 0.434f * c * (2 * pi) * (2 * pi) * 0.5f;
- VEC3OPF(sunSky->atm_BetaDashMie, vLambda2, *, fTemp2);
-
- fTemp3 = 0.434f * c * pi * (2 * pi) * (2 * pi);
-
- VEC3OPV(vBetaMieTemp, K, *, fLambda);
- VEC3OPF(sunSky->atm_BetaMie, vBetaMieTemp, *, fTemp3);
-
-}
-
-/**
- * AtmospherePixleShader:
- * this function apply atmosphere effect on a pixle color `rgb' at distance `s'
- * parameters:
- * sunSky, contains information about sun parameters and user values
- * view, is camera view vector
- * s, is distance
- * rgb, contains rendered color value for a pixle
- * */
-void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3])
-{
- float costheta;
- float Phase_1;
- float Phase_2;
- float sunColor[3];
-
- float E[3];
- float E1[3];
-
-
- float I[3];
- float fTemp;
- float vTemp1[3], vTemp2[3];
-
- float sunDirection[3];
-
- s *= sunSky->atm_DistanceMultiplier;
-
- sunDirection[0] = sunSky->toSun[0];
- sunDirection[1] = sunSky->toSun[1];
- sunDirection[2] = sunSky->toSun[2];
-
- costheta = dot_v3v3(view, sunDirection); /* cos(theta) */
- Phase_1 = 1 + (costheta * costheta); /* Phase_1 */
-
- VEC3OPF(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier);
- VEC3OPF(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier);
- VEC3OPV(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie);
-
- /* e^(-(beta_1 + beta_2) * s) = E1 */
- VEC3OPF(E1, sunSky->atm_BetaRM, *, -s / (float)M_LN2);
- E1[0] = exp(E1[0]);
- E1[1] = exp(E1[1]);
- E1[2] = exp(E1[2]);
-
- copy_v3_v3(E, E1);
-
- /* Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2) */
- fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta;
- fTemp = fTemp * sqrtf(fTemp);
- Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg) / fTemp;
-
- VEC3OPF(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1);
- VEC3OPF(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2);
-
- VEC3OPV(vTemp1, vTemp1, +, vTemp2);
- FOPVEC3(vTemp2, 1.0f, -, E1);
- VEC3OPV(vTemp1, vTemp1, *, vTemp2);
-
- FOPVEC3(vTemp2, 1.0f, /, sunSky->atm_BetaRM);
-
- VEC3OPV(I, vTemp1, *, vTemp2);
-
- VEC3OPF(I, I, *, sunSky->atm_InscatteringMultiplier);
- VEC3OPF(E, E, *, sunSky->atm_ExtinctionMultiplier);
-
- /* scale to color sun */
- ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor);
- VEC3OPV(E, E, *, sunColor);
-
- VEC3OPF(I, I, *, sunSky->atm_SunIntensity);
-
- VEC3OPV(rgb, rgb, *, E);
- VEC3OPV(rgb, rgb, +, I);
-}
-
-#undef VEC3OPV
-#undef VEC3OPF
-#undef FOPVEC3
-
-/* EOF */
diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c
deleted file mode 100644
index a932123243d..00000000000
--- a/source/blender/render/intern/source/texture_ocean.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * ***** 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: Matt Ebb
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/texture_ocean.c
- * \ingroup bke
- */
-
-#include <stddef.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_global.h" /* XXX */
-
-#include "BKE_modifier.h"
-#include "BKE_ocean.h"
-
-#include "render_types.h"
-#include "RE_shader_ext.h"
-
-#include "texture.h"
-
-#include "texture_ocean.h" /* own include */
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ***** actual texture sampling ***** */
-int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres)
-{
- OceanTex *ot = tex->ot;
- ModifierData *md;
- OceanModifierData *omd;
-
- texres->tin = 0.0f;
-
- if ( !(ot) ||
- !(ot->object) ||
- !(md = (ModifierData *)modifiers_findByType(ot->object, eModifierType_Ocean)) ||
- !(omd = (OceanModifierData *)md)->ocean)
- {
- return 0;
- }
- else {
- const bool do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS) != 0;
- int cfra = R.r.cfra;
- int retval = TEX_INT;
-
- OceanResult ocr;
- const float u = 0.5f + 0.5f * texvec[0];
- const float v = 0.5f + 0.5f * texvec[1];
-
- if (omd->oceancache && omd->cached == true) {
-
- CLAMP(cfra, omd->bakestart, omd->bakeend);
- cfra -= omd->bakestart; /* shift to 0 based */
-
- BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
-
- }
- else { /* non-cached */
-
- if (G.is_rendering)
- BKE_ocean_eval_uv_catrom(omd->ocean, &ocr, u, v);
- else
- BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
-
- ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
- }
-
- switch (ot->output) {
- case TEX_OCN_DISPLACEMENT:
- /* XYZ displacement */
- texres->tr = 0.5f + 0.5f * ocr.disp[0];
- texres->tg = 0.5f + 0.5f * ocr.disp[2];
- texres->tb = 0.5f + 0.5f * ocr.disp[1];
-
- texres->tr = MAX2(0.0f, texres->tr);
- texres->tg = MAX2(0.0f, texres->tg);
- texres->tb = MAX2(0.0f, texres->tb);
-
- BRICONTRGB;
-
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_EMINUS:
- /* -ve eigenvectors ? */
- texres->tr = ocr.Eminus[0];
- texres->tg = ocr.Eminus[2];
- texres->tb = ocr.Eminus[1];
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_EPLUS:
- /* -ve eigenvectors ? */
- texres->tr = ocr.Eplus[0];
- texres->tg = ocr.Eplus[2];
- texres->tb = ocr.Eplus[1];
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_JPLUS:
- texres->tin = ocr.Jplus;
- retval = TEX_INT;
- break;
-
- case TEX_OCN_FOAM:
-
- texres->tin = ocr.foam;
-
- BRICONT;
-
- retval = TEX_INT;
- break;
- }
-
- /* if normals needed */
-
- if (texres->nor && do_normals) {
- normalize_v3_v3(texres->nor, ocr.normal);
- retval |= TEX_NOR;
- }
-
- texres->ta = 1.0f;
-
- return retval;
- }
-}
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
deleted file mode 100644
index 752a9df0b79..00000000000
--- a/source/blender/render/intern/source/volume_precache.c
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb, Ra˙l Fern·ndez Hern·ndez (Farsthary).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/volume_precache.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_task.h"
-#include "BLI_threads.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "PIL_time.h"
-
-#include "RE_shader_ext.h"
-
-#include "DNA_material_types.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "volumetric.h"
-#include "volume_precache.h"
-
-#include "atomic_ops.h"
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
-
-/* Recursive test for intersections, from a point inside the mesh, to outside
- * Number of intersections (depth) determine if a point is inside or outside the mesh */
-static int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth)
-{
- if (limit == 0) return depth;
-
- if (RE_rayobject_raycast(tree, isect)) {
-
- isect->start[0] = isect->start[0] + isect->dist*isect->dir[0];
- isect->start[1] = isect->start[1] + isect->dist*isect->dir[1];
- isect->start[2] = isect->start[2] + isect->dist*isect->dir[2];
-
- isect->dist = FLT_MAX;
- isect->skip = RE_SKIP_VLR_NEIGHBOUR;
- isect->orig.face= isect->hit.face;
- isect->orig.ob= isect->hit.ob;
-
- return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
- }
- else {
- return depth;
- }
-}
-
-/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
-static int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, const float co[3])
-{
- Isect isect= {{0}};
- float dir[3] = {0.0f, 0.0f, 1.0f};
- int final_depth=0, depth=0, limit=20;
-
- /* set up the isect */
- copy_v3_v3(isect.start, co);
- copy_v3_v3(isect.dir, dir);
- isect.mode= RE_RAY_MIRROR;
- isect.last_hit= NULL;
- isect.lay= -1;
-
- isect.dist = FLT_MAX;
- isect.orig.face= NULL;
- isect.orig.ob = NULL;
-
- RE_instance_rotate_ray(obi, &isect);
- final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth);
- RE_instance_rotate_ray_restore(obi, &isect);
-
- /* even number of intersections: point is outside
- * odd number: point is inside */
- if (final_depth % 2 == 0) return 0;
- else return 1;
-}
-
-/* find the bounding box of an objectinstance in global space */
-void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3])
-{
- ObjectRen *obr = obi->obr;
- VolumePrecache *vp = obi->volume_precache;
- VertRen *ver= NULL;
- float co[3];
- int a;
-
- if (vp->bbmin != NULL && vp->bbmax != NULL) {
- copy_v3_v3(bbmin, vp->bbmin);
- copy_v3_v3(bbmax, vp->bbmax);
- return;
- }
-
- vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner");
- vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner");
-
- INIT_MINMAX(bbmin, bbmax);
-
- for (a=0; a<obr->totvert; a++) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- copy_v3_v3(co, ver->co);
-
- /* transformed object instance in camera space */
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, co);
-
- /* convert to global space */
- mul_m4_v3(re->viewinv, co);
-
- minmax_v3v3_v3(vp->bbmin, vp->bbmax, co);
- }
-
- copy_v3_v3(bbmin, vp->bbmin);
- copy_v3_v3(bbmax, vp->bbmax);
-
-}
-
-/* *** light cache filtering *** */
-
-static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
-{
- int x, y, z, x_, y_, z_;
- int added=0;
- float tot=0.0f;
-
- for (z=-1; z <= 1; z++) {
- z_ = zz+z;
- if (z_ >= 0 && z_ <= res[2]-1) {
-
- for (y=-1; y <= 1; y++) {
- y_ = yy+y;
- if (y_ >= 0 && y_ <= res[1]-1) {
-
- for (x=-1; x <= 1; x++) {
- x_ = xx+x;
- if (x_ >= 0 && x_ <= res[0]-1) {
- const int64_t i = BLI_VOXEL_INDEX(x_, y_, z_, res);
-
- if (cache[i] > 0.0f) {
- tot += cache[i];
- added++;
- }
-
- }
- }
- }
- }
- }
- }
-
- if (added > 0) tot /= added;
-
- return tot;
-}
-
-/* function to filter the edges of the light cache, where there was no volume originally.
- * For each voxel which was originally external to the mesh, it finds the average values of
- * the surrounding internal voxels and sets the original external voxel to that average amount.
- * Works almost a bit like a 'dilate' filter */
-static void lightcache_filter(VolumePrecache *vp)
-{
- int x, y, z;
-
- for (z=0; z < vp->res[2]; z++) {
- for (y=0; y < vp->res[1]; y++) {
- for (x=0; x < vp->res[0]; x++) {
- /* trigger for outside mesh */
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
-
- if (vp->data_r[i] < -0.f)
- vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
- if (vp->data_g[i] < -0.f)
- vp->data_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
- if (vp->data_b[i] < -0.f)
- vp->data_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
- }
- }
- }
-}
-
-#if 0
-static void lightcache_filter2(VolumePrecache *vp)
-{
- int x, y, z;
- float *new_r, *new_g, *new_b;
- int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float);
-
- new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel");
- new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel");
- new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel");
-
- memcpy(new_r, vp->data_r, field_size);
- memcpy(new_g, vp->data_g, field_size);
- memcpy(new_b, vp->data_b, field_size);
-
- for (z=0; z < vp->res[2]; z++) {
- for (y=0; y < vp->res[1]; y++) {
- for (x=0; x < vp->res[0]; x++) {
- /* trigger for outside mesh */
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
- if (vp->data_r[i] < -0.f)
- new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
- if (vp->data_g[i] < -0.f)
- new_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
- if (vp->data_b[i] < -0.f)
- new_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
- }
- }
- }
-
- SWAP(float *, vp->data_r, new_r);
- SWAP(float *, vp->data_g, new_g);
- SWAP(float *, vp->data_b, new_b);
-
- if (new_r) { MEM_freeN(new_r); new_r=NULL; }
- if (new_g) { MEM_freeN(new_g); new_g=NULL; }
- if (new_b) { MEM_freeN(new_b); new_b=NULL; }
-}
-#endif
-
-/* has a pad of 1 voxel surrounding the core for boundary simulation */
-BLI_INLINE int64_t ms_I(int x, int y, int z, const int *n)
-{
- /* different ordering to light cache */
- return ((int64_t)x * (int64_t)(n[1] + 2) * (int64_t)(n[2] + 2) +
- (int64_t)y * (int64_t)(n[2] + 2) +
- (int64_t)z);
-}
-
-/* has a pad of 1 voxel surrounding the core for boundary simulation */
-BLI_INLINE int64_t v_I_pad(int x, int y, int z, const int *n)
-{
- /* same ordering to light cache, with padding */
- return ((int64_t)z * (int64_t)(n[1] + 2) * (int64_t)(n[0] + 2) +
- (int64_t)y * (int64_t)(n[0] + 2) +
- (int64_t)x);
-}
-
-BLI_INLINE int64_t lc_to_ms_I(int x, int y, int z, const int *n)
-{
- /* converting light cache index to multiple scattering index */
- return ((int64_t)(x - 1) * ((int64_t)n[1] * (int64_t)n[2]) +
- (int64_t)(y - 1) * ((int64_t)n[2]) +
- (int64_t)(z - 1));
-}
-
-/* *** multiple scattering approximation *** */
-
-/* get the total amount of light energy in the light cache. used to normalize after multiple scattering */
-static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp)
-{
- int x, y, z;
- const int *res = vp->res;
- float energy=0.f;
-
- for (z=0; z < res[2]; z++) {
- for (y=0; y < res[1]; y++) {
- for (x=0; x < res[0]; x++) {
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, res);
-
- if (vp->data_r[i] > 0.f) energy += vp->data_r[i];
- if (vp->data_g[i] > 0.f) energy += vp->data_g[i];
- if (vp->data_b[i] > 0.f) energy += vp->data_b[i];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- return energy;
-}
-
-static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, const int res[3])
-{
- int x, y, z;
- float energy=0.f;
-
- for (z=1;z<=res[2];z++) {
- for (y=1;y<=res[1];y++) {
- for (x=1;x<=res[0];x++) {
- const int64_t i = ms_I(x, y, z, res);
-
- if (sr[i] > 0.f) energy += sr[i];
- if (sg[i] > 0.f) energy += sg[i];
- if (sb[i] > 0.f) energy += sb[i];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- return energy;
-}
-
-/**
- * \param n: the unpadded resolution
- */
-static void ms_diffuse(Render *re, int do_test_break, const float *x0, float *x, float diff, const int n[3])
-{
- int i, j, k, l;
- const float dt = VOL_MS_TIMESTEP;
- int64_t size = (int64_t)n[0] * (int64_t)n[1] * (int64_t)n[2];
- const float a = dt * diff * size;
-
- for (l=0; l<20; l++) {
- for (k=1; k<=n[2]; k++) {
- for (j=1; j<=n[1]; j++) {
- for (i=1; i<=n[0]; i++) {
- x[v_I_pad(i, j, k, n)] =
- ((x0[v_I_pad(i, j, k, n)]) + (
- (x0[v_I_pad(i - 1, j, k, n)] +
- x0[v_I_pad(i + 1, j, k, n)] +
- x0[v_I_pad(i, j - 1, k, n)] +
- x0[v_I_pad(i, j + 1, k, n)] +
- x0[v_I_pad(i, j, k - 1, n)] +
- x0[v_I_pad(i, j, k + 1, n)]) * a) / (1 + 6 * a));
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- if (re->test_break(re->tbh)) break;
- }
-}
-
-static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
-{
- const float diff = ma->vol.ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */
- const int simframes = (int)(ma->vol.ms_spread * (float)max_iii(vp->res[0], vp->res[1], vp->res[2]));
- const int shade_type = ma->vol.shade_type;
- float fac = ma->vol.ms_intensity;
-
- int x, y, z, m;
- const int *n = vp->res;
- const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
- const int do_test_break = (size > 100000);
- double time, lasttime= PIL_check_seconds_timer();
- float total;
- float c=1.0f;
- float origf; /* factor for blending in original light cache */
- float energy_ss, energy_ms;
-
- float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
-
- total = (float)(n[0]*n[1]*n[2]*simframes);
-
- energy_ss = total_ss_energy(re, do_test_break, vp);
-
- /* Scattering as diffusion pass */
- for (m=0; m<simframes; m++) {
- /* add sources */
- for (z=1; z<=n[2]; z++) {
- for (y=1; y<=n[1]; y++) {
- for (x=1; x<=n[0]; x++) {
- const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
- const int64_t j = ms_I(x, y, z, n); //ms index
-
- time= PIL_check_seconds_timer();
- c++;
- if (vp->data_r[i] > 0.0f)
- sr[j] += vp->data_r[i];
- if (vp->data_g[i] > 0.0f)
- sg[j] += vp->data_g[i];
- if (vp->data_b[i] > 0.0f)
- sb[j] += vp->data_b[i];
-
- /* Displays progress every second */
- if (time-lasttime>1.0) {
- char str[64];
- BLI_snprintf(str, sizeof(str), IFACE_("Simulating multiple scattering: %d%%"),
- (int)(100.0f * (c / total)));
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
- lasttime= time;
- }
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- if (re->test_break(re->tbh)) break;
-
- SWAP(float *, sr, sr0);
- SWAP(float *, sg, sg0);
- SWAP(float *, sb, sb0);
-
- /* main diffusion simulation */
- ms_diffuse(re, do_test_break, sr0, sr, diff, n);
- ms_diffuse(re, do_test_break, sg0, sg, diff, n);
- ms_diffuse(re, do_test_break, sb0, sb, diff, n);
-
- if (re->test_break(re->tbh)) break;
- }
-
- /* normalization factor to conserve energy */
- energy_ms = total_ms_energy(re, do_test_break, sr, sg, sb, n);
- fac *= (energy_ss / energy_ms);
-
- /* blend multiple scattering back in the light cache */
- if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
- /* conserve energy - half single, half multiple */
- origf = 0.5f;
- fac *= 0.5f;
- }
- else {
- origf = 0.0f;
- }
-
- for (z=1;z<=n[2];z++) {
- for (y=1;y<=n[1];y++) {
- for (x=1;x<=n[0];x++) {
- const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
- const int64_t j = ms_I(x, y, z, n); //ms index
-
- vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j];
- vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j];
- vp->data_b[i] = origf * vp->data_b[i] + fac * sb[j];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- MEM_freeN(sr0);
- MEM_freeN(sr);
- MEM_freeN(sg0);
- MEM_freeN(sg);
- MEM_freeN(sb0);
- MEM_freeN(sb);
-}
-
-
-
-#if 0 /* debug stuff */
-static void *vol_precache_part_test(void *data)
-{
- VolPrecachePart *pa = data;
-
- printf("part number: %d\n", pa->num);
- printf("done: %d\n", pa->done);
- printf("x min: %d x max: %d\n", pa->minx, pa->maxx);
- printf("y min: %d y max: %d\n", pa->miny, pa->maxy);
- printf("z min: %d z max: %d\n", pa->minz, pa->maxz);
-
- return NULL;
-}
-#endif
-
-/* Iterate over the 3d voxel grid, and fill the voxels with scattering information
- *
- * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
- * I'm guessing the memory alignment may work out better this way for the purposes
- * of doing linear interpolation, but I haven't actually tested this theory! :)
- */
-typedef struct VolPrecacheState {
- double lasttime;
- unsigned int doneparts;
- unsigned int totparts;
-} VolPrecacheState;
-
-static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
-{
- VolPrecacheState *state = (VolPrecacheState *)BLI_task_pool_userdata(pool);
- VolPrecachePart *pa = (VolPrecachePart *)taskdata;
- Render *re = pa->re;
-
- ObjectInstanceRen *obi = pa->obi;
- RayObject *tree = pa->tree;
- ShadeInput *shi = pa->shi;
- float scatter_col[3] = {0.f, 0.f, 0.f};
- float co[3], cco[3], view[3];
- int x, y, z;
- int res[3];
- double time;
-
- if (re->test_break && re->test_break(re->tbh))
- return;
-
- //printf("thread id %d\n", threadid);
-
- res[0]= pa->res[0];
- res[1]= pa->res[1];
- res[2]= pa->res[2];
-
- for (z= pa->minz; z < pa->maxz; z++) {
- co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
-
- for (y= pa->miny; y < pa->maxy; y++) {
- co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
-
- for (x=pa->minx; x < pa->maxx; x++) {
- int64_t i;
- co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
-
- if (re->test_break && re->test_break(re->tbh))
- break;
-
- /* convert from world->camera space for shading */
- mul_v3_m4v3(cco, pa->viewmat, co);
-
- i = BLI_VOXEL_INDEX(x, y, z, res);
-
- /* don't bother if the point is not inside the volume mesh */
- if (!point_inside_obi(tree, obi, cco)) {
- obi->volume_precache->data_r[i] = -1.0f;
- obi->volume_precache->data_g[i] = -1.0f;
- obi->volume_precache->data_b[i] = -1.0f;
- continue;
- }
-
- copy_v3_v3(view, cco);
- normalize_v3(view);
- vol_get_scattering(shi, scatter_col, cco, view);
-
- obi->volume_precache->data_r[i] = scatter_col[0];
- obi->volume_precache->data_g[i] = scatter_col[1];
- obi->volume_precache->data_b[i] = scatter_col[2];
-
- }
- }
- }
-
- unsigned int doneparts = atomic_add_and_fetch_u(&state->doneparts, 1);
-
- time = PIL_check_seconds_timer();
- if (time - state->lasttime > 1.0) {
- ThreadMutex *mutex = BLI_task_pool_user_mutex(pool);
-
- if (BLI_mutex_trylock(mutex)) {
- char str[64];
- float ratio = (float)doneparts/(float)state->totparts;
- BLI_snprintf(str, sizeof(str), IFACE_("Precaching volume: %d%%"), (int)(100.0f * ratio));
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
- state->lasttime = time;
-
- BLI_mutex_unlock(mutex);
- }
- }
-}
-
-static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
-{
- memset(shi, 0, sizeof(ShadeInput));
- shi->depth= 1;
- shi->mask= 1;
- shi->mat = ma;
- shi->vlr = NULL;
- memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); /* note, keep this synced with render_types.h */
- shi->har= shi->mat->har;
- shi->obi= obi;
- shi->obr= obi->obr;
- shi->lay = re->lay;
-}
-
-static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- VolumePrecache *vp = obi->volume_precache;
- VolPrecacheState state;
- int i=0, x, y, z;
- float voxel[3];
- int sizex, sizey, sizez;
- float bbmin[3], bbmax[3];
- const int *res;
- int minx, maxx;
- int miny, maxy;
- int minz, maxz;
- int totthread = re->r.threads;
- int parts[3];
-
- if (!vp) return;
-
- /* currently we just subdivide the box, number of threads per side */
- parts[0] = parts[1] = parts[2] = totthread;
- res = vp->res;
-
- /* setup task scheduler */
- memset(&state, 0, sizeof(state));
- state.doneparts = 0;
- state.totparts = parts[0]*parts[1]*parts[2];
- state.lasttime = PIL_check_seconds_timer();
-
- task_scheduler = BLI_task_scheduler_create(totthread);
- task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- /* using boundbox in worldspace */
- global_bounds_obi(re, obi, bbmin, bbmax);
- sub_v3_v3v3(voxel, bbmax, bbmin);
-
- voxel[0] /= (float)res[0];
- voxel[1] /= (float)res[1];
- voxel[2] /= (float)res[2];
-
- for (x=0; x < parts[0]; x++) {
- sizex = ceil(res[0] / (float)parts[0]);
- minx = x * sizex;
- maxx = minx + sizex;
- maxx = (maxx>res[0])?res[0]:maxx;
-
- for (y=0; y < parts[1]; y++) {
- sizey = ceil(res[1] / (float)parts[1]);
- miny = y * sizey;
- maxy = miny + sizey;
- maxy = (maxy>res[1])?res[1]:maxy;
-
- for (z=0; z < parts[2]; z++) {
- VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
-
- sizez = ceil(res[2] / (float)parts[2]);
- minz = z * sizez;
- maxz = minz + sizez;
- maxz = (maxz>res[2])?res[2]:maxz;
-
- pa->re = re;
- pa->num = i;
- pa->tree = tree;
- pa->shi = shi;
- pa->obi = obi;
- copy_m4_m4(pa->viewmat, re->viewmat);
-
- copy_v3_v3(pa->bbmin, bbmin);
- copy_v3_v3(pa->voxel, voxel);
- copy_v3_v3_int(pa->res, res);
-
- pa->minx = minx; pa->maxx = maxx;
- pa->miny = miny; pa->maxy = maxy;
- pa->minz = minz; pa->maxz = maxz;
-
- BLI_task_pool_push(task_pool, vol_precache_part, pa, true, TASK_PRIORITY_HIGH);
-
- i++;
- }
- }
- }
-
- /* work and wait until tasks are done */
- BLI_task_pool_work_and_wait(task_pool);
-
- /* free */
- BLI_task_pool_free(task_pool);
- BLI_task_scheduler_free(task_scheduler);
-}
-
-/* calculate resolution from bounding box in world space */
-static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen *obi, int res)
-{
- float dim[3], div;
- float bbmin[3], bbmax[3];
-
- /* bound box in global space */
- global_bounds_obi(re, obi, bbmin, bbmax);
- sub_v3_v3v3(dim, bbmax, bbmin);
-
- div = max_fff(dim[0], dim[1], dim[2]);
- dim[0] /= div;
- dim[1] /= div;
- dim[2] /= div;
-
- vp->res[0] = ceil(dim[0] * res);
- vp->res[1] = ceil(dim[1] * res);
- vp->res[2] = ceil(dim[2] * res);
-
- if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1))
- return 0;
-
- return 1;
-}
-
-/* Precache a volume into a 3D voxel grid.
- * The voxel grid is stored in the ObjectInstanceRen,
- * in camera space, aligned with the ObjectRen's bounding box.
- * Resolution is defined by the user.
- */
-static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
-{
- VolumePrecache *vp;
- RayObject *tree;
- ShadeInput shi;
-
- R = *re;
-
- /* create a raytree with just the faces of the instanced ObjectRen,
- * used for checking if the cached point is inside or outside. */
- tree = makeraytree_object(&R, obi);
- if (!tree) return;
-
- vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
- obi->volume_precache = vp;
-
- if (!precache_resolution(re, vp, obi, ma->vol.precache_resolution)) {
- MEM_freeN(vp);
- vp = NULL;
- return;
- }
-
- vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
- vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
- vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
- if (vp->data_r==NULL || vp->data_g==NULL || vp->data_b==NULL) {
- MEM_freeN(vp);
- return;
- }
-
- /* Need a shadeinput to calculate scattering */
- precache_setup_shadeinput(re, obi, ma, &shi);
-
- precache_launch_parts(re, tree, &shi, obi);
-
- if (tree) {
- /* TODO: makeraytree_object creates a tree and saves it on OBI,
- * if we free this tree we should also clear other pointers to it */
- //RE_rayobject_free(tree);
- //tree= NULL;
- }
-
- if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
- /* this should be before the filtering */
- multiple_scattering_diffusion(re, obi->volume_precache, ma);
- }
-
- lightcache_filter(obi->volume_precache);
-}
-
-static int using_lightcache(Material *ma)
-{
- return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED)) ||
- (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)));
-}
-
-/* loop through all objects (and their associated materials)
- * marked for pre-caching in convertblender.c, and pre-cache them */
-void volume_precache(Render *re)
-{
- ObjectInstanceRen *obi;
- VolumeOb *vo;
-
- re->i.infostr = IFACE_("Volume preprocessing");
- re->stats_draw(re->sdh, &re->i);
-
- for (vo= re->volumes.first; vo; vo= vo->next) {
- if (using_lightcache(vo->ma)) {
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->obr == vo->obr) {
- vol_precache_objectinstance_threads(re, obi, vo->ma);
-
- if (re->test_break && re->test_break(re->tbh))
- break;
- }
- }
-
- if (re->test_break && re->test_break(re->tbh))
- break;
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-void free_volume_precache(Render *re)
-{
- ObjectInstanceRen *obi;
-
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->volume_precache != NULL) {
- MEM_freeN(obi->volume_precache->data_r);
- MEM_freeN(obi->volume_precache->data_g);
- MEM_freeN(obi->volume_precache->data_b);
- MEM_freeN(obi->volume_precache->bbmin);
- MEM_freeN(obi->volume_precache->bbmax);
- MEM_freeN(obi->volume_precache);
- obi->volume_precache = NULL;
- }
- }
-
- BLI_freelistN(&re->volumes);
-}
-
-int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3])
-{
- RayObject *tree;
- int inside=0;
-
- tree = makeraytree_object(re, obi);
- if (!tree) return 0;
-
- inside = point_inside_obi(tree, obi, co);
-
- //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
- //RE_rayobject_free(tree);
- //tree= NULL;
-
- return inside;
-}
-
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
deleted file mode 100644
index e12a7246254..00000000000
--- a/source/blender/render/intern/source/volumetric.c
+++ /dev/null
@@ -1,834 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/volumetric.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "RE_shader_ext.h"
-
-#include "IMB_colormanagement.h"
-
-#include "DNA_material_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_meta_types.h"
-
-
-#include "render_types.h"
-#include "pixelshading.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "shadbuf.h"
-#include "texture.h"
-#include "volumetric.h"
-#include "volume_precache.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* tracing */
-static float vol_get_shadow(ShadeInput *shi, LampRen *lar, const float co[3])
-{
- float visibility = 1.f;
-
- if (lar->shb) {
- float dxco[3] = {0.f, 0.f, 0.f}, dyco[3] = {0.f, 0.f, 0.f};
-
- visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0);
- }
- else if (lar->mode & LA_SHAD_RAY) {
- /* trace shadow manually, no good lamp api atm */
- Isect is;
-
- copy_v3_v3(is.start, co);
- if (lar->type == LA_SUN || lar->type == LA_HEMI) {
- is.dir[0] = -lar->vec[0];
- is.dir[1] = -lar->vec[1];
- is.dir[2] = -lar->vec[2];
- is.dist = R.maxdist;
- }
- else {
- sub_v3_v3v3(is.dir, lar->co, is.start);
- is.dist = normalize_v3(is.dir);
- }
-
- is.mode = RE_RAY_MIRROR;
- is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
- is.skip = 0;
-
- if (lar->mode & (LA_LAYER | LA_LAYER_SHADOW))
- is.lay = lar->lay;
- else
- is.lay = -1;
-
- is.orig.ob = NULL;
- is.orig.face = NULL;
- is.last_hit = lar->last_hit[shi->thread];
-
- RE_instance_rotate_ray(shi->obi, &is);
-
- if (RE_rayobject_raycast(R.raytree, &is)) {
- RE_instance_rotate_ray_restore(shi->obi, &is);
-
- visibility = 0.f;
- }
-
- lar->last_hit[shi->thread] = is.last_hit;
- }
- return visibility;
-}
-
-static int vol_get_bounds(ShadeInput *shi, const float co[3], const float vec[3], float hitco[3], Isect *isect, int intersect_type)
-{
-
- copy_v3_v3(isect->start, co);
- copy_v3_v3(isect->dir, vec);
- isect->dist = FLT_MAX;
- isect->mode = RE_RAY_MIRROR;
- isect->last_hit = NULL;
- isect->lay = -1;
- isect->check = RE_CHECK_VLR_NONE;
-
- if (intersect_type == VOL_BOUNDS_DEPTH) {
- isect->skip = RE_SKIP_VLR_NEIGHBOUR;
- isect->orig.face = (void *)shi->vlr;
- isect->orig.ob = (void *)shi->obi;
- }
- else { // if (intersect_type == VOL_BOUNDS_SS) {
- isect->skip = 0;
- isect->orig.face = NULL;
- isect->orig.ob = NULL;
- }
-
- RE_instance_rotate_ray(shi->obi, isect);
-
- if (RE_rayobject_raycast(R.raytree, isect)) {
- RE_instance_rotate_ray_restore(shi->obi, isect);
-
- hitco[0] = isect->start[0] + isect->dist * isect->dir[0];
- hitco[1] = isect->start[1] + isect->dist * isect->dir[1];
- hitco[2] = isect->start[2] + isect->dist * isect->dir[2];
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void shade_intersection(ShadeInput *shi, float col_r[4], Isect *is)
-{
- ShadeInput shi_new;
- ShadeResult shr_new;
-
- memset(&shi_new, 0, sizeof(ShadeInput));
-
- shi_new.mask = shi->mask;
- shi_new.osatex = shi->osatex;
- shi_new.thread = shi->thread;
- shi_new.depth = shi->depth + 1;
- shi_new.volume_depth = shi->volume_depth + 1;
- shi_new.xs = shi->xs;
- shi_new.ys = shi->ys;
- shi_new.lay = shi->lay;
- shi_new.passflag = SCE_PASS_COMBINED; /* result of tracing needs no pass info */
- shi_new.combinedflag = 0xFFFFFF; /* ray trace does all options */
-
- copy_v3_v3(shi_new.camera_co, is->start);
-
- memset(&shr_new, 0, sizeof(ShadeResult));
-
- /* hardcoded limit of 100 for now - prevents problems in weird geometry */
- if (shi->volume_depth < 100) {
- shade_ray(is, &shi_new, &shr_new);
- }
-
- copy_v3_v3(col_r, shr_new.combined);
- col_r[3] = shr_new.alpha;
-}
-
-static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, const float co[3], float col_r[4])
-{
- Isect isect;
-
- copy_v3_v3(isect.start, co);
- copy_v3_v3(isect.dir, shi->view);
- isect.dist = FLT_MAX;
-
- isect.mode = RE_RAY_MIRROR;
- isect.check = RE_CHECK_VLR_NONE;
- isect.skip = RE_SKIP_VLR_NEIGHBOUR;
- isect.orig.ob = (void *) shi->obi;
- isect.orig.face = (void *)vlr;
- isect.last_hit = NULL;
- isect.lay = -1;
-
- /* check to see if there's anything behind the volume, otherwise shade the sky */
- RE_instance_rotate_ray(shi->obi, &isect);
-
- if (RE_rayobject_raycast(R.raytree, &isect)) {
- RE_instance_rotate_ray_restore(shi->obi, &isect);
-
- shade_intersection(shi, col_r, &isect);
- }
- else {
- shadeSkyView(col_r, co, shi->view, NULL, shi->thread);
- shadeSunView(col_r, shi->view);
- }
-}
-
-
-/* trilinear interpolation */
-static void vol_get_precached_scattering(Render *re, ShadeInput *shi, float scatter_col[3], const float co[3])
-{
- VolumePrecache *vp = shi->obi->volume_precache;
- float bbmin[3], bbmax[3], dim[3];
- float world_co[3], sample_co[3];
-
- if (!vp) return;
-
- /* find sample point in global space bounding box 0.0-1.0 */
- global_bounds_obi(re, shi->obi, bbmin, bbmax);
- sub_v3_v3v3(dim, bbmax, bbmin);
- mul_v3_m4v3(world_co, re->viewinv, co);
-
- /* sample_co in 0.0-1.0 */
- sample_co[0] = (world_co[0] - bbmin[0]) / dim[0];
- sample_co[1] = (world_co[1] - bbmin[1]) / dim[1];
- sample_co[2] = (world_co[2] - bbmin[2]) / dim[2];
-
- scatter_col[0] = BLI_voxel_sample_triquadratic(vp->data_r, vp->res, sample_co);
- scatter_col[1] = BLI_voxel_sample_triquadratic(vp->data_g, vp->res, sample_co);
- scatter_col[2] = BLI_voxel_sample_triquadratic(vp->data_b, vp->res, sample_co);
-}
-
-/* Meta object density, brute force for now
- * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
-static float metadensity(Object *ob, const float co[3])
-{
- float mat[4][4], imat[4][4], dens = 0.f;
- MetaBall *mb = (MetaBall *)ob->data;
- MetaElem *ml;
-
- /* transform co to meta-element */
- float tco[3] = {co[0], co[1], co[2]};
- mul_m4_m4m4(mat, R.viewmat, ob->obmat);
- invert_m4_m4(imat, mat);
- mul_m4_v3(imat, tco);
-
- for (ml = mb->elems.first; ml; ml = ml->next) {
- float bmat[3][3], dist2;
-
- /* element rotation transform */
- float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
- quat_to_mat3(bmat, ml->quat);
- transpose_m3(bmat); /* rot.only, so inverse == transpose */
- mul_m3_v3(bmat, tp);
-
- /* MB_BALL default */
- switch (ml->type) {
- case MB_ELIPSOID:
- tp[0] /= ml->expx;
- tp[1] /= ml->expy;
- tp[2] /= ml->expz;
- break;
- case MB_CUBE:
- tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
- /* no break, xy as plane */
- ATTR_FALLTHROUGH;
- case MB_PLANE:
- tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
- /* no break, x as tube */
- ATTR_FALLTHROUGH;
- case MB_TUBE:
- tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
- }
-
- /* ml->rad2 is not set */
- dist2 = 1.0f - (dot_v3v3(tp, tp) / (ml->rad * ml->rad));
- if (dist2 > 0.f)
- dens += (ml->flag & MB_NEGATIVE) ? -ml->s * dist2 * dist2 * dist2 : ml->s * dist2 * dist2 * dist2;
- }
-
- dens -= mb->thresh;
- return (dens < 0.f) ? 0.f : dens;
-}
-
-float vol_get_density(struct ShadeInput *shi, const float co[3])
-{
- float density = shi->mat->vol.density;
- float density_scale = shi->mat->vol.density_scale;
-
- if (shi->mat->mapto_textured & MAP_DENSITY)
- do_volume_tex(shi, co, MAP_DENSITY, NULL, &density, &R);
-
- /* if meta-object, modulate by metadensity without increasing it */
- if (shi->obi->obr->ob->type == OB_MBALL) {
- const float md = metadensity(shi->obi->obr->ob, co);
- if (md < 1.f) density *= md;
- }
-
- return density * density_scale;
-}
-
-
-/* Color of light that gets scattered out by the volume */
-/* Uses same physically based scattering parameter as in transmission calculations,
- * along with artificial reflection scale/reflection color tint */
-static void vol_get_reflection_color(ShadeInput *shi, float ref_col[3], const float co[3])
-{
- float scatter = shi->mat->vol.scattering;
- float reflection = shi->mat->vol.reflection;
- copy_v3_v3(ref_col, shi->mat->vol.reflection_col);
-
- if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_REFLECTION_COL))
- do_volume_tex(shi, co, MAP_SCATTERING + MAP_REFLECTION_COL, ref_col, &scatter, &R);
-
- /* only one single float parameter at a time... :s */
- if (shi->mat->mapto_textured & (MAP_REFLECTION))
- do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection, &R);
-
- ref_col[0] = reflection * ref_col[0] * scatter;
- ref_col[1] = reflection * ref_col[1] * scatter;
- ref_col[2] = reflection * ref_col[2] * scatter;
-}
-
-/* compute emission component, amount of radiance to add per segment
- * can be textured with 'emit' */
-static void vol_get_emission(ShadeInput *shi, float emission_col[3], const float co[3])
-{
- float emission = shi->mat->vol.emission;
- copy_v3_v3(emission_col, shi->mat->vol.emission_col);
-
- if (shi->mat->mapto_textured & (MAP_EMISSION + MAP_EMISSION_COL))
- do_volume_tex(shi, co, MAP_EMISSION + MAP_EMISSION_COL, emission_col, &emission, &R);
-
- emission_col[0] = emission_col[0] * emission;
- emission_col[1] = emission_col[1] * emission;
- emission_col[2] = emission_col[2] * emission;
-}
-
-
-/* A combination of scattering and absorption -> known as sigma T.
- * This can possibly use a specific scattering color,
- * and absorption multiplier factor too, but these parameters are left out for simplicity.
- * It's easy enough to get a good wide range of results with just these two parameters. */
-static void vol_get_sigma_t(ShadeInput *shi, float sigma_t[3], const float co[3])
-{
- /* technically absorption, but named transmission color
- * since it describes the effect of the coloring *after* absorption */
- float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]};
- float scattering = shi->mat->vol.scattering;
-
- if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_TRANSMISSION_COL))
- do_volume_tex(shi, co, MAP_SCATTERING + MAP_TRANSMISSION_COL, transmission_col, &scattering, &R);
-
- sigma_t[0] = (1.0f - transmission_col[0]) + scattering;
- sigma_t[1] = (1.0f - transmission_col[1]) + scattering;
- sigma_t[2] = (1.0f - transmission_col[2]) + scattering;
-}
-
-/* phase function - determines in which directions the light
- * is scattered in the volume relative to incoming direction
- * and view direction */
-static float vol_get_phasefunc(ShadeInput *UNUSED(shi), float g, const float w[3], const float wp[3])
-{
- const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI)
-
- /* normalization constant is 1/4 rather than 1/4pi, since
- * Blender's shading system doesn't normalize for
- * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ).
- * This means that lambert surfaces in Blender are pi times brighter than they 'should be'
- * and therefore, with correct energy conservation, volumes will darker than other solid objects,
- * for the same lighting intensity.
- * To correct this, scale up the phase function values by pi
- * until Blender's shading system supports this better. --matt
- */
-
- if (g == 0.f) { /* isotropic */
- return normalize * 1.f;
- }
- else { /* schlick */
- const float k = 1.55f * g - 0.55f * g * g * g;
- const float kcostheta = k * dot_v3v3(w, wp);
- return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
- }
-
- /* not used, but here for reference: */
-#if 0
- switch (phasefunc_type) {
- case MA_VOL_PH_MIEHAZY:
- return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f));
- case MA_VOL_PH_MIEMURKY:
- return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f));
- case MA_VOL_PH_RAYLEIGH:
- return normalize * 3.f / 4.f * (1 + costheta * costheta);
- case MA_VOL_PH_HG:
- return normalize * (1.f - g * g) / powf(1.f + g * g - 2.f * g * costheta, 1.5f);
- case MA_VOL_PH_SCHLICK:
- {
- const float k = 1.55f * g - 0.55f * g * g * g;
- const float kcostheta = k * costheta;
- return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
- }
- case MA_VOL_PH_ISOTROPIC:
- default:
- return normalize * 1.f;
- }
-#endif
-}
-
-/* Compute transmittance = e^(-attenuation) */
-static void vol_get_transmittance_seg(ShadeInput *shi, float tr[3], float stepsize, const float co[3], float density)
-{
- /* input density = density at co */
- float tau[3] = {0.f, 0.f, 0.f};
- const float stepd = density * stepsize;
- float sigma_t[3];
-
- vol_get_sigma_t(shi, sigma_t, co);
-
- /* homogeneous volume within the sampled distance */
- tau[0] += stepd * sigma_t[0];
- tau[1] += stepd * sigma_t[1];
- tau[2] += stepd * sigma_t[2];
-
- tr[0] *= expf(-tau[0]);
- tr[1] *= expf(-tau[1]);
- tr[2] *= expf(-tau[2]);
-}
-
-/* Compute transmittance = e^(-attenuation) */
-static void vol_get_transmittance(ShadeInput *shi, float tr[3], const float co[3], const float endco[3])
-{
- float p[3] = {co[0], co[1], co[2]};
- float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
- float tau[3] = {0.f, 0.f, 0.f};
-
- float t0 = 0.f;
- float t1 = normalize_v3(step_vec);
- float pt0 = t0;
-
- t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
- p[0] += t0 * step_vec[0];
- p[1] += t0 * step_vec[1];
- p[2] += t0 * step_vec[2];
- mul_v3_fl(step_vec, shi->mat->vol.stepsize);
-
- for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) {
- const float d = vol_get_density(shi, p);
- const float stepd = (t0 - pt0) * d;
- float sigma_t[3];
-
- vol_get_sigma_t(shi, sigma_t, p);
-
- tau[0] += stepd * sigma_t[0];
- tau[1] += stepd * sigma_t[1];
- tau[2] += stepd * sigma_t[2];
-
- add_v3_v3(p, step_vec);
- }
-
- /* return transmittance */
- tr[0] = expf(-tau[0]);
- tr[1] = expf(-tau[1]);
- tr[2] = expf(-tau[2]);
-}
-
-static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3])
-{
- float visifac, lv[3], lampdist;
- float tr[3] = {1.0, 1.0, 1.0};
- float hitco[3], *atten_co;
- float p, ref_col[3];
-
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return;
- if ((lar->lay & shi->lay) == 0) return;
- if (lar->energy == 0.0f) return;
-
- if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
-
- copy_v3_v3(lacol, &lar->r);
-
- if (lar->mode & LA_TEXTURE) {
- shi->osatex = 0;
- do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
- }
-
- mul_v3_fl(lacol, visifac);
-
- if (ELEM(lar->type, LA_SUN, LA_HEMI))
- copy_v3_v3(lv, lar->vec);
- negate_v3(lv);
-
- if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
- mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- }
- else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
- Isect is;
-
- if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
- mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
- }
-
- /* find minimum of volume bounds, or lamp coord */
- if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
- float dist = len_v3v3(co, hitco);
- VlakRen *vlr = (VlakRen *)is.hit.face;
-
- /* simple internal shadowing */
- if (vlr->mat->material_type == MA_TYPE_SURFACE) {
- lacol[0] = lacol[1] = lacol[2] = 0.0f;
- return;
- }
-
- if (ELEM(lar->type, LA_SUN, LA_HEMI))
- /* infinite lights, can never be inside volume */
- atten_co = hitco;
- else if (lampdist < dist) {
- atten_co = lar->co;
- }
- else
- atten_co = hitco;
-
- vol_get_transmittance(shi, tr, co, atten_co);
-
- mul_v3_v3v3(lacol, lacol, tr);
- }
- else {
- /* Point is on the outside edge of the volume,
- * therefore no attenuation, full transmission.
- * Radiance from lamp remains unchanged */
- }
- }
-
- if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
-
- normalize_v3(lv);
- p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
-
- /* physically based scattering with non-physically based RGB gain */
- vol_get_reflection_color(shi, ref_col, co);
-
- lacol[0] *= p * ref_col[0];
- lacol[1] *= p * ref_col[1];
- lacol[2] *= p * ref_col[2];
-}
-
-/* single scattering only for now */
-void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3])
-{
- ListBase *lights;
- GroupObject *go;
- LampRen *lar;
-
- zero_v3(scatter_col);
-
- lights = get_lights(shi);
- for (go = lights->first; go; go = go->next) {
- float lacol[3] = {0.f, 0.f, 0.f};
- lar = go->lampren;
-
- if (lar) {
- vol_shade_one_lamp(shi, co, view, lar, lacol);
- add_v3_v3(scatter_col, lacol);
- }
- }
-}
-
-
-/*
- * The main volumetric integrator, using an emission/absorption/scattering model.
- *
- * Incoming radiance =
- *
- * outgoing radiance from behind surface * beam transmittance/attenuation
- * + added radiance from all points along the ray due to participating media
- * --> radiance for each segment =
- * (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
- */
-
-/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't
- * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light
- * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
- * it also makes it harder to control the overall look of the volume since coloring the outscattered light results
- * in the inverse color being transmitted through the rest of the volume.
- */
-static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3])
-{
- float radiance[3] = {0.f, 0.f, 0.f};
- float tr[3] = {1.f, 1.f, 1.f};
- float p[3] = {co[0], co[1], co[2]};
- float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
- const float stepsize = shi->mat->vol.stepsize;
-
- float t0 = 0.f;
- float pt0 = t0;
- float t1 = normalize_v3(step_vec); /* returns vector length */
-
- t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
- p[0] += t0 * step_vec[0];
- p[1] += t0 * step_vec[1];
- p[2] += t0 * step_vec[2];
- mul_v3_fl(step_vec, stepsize);
-
- for (; t0 < t1; pt0 = t0, t0 += stepsize) {
- const float density = vol_get_density(shi, p);
-
- if (density > 0.00001f) {
- float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
- const float stepd = (t0 - pt0) * density;
-
- /* transmittance component (alpha) */
- vol_get_transmittance_seg(shi, tr, stepsize, co, density);
-
- if (t0 > t1 * 0.25f) {
- /* only use depth cutoff after we've traced a little way into the volume */
- if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
- }
-
- vol_get_emission(shi, emit_col, p);
-
- if (shi->obi->volume_precache) {
- float p2[3];
-
- p2[0] = p[0] + (step_vec[0] * 0.5f);
- p2[1] = p[1] + (step_vec[1] * 0.5f);
- p2[2] = p[2] + (step_vec[2] * 0.5f);
-
- vol_get_precached_scattering(&R, shi, scatter_col, p2);
- }
- else
- vol_get_scattering(shi, scatter_col, p, shi->view);
-
- radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
- radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
- radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
- }
- add_v3_v3(p, step_vec);
- }
-
- /* multiply original color (from behind volume) with transmittance over entire distance */
- mul_v3_v3v3(col, tr, col);
- add_v3_v3(col, radiance);
-
- /* alpha <-- transmission luminance */
- col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
-}
-
-/* the main entry point for volume shading */
-static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
-{
- float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f};
- const float *startco, *endco;
- int trace_behind = 1;
- const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
- Isect is;
-
- /* check for shading an internal face a volume object directly */
- if (inside_volume == VOL_SHADE_INSIDE)
- trace_behind = 0;
- else if (inside_volume == VOL_SHADE_OUTSIDE) {
- if (shi->flippednor)
- inside_volume = VOL_SHADE_INSIDE;
- }
-
- if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
- MatInside *mi;
- int render_this = 0;
-
- /* don't render the backfaces of ztransp volume materials.
- *
- * volume shading renders the internal volume from between the
- * ' view intersection of the solid volume to the
- * intersection on the other side, as part of the shading of
- * the front face.
- *
- * Because ztransp renders both front and back faces independently
- * this will double up, so here we prevent rendering the backface as well,
- * which would otherwise render the volume in between the camera and the backface
- * --matt */
-
- for (mi = R.render_volumes_inside.first; mi; mi = mi->next) {
- /* weak... */
- if (mi->ma == shi->mat) render_this = 1;
- }
- if (!render_this) return;
- }
-
-
- if (inside_volume == VOL_SHADE_INSIDE) {
- startco = shi->camera_co;
- endco = shi->co;
-
- if (trace_behind) {
- if (!ztransp)
- /* trace behind the volume object */
- vol_trace_behind(shi, shi->vlr, endco, col);
- }
- else {
- /* we're tracing through the volume between the camera
- * and a solid surface, so use that pre-shaded radiance */
- copy_v4_v4(col, shr->combined);
- }
-
- /* shade volume from 'camera' to 1st hit point */
- volumeintegrate(shi, col, startco, endco);
- }
- /* trace to find a backface, the other side bounds of the volume */
- /* (ray intersect ignores front faces here) */
- else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
- VlakRen *vlr = (VlakRen *)is.hit.face;
-
- startco = shi->co;
- endco = hitco;
-
- if (!ztransp) {
- /* if it's another face in the same material */
- if (vlr->mat == shi->mat) {
- /* trace behind the 2nd (raytrace) hit point */
- vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
- }
- else {
- shade_intersection(shi, col, &is);
- }
- }
-
- /* shade volume from 1st hit point to 2nd hit point */
- volumeintegrate(shi, col, startco, endco);
- }
-
- if (ztransp)
- col[3] = col[3] > 1.f ? 1.f : col[3];
- else
- col[3] = 1.f;
-
- copy_v3_v3(shr->combined, col);
- shr->alpha = col[3];
-
- copy_v3_v3(shr->diff, shr->combined);
- copy_v3_v3(shr->diffshad, shr->diff);
-}
-
-/* Traces a shadow through the object,
- * pretty much gets the transmission over a ray path */
-void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
-{
- float hitco[3];
- float tr[3] = {1.0, 1.0, 1.0};
- Isect is = {{0}};
- const float *startco, *endco;
-
- memset(shr, 0, sizeof(ShadeResult));
-
- /* if 1st hit normal is facing away from the camera,
- * then we're inside the volume already. */
- if (shi->flippednor) {
- startco = last_is->start;
- endco = shi->co;
- }
-
- /* trace to find a backface, the other side bounds of the volume */
- /* (ray intersect ignores front faces here) */
- else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
- startco = shi->co;
- endco = hitco;
- }
- else {
- shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
- shr->alpha = shr->combined[3] = 1.f;
- return;
- }
-
- vol_get_transmittance(shi, tr, startco, endco);
-
-
- /* if we hit another face in the same volume bounds */
- /* shift raytrace coordinates to the hit point, to avoid shading volume twice */
- /* due to idiosyncracy in ray_trace_shadow_tra() */
- if (is.hit.ob == shi->obi) {
- copy_v3_v3(shi->co, hitco);
- last_is->dist += is.dist;
- shi->vlr = (VlakRen *)is.hit.face;
- }
-
-
- copy_v3_v3(shr->combined, tr);
- shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
- shr->alpha = shr->combined[3];
-}
-
-
-/* delivers a fully filled in ShadeResult, for all passes */
-void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
-{
- memset(shr, 0, sizeof(ShadeResult));
- volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
-}
-
-
-void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
-{
- MatInside *m;
- Material *mat_backup;
- ObjectInstanceRen *obi_backup;
- float prev_alpha = shr->alpha;
-
- /* XXX: extend to multiple volumes perhaps later */
- mat_backup = shi->mat;
- obi_backup = shi->obi;
-
- m = R.render_volumes_inside.first;
- shi->mat = m->ma;
- shi->obi = m->obi;
- shi->obr = m->obi->obr;
-
- volume_trace(shi, shr, VOL_SHADE_INSIDE);
-
- shr->alpha = shr->alpha + prev_alpha;
- CLAMP(shr->alpha, 0.0f, 1.0f);
-
- shi->mat = mat_backup;
- shi->obi = obi_backup;
- shi->obr = obi_backup->obr;
-}
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
deleted file mode 100644
index c45bde300e7..00000000000
--- a/source/blender/render/intern/source/voxeldata.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * ***** 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.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/voxeldata.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef WIN32
-#include "BLI_winstuff.h"
-#endif
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_threads.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_cloth.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_modifier.h"
-
-#include "smoke_API.h"
-#include "BPH_mass_spring.h"
-
-#include "DNA_texture_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_smoke_types.h"
-
-
-#include "render_types.h"
-#include "texture.h"
-#include "voxeldata.h"
-
-static bool is_vd_res_ok(VoxelData *vd)
-{
- /* arbitrary large value so corrupt headers don't break */
- const int min = 1, max = 100000;
- return (vd->resol[0] >= min && vd->resol[0] <= max) &&
- (vd->resol[1] >= min && vd->resol[1] <= max) &&
- (vd->resol[2] >= min && vd->resol[2] <= max);
-}
-
-/* use size_t because the result may exceed INT_MAX */
-static size_t vd_resol_size(VoxelData *vd)
-{
- return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2];
-}
-
-static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame)
-{
- const size_t size = vd_resol_size(vd);
- size_t offset = sizeof(VoxelDataHeader);
-
- if (is_vd_res_ok(vd) == false)
- return 0;
-
- vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
- if (vd->dataset == NULL) return 0;
-
- if (fseek(fp, frame * size * sizeof(float) + offset, 0) == -1)
- return 0;
- if (fread(vd->dataset, sizeof(float), size, fp) != size)
- return 0;
-
- vd->cachedframe = frame;
- vd->ok = 1;
- return 1;
-}
-
-static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
-{
- const size_t size = vd_resol_size(vd);
- size_t i;
- char *data_c;
-
- if (is_vd_res_ok(vd) == false)
- return 0;
-
- vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
- if (vd->dataset == NULL) return 0;
- data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage");
- if (data_c == NULL) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
-
- if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) {
- MEM_freeN(data_c);
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
- if (fread(data_c, sizeof(char), size, fp) != size) {
- MEM_freeN(data_c);
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
-
- for (i = 0; i < size; i++) {
- vd->dataset[i] = (float)data_c[i] / 255.f;
- }
- MEM_freeN(data_c);
-
- vd->cachedframe = frame;
- vd->ok = 1;
- return 1;
-}
-
-static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
-{
- ImBuf *ibuf;
- Image *ima = tex->ima;
- ImageUser *tiuser = &tex->iuser;
- ImageUser iuser = *(tiuser);
- int x = 0, y = 0, z = 0;
- const float *rf;
-
- if (!ima) return;
- if (iuser.frames == 0) return;
-
- ima->source = IMA_SRC_SEQUENCE;
- iuser.framenr = 1 + iuser.offset;
-
- /* find the first valid ibuf and use it to initialize the resolution of the data set */
- /* need to do this in advance so we know how much memory to allocate */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- while (!ibuf && (iuser.framenr < iuser.frames)) {
- iuser.framenr++;
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- }
- if (!ibuf) return;
- if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
-
- vd->flag |= TEX_VD_STILL;
- vd->resol[0] = ibuf->x;
- vd->resol[1] = ibuf->y;
- vd->resol[2] = iuser.frames;
- vd->dataset = MEM_mapallocN(sizeof(float) * vd_resol_size(vd), "voxel dataset");
-
- for (z = 0; z < iuser.frames; z++) {
- /* get a new ibuf for each frame */
- if (z > 0) {
- iuser.framenr++;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (!ibuf) break;
- if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
- }
- rf = ibuf->rect_float;
-
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- /* currently averaged to monchrome */
- vd->dataset[BLI_VOXEL_INDEX(x, y, z, vd->resol)] = (rf[0] + rf[1] + rf[2]) / 3.0f;
- rf += 4;
- }
- }
-
- BKE_image_free_anim_ibufs(ima, iuser.framenr);
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- vd->ok = 1;
- return;
-}
-
-static int read_voxeldata_header(FILE *fp, struct VoxelData *vd)
-{
- VoxelDataHeader *h = (VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
-
- rewind(fp);
- if (fread(h, sizeof(VoxelDataHeader), 1, fp) != 1) {
- MEM_freeN(h);
- return 0;
- }
-
- vd->resol[0] = h->resolX;
- vd->resol[1] = h->resolY;
- vd->resol[2] = h->resolZ;
-
- MEM_freeN(h);
- return 1;
-}
-
-static void init_frame_smoke(VoxelData *vd, int cfra)
-{
-#ifdef WITH_SMOKE
- Object *ob;
- ModifierData *md;
-
- vd->dataset = NULL;
- if (vd->object == NULL) return;
- ob = vd->object;
-
- /* draw code for smoke */
- if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
-
- if (sds && sds->fluid) {
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (!sds->fluid) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
-
- if (cfra < sds->point_cache[0]->startframe)
- ; /* don't show smoke before simulation starts, this could be made an option in the future */
- else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
- size_t totRes;
- size_t i;
- float *heat;
-
- if (!smoke_has_heat(sds->fluid)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
-
- copy_v3_v3_int(vd->resol, sds->res);
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
- /* get heat data */
- heat = smoke_get_heat(sds->fluid);
-
- /* scale heat values from -2.0-2.0 to 0.0-1.0 */
- for (i = 0; i < totRes; i++) {
- vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
- }
- }
- else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
- size_t totRes;
- size_t i;
- float *xvel, *yvel, *zvel;
-
- copy_v3_v3_int(vd->resol, sds->res);
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
- /* get velocity data */
- xvel = smoke_get_velocity_x(sds->fluid);
- yvel = smoke_get_velocity_y(sds->fluid);
- zvel = smoke_get_velocity_z(sds->fluid);
-
- /* map velocities between 0 and 0.3f */
- for (i = 0; i < totRes; i++) {
- vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
- }
-
- }
- else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
- size_t totRes;
- float *flame;
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (!smoke_turbulence_has_fuel(sds->wt)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
- smoke_turbulence_get_res(sds->wt, vd->resol);
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- if (!smoke_has_fuel(sds->fluid)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
- copy_v3_v3_int(vd->resol, sds->res);
- flame = smoke_get_flame(sds->fluid);
- }
-
- /* always store copy, as smoke internal data can change */
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
- memcpy(vd->dataset, flame, sizeof(float)*totRes);
- }
- else {
- size_t totCells;
- int depth = 4;
- vd->data_type = TEX_VD_RGBA_PREMUL;
-
- /* data resolution */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_get_res(sds->wt, vd->resol);
- }
- else {
- copy_v3_v3_int(vd->resol, sds->res);
- }
-
- /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
- totCells = vd_resol_size(vd) * depth;
- /* always store copy, as smoke internal data can change */
- vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (smoke_turbulence_has_colors(sds->wt)) {
- smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
- }
- else {
- smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
- }
- }
- else {
- if (smoke_has_colors(sds->fluid)) {
- smoke_get_rgba(sds->fluid, vd->dataset, 1);
- }
- else {
- smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
- }
- }
- } /* end of fluid condition */
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- }
- }
-
- vd->ok = 1;
-
-#else // WITH_SMOKE
- (void)vd;
- (void)cfra;
-
- vd->dataset = NULL;
-#endif
-}
-
-static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
-{
- Object *ob;
- ModifierData *md;
-
- vd->dataset = NULL;
- if (vd->object == NULL) return;
- ob = vd->object;
-
- if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
- ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
-
- if (pmd->psys && pmd->psys->clmd) {
- vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
- }
- }
-}
-
-void cache_voxeldata(Tex *tex, int scene_frame)
-{
- VoxelData *vd = tex->vd;
- FILE *fp;
- int curframe;
- char path[sizeof(vd->source_path)];
-
- /* only re-cache if dataset needs updating */
- if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == scene_frame))
- if (vd->ok) return;
-
- /* clear out old cache, ready for new */
- if (vd->dataset) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- }
- /* reset data_type */
- vd->data_type = TEX_VD_INTENSITY;
-
- if (vd->flag & TEX_VD_STILL)
- curframe = vd->still_frame;
- else
- curframe = scene_frame;
-
- BLI_strncpy(path, vd->source_path, sizeof(path));
-
- /* each type is responsible for setting to true */
- vd->ok = false;
-
- switch (vd->file_format) {
- case TEX_VD_IMAGE_SEQUENCE:
- load_frame_image_sequence(vd, tex);
- return;
- case TEX_VD_SMOKE:
- init_frame_smoke(vd, scene_frame);
- return;
- case TEX_VD_HAIR:
- init_frame_hair(vd, scene_frame);
- return;
- case TEX_VD_BLENDERVOXEL:
- BLI_path_abs(path, G.main->name);
- fp = BLI_fopen(path, "rb");
- if (!fp) return;
-
- if (read_voxeldata_header(fp, vd))
- load_frame_blendervoxel(vd, fp, curframe - 1);
-
- fclose(fp);
- return;
- case TEX_VD_RAW_8BIT:
- BLI_path_abs(path, G.main->name);
- fp = BLI_fopen(path, "rb");
- if (!fp) return;
-
- load_frame_raw8(vd, fp, curframe);
- fclose(fp);
- return;
- }
-}
-
-void make_voxeldata(struct Render *re)
-{
- Tex *tex;
-
- re->i.infostr = IFACE_("Loading voxel datasets");
- re->stats_draw(re->sdh, &re->i);
-
- /* XXX: should be doing only textures used in this render */
- for (tex = re->main->tex.first; tex; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_VOXELDATA) {
- cache_voxeldata(tex, re->r.cfra);
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-
-}
-
-int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
-{
- VoxelData *vd = tex->vd;
- float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
- int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
- int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
- int ch;
-
- if (vd->dataset == NULL) {
- texres->tin = 0.0f;
- return 0;
- }
-
- /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
- /* in implementation this works backwards, bringing sample locations from -1.0, 1.0
- * to the range 0.0, 1.0, before looking up in the voxel structure. */
- copy_v3_v3(co, texvec);
- mul_v3_fl(co, 0.5f);
- add_v3_v3(co, offset);
-
- /* co is now in the range 0.0, 1.0 */
- switch (vd->extend) {
- case TEX_CLIP:
- {
- if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
- texres->tin = 0.f;
- return retval;
- }
- break;
- }
- case TEX_REPEAT:
- {
- co[0] = co[0] - floorf(co[0]);
- co[1] = co[1] - floorf(co[1]);
- co[2] = co[2] - floorf(co[2]);
- break;
- }
- case TEX_EXTEND:
- {
- CLAMP(co[0], 0.f, 1.f);
- CLAMP(co[1], 0.f, 1.f);
- CLAMP(co[2], 0.f, 1.f);
- break;
- }
- }
-
- for (ch = 0; ch < depth; ch++) {
- float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
- float *result = &texres->tin;
-
- if (vd->data_type == TEX_VD_RGBA_PREMUL) {
- switch (ch) {
- case 0:
- result = &texres->tr;
- break;
- case 1:
- result = &texres->tg;
- break;
- case 2:
- result = &texres->tb;
- break;
- }
- }
-
- switch (vd->interp_type) {
- case TEX_VD_NEARESTNEIGHBOR:
- *result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
- break;
- case TEX_VD_LINEAR:
- *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
- break;
- case TEX_VD_QUADRATIC:
- *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
- break;
- case TEX_VD_TRICUBIC_CATROM:
- case TEX_VD_TRICUBIC_BSPLINE:
- *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
- break;
- }
- }
-
- a = texres->tin;
- texres->tin *= vd->int_multiplier;
- BRICONT;
-
- if (vd->data_type == TEX_VD_RGBA_PREMUL) {
- /* unmultiply */
- if (a>0.001f) {
- texres->tr /= a;
- texres->tg /= a;
- texres->tb /= a;
- }
- texres->talpha = 1;
- }
- else {
- texres->tr = texres->tin;
- texres->tg = texres->tin;
- texres->tb = texres->tin;
- }
-
- texres->ta = texres->tin;
- BRICONTRGB;
-
- return retval;
-}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index e948662df00..3837383c4c7 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -34,40 +34,11 @@
/* Common includes */
/*---------------------------------------------------------------------------*/
-#include <math.h>
-#include <float.h>
-#include <stdlib.h>
-#include <limits.h>
#include <string.h>
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
#include "MEM_guardedalloc.h"
-#include "DNA_lamp_types.h"
-#include "DNA_node_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_material_types.h"
-
-#include "BKE_global.h"
-#include "BKE_material.h"
-
-
-#include "RE_render_ext.h"
-
-/* local includes */
-#include "pixelblending.h"
-#include "render_result.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "strand.h"
+#include "BLI_math_base.h"
/* own includes */
#include "zbuf.h"
@@ -77,17 +48,10 @@
# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
/* ****************** Spans ******************************* */
/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
-void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop)
+void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
@@ -96,8 +60,6 @@ void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop)
zspan->span1= MEM_mallocN(recty*sizeof(float), "zspan");
zspan->span2= MEM_mallocN(recty*sizeof(float), "zspan");
-
- zspan->clipcrop= clipcrop;
}
void zbuf_free_span(ZSpan *zspan)
@@ -200,1312 +162,6 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-void fillrect(int *rect, int x, int y, int val)
-{
- int len, *drect;
-
- len= x*y;
- drect= rect;
- while (len>0) {
- len--;
- *drect= val;
- drect++;
- }
-}
-
-/* based on Liang&Barsky, for clipping of pyramidical volume */
-static short cliptestf(float a, float b, float c, float d, float *u1, float *u2)
-{
- float p= a + b, q= c + d, r;
-
- if (p<0.0f) {
- if (q<p) return 0;
- else if (q<0.0f) {
- r= q/p;
- if (r>*u2) return 0;
- else if (r>*u1) *u1=r;
- }
- }
- else {
- if (p>0.0f) {
- if (q<0.0f) return 0;
- else if (q<p) {
- r= q/p;
- if (r<*u1) return 0;
- else if (r<*u2) *u2=r;
- }
- }
- else if (q<0.0f) return 0;
- }
- return 1;
-}
-
-int testclip(const float v[4])
-{
- float abs4; /* WATCH IT: this function should do the same as cliptestf, otherwise troubles in zbufclip()*/
- short c=0;
-
- /* if we set clip flags, the clipping should be at least larger than epsilon.
- * prevents issues with vertices lying exact on borders */
- abs4= fabsf(v[3]) + FLT_EPSILON;
-
- if ( v[0] < -abs4) c+=1;
- else if ( v[0] > abs4) c+=2;
-
- if ( v[1] > abs4) c+=4;
- else if ( v[1] < -abs4) c+=8;
-
- if (v[2] < -abs4) c+=16; /* this used to be " if (v[2]<0) ", see clippz() */
- else if (v[2]> abs4) c+= 32;
-
- return c;
-}
-
-
-
-/* ************* ACCUMULATION ZBUF ************ */
-
-
-static APixstr *addpsmainA(ListBase *lb)
-{
- APixstrMain *psm;
-
- psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
- BLI_addtail(lb, psm);
- psm->ps= MEM_callocN(4096*sizeof(APixstr), "pixstr");
-
- return psm->ps;
-}
-
-void freepsA(ListBase *lb)
-{
- APixstrMain *psm, *psmnext;
-
- for (psm= lb->first; psm; psm= psmnext) {
- psmnext= psm->next;
- if (psm->ps)
- MEM_freeN(psm->ps);
- MEM_freeN(psm);
- }
-}
-
-static APixstr *addpsA(ZSpan *zspan)
-{
- /* make new PS */
- if (zspan->apsmcounter==0) {
- zspan->curpstr= addpsmainA(zspan->apsmbase);
- zspan->apsmcounter= 4095;
- }
- else {
- zspan->curpstr++;
- zspan->apsmcounter--;
- }
- return zspan->curpstr;
-}
-
-static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- APixstr *ap, *apofs, *apn;
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rz, *rm, x, y;
- int sn1, sn2, rectx, *rectzofs, *rectmaskofs, my0, my2, mask;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (int *)(zspan->arectz+rectx*(my2));
- rectmaskofs= (int *)(zspan->rectmask+rectx*(my2));
- apofs= (zspan->apixbuf+ rectx*(my2));
- mask= zspan->mask;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rm= rectmaskofs+sn1;
- ap= apofs+sn1;
- x= sn2-sn1;
-
- zverg-= zspan->polygon_offset;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if ( intzverg < *rz) {
- if (!zspan->rectmask || intzverg > *rm) {
-
- apn= ap;
- while (apn) {
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= intzverg; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr && apn->obi[0]==obi) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= intzverg; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr && apn->obi[1]==obi) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= intzverg; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr && apn->obi[2]==obi) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= intzverg; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr && apn->obi[3]==obi) {apn->mask[3]|= mask; break; }
- if (apn->next==NULL) apn->next= addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- zverg+= zxd;
- rz++;
- rm++;
- ap++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectmaskofs-= rectx;
- apofs-= rectx;
- }
-}
-
-
-
-static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, const float vec1[3], const float vec2[3])
-{
- APixstr *ap, *apn;
- const int *rectz, *rectmask;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, mask, maxtest=0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- mask= zspan->mask;
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= v1[2];
- vergz-= zspan->polygon_offset;
- dz= (v2[2]-v1[2])/dx;
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= (int *)(zspan->arectz+zspan->rectx*(oldy) +start);
- rectmask= (int *)(zspan->rectmask+zspan->rectx*(oldy) +start);
- ap= (zspan->apixbuf+ zspan->rectx*(oldy) +start);
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++, rectmask++, ap++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- rectmask+= ofs;
- ap+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
-
- apn= ap;
- while (apn) { /* loop unrolled */
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr && apn->obi[0]==obi) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr && apn->obi[1]==obi) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr && apn->obi[2]==obi) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr && apn->obi[3]==obi) {apn->mask[3]|= mask; break; }
- if (apn->next == NULL) apn->next = addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- }
-
- v1[1]+= dy;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
- else {
-
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (start>=zspan->recty || end<0) return;
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= v1[2];
- vergz-= zspan->polygon_offset;
- dz= (v2[2]-v1[2])/dy;
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= (int *)( zspan->arectz+ (start)*zspan->rectx+ oldx );
- rectmask= (int *)( zspan->rectmask+ (start)*zspan->rectx+ oldx );
- ap= (zspan->apixbuf+ zspan->rectx*(start) +oldx);
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx, rectmask+=zspan->rectx, ap+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- rectmask+= ofs;
- ap+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
-
- apn= ap;
- while (apn) { /* loop unrolled */
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; }
- if (apn->next == NULL) apn->next = addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
-}
-
-/* ************* NORMAL ZBUFFER ************ */
-
-static void zbufline(ZSpan *zspan, int obi, int zvlnr, const float vec1[3], const float vec2[3])
-{
- int *rectz, *rectp, *recto, *rectmask;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, maxtest= 0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dx);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + oldy*zspan->rectx+ start;
- rectp= zspan->rectp + oldy*zspan->rectx+ start;
- recto= zspan->recto + oldy*zspan->rectx+ start;
- rectmask= zspan->rectmask + oldy*zspan->rectx+ start;
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++, rectp++, recto++, rectmask++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- rectp+= ofs;
- recto+= ofs;
- rectmask+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
- *recto= obi;
- *rectz= vergz;
- *rectp= zvlnr;
- }
- }
- }
-
- v1[1]+= dy;
-
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
- else {
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dy);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + start*zspan->rectx+ oldx;
- rectp= zspan->rectp + start*zspan->rectx+ oldx;
- recto= zspan->recto + start*zspan->rectx+ oldx;
- rectmask= zspan->rectmask + start*zspan->rectx+ oldx;
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx, rectp+=zspan->rectx, recto+=zspan->rectx, rectmask+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- rectp+= ofs;
- recto+= ofs;
- rectmask+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
- *rectz= vergz;
- *rectp= zvlnr;
- *recto= obi;
- }
- }
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
-}
-
-static void zbufline_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr), const float vec1[3], const float vec2[3])
-{
- int *rectz, *rectz1= NULL;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, maxtest= 0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dx);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + oldy*zspan->rectx+ start;
- if (zspan->rectz1)
- rectz1= zspan->rectz1 + oldy*zspan->rectx+ start;
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- if (rectz1) rectz1+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz < *rectz) {
- if (rectz1) *rectz1= *rectz;
- *rectz= vergz;
- }
- else if (rectz1 && vergz < *rectz1)
- *rectz1= vergz;
- }
-
- v1[1]+= dy;
-
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
-
- if (rectz1) rectz1++;
- }
- }
- else {
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dy);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + start*zspan->rectx+ oldx;
- if (zspan->rectz1)
- rectz1= zspan->rectz1 + start*zspan->rectx+ oldx;
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- if (rectz1) rectz1+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz < *rectz) {
- if (rectz1) *rectz1= *rectz;
- *rectz= vergz;
- }
- else if (rectz1 && vergz < *rectz1)
- *rectz1= vergz;
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
-
- if (rectz1)
- rectz1+=zspan->rectx;
- }
- }
-}
-
-
-static int clipline(float v1[4], float v2[4]) /* return 0: do not draw */
-{
- float dz, dw, u1=0.0, u2=1.0;
- float dx, dy, v13;
-
- dz= v2[2]-v1[2];
- dw= v2[3]-v1[3];
-
- /* this 1.01 is for clipping x and y just a tinsy larger. that way it is
- * filled in with zbufwire correctly when rendering in parts. otherwise
- * you see line endings at edges... */
-
- if (cliptestf(-dz, -dw, v1[3], v1[2], &u1, &u2)) {
- if (cliptestf(dz, -dw, v1[3], -v1[2], &u1, &u2)) {
-
- dx= v2[0]-v1[0];
- dz= 1.01f*(v2[3]-v1[3]);
- v13= 1.01f*v1[3];
-
- if (cliptestf(-dx, -dz, v1[0], v13, &u1, &u2)) {
- if (cliptestf(dx, -dz, v13, -v1[0], &u1, &u2)) {
-
- dy= v2[1]-v1[1];
-
- if (cliptestf(-dy, -dz, v1[1], v13, &u1, &u2)) {
- if (cliptestf(dy, -dz, v13, -v1[1], &u1, &u2)) {
-
- if (u2<1.0f) {
- v2[0]= v1[0]+u2*dx;
- v2[1]= v1[1]+u2*dy;
- v2[2]= v1[2]+u2*dz;
- v2[3]= v1[3]+u2*dw;
- }
- if (u1>0.0f) {
- v1[0]= v1[0]+u1*dx;
- v1[1]= v1[1]+u1*dy;
- v1[2]= v1[2]+u1*dz;
- v1[3]= v1[3]+u1*dw;
- }
- return 1;
- }
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4])
-{
- float div;
-
- div= 1.0f/hoco[3];
- zco[0]= zspan->zmulx*(1.0f+hoco[0]*div) + zspan->zofsx;
- zco[1]= zspan->zmuly*(1.0f+hoco[1]*div) + zspan->zofsy;
- zco[2]= 0x7FFFFFFF *(hoco[2]*div);
-}
-
-void zbufclipwire(ZSpan *zspan, int obi, int zvlnr, int ec,
- const float ho1[4], const float ho2[4], const float ho3[4], const float ho4[4],
- const int c1, const int c2, const int c3, const int c4)
-{
- float vez[20];
- int and, or;
-
- /* edgecode: 1= draw */
- if (ec==0) return;
-
- if (ho4) {
- and= (c1 & c2 & c3 & c4);
- or= (c1 | c2 | c3 | c4);
- }
- else {
- and= (c1 & c2 & c3);
- or= (c1 | c2 | c3);
- }
-
- if (or) { /* not in the middle */
- if (and) { /* out completely */
- return;
- }
- else { /* clipping */
-
- if (ec & ME_V1V2) {
- copy_v4_v4(vez, ho1);
- copy_v4_v4(vez+4, ho2);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ec & ME_V2V3) {
- copy_v4_v4(vez, ho2);
- copy_v4_v4(vez+4, ho3);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ho4) {
- if (ec & ME_V3V4) {
- copy_v4_v4(vez, ho3);
- copy_v4_v4(vez+4, ho4);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ec & ME_V4V1) {
- copy_v4_v4(vez, ho4);
- copy_v4_v4(vez+4, ho1);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- }
- else {
- if (ec & ME_V3V1) {
- copy_v4_v4(vez, ho3);
- copy_v4_v4(vez+4, ho1);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- }
-
- return;
- }
- }
-
- hoco_to_zco(zspan, vez, ho1);
- hoco_to_zco(zspan, vez+4, ho2);
- hoco_to_zco(zspan, vez+8, ho3);
- if (ho4) {
- hoco_to_zco(zspan, vez+12, ho4);
-
- if (ec & ME_V3V4) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+8, vez+12);
- if (ec & ME_V4V1) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+12, vez);
- }
- else {
- if (ec & ME_V3V1) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+8, vez);
- }
-
- if (ec & ME_V1V2) zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- if (ec & ME_V2V3) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+4, vez+8);
-
-}
-
-void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, const float ho1[4], const float ho2[4])
-{
- float f1[4], f2[4];
- int c1, c2;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
-
- if (c1 | c2) { /* not in the middle */
- if (!(c1 & c2)) { /* not out completely */
- copy_v4_v4(f1, ho1);
- copy_v4_v4(f2, ho2);
-
- if (clipline(f1, f2)) {
- hoco_to_zco(zspan, f1, f1);
- hoco_to_zco(zspan, f2, f2);
- zspan->zbuflinefunc(zspan, obi, zvlnr, f1, f2);
- }
- }
- }
- else {
- hoco_to_zco(zspan, f1, ho1);
- hoco_to_zco(zspan, f2, ho2);
-
- zspan->zbuflinefunc(zspan, obi, zvlnr, f1, f2);
- }
-}
-
-/**
- * Fill the z buffer, but invert z order, and add the face index to
- * the corresponding face buffer.
- *
- * This is one of the z buffer fill functions called in zbufclip() and
- * zbufwireclip().
- *
- * \param v1 [4 floats, world coordinates] first vertex
- * \param v2 [4 floats, world coordinates] second vertex
- * \param v3 [4 floats, world coordinates] third vertex
- */
-
-/* WATCH IT: zbuffillGLinv4 and zbuffillGL4 are identical except for a 2 lines,
- * commented below */
-static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rectoofs, *ro;
- int *rectpofs, *rp;
- const int *rectmaskofs, *rm;
- int *rz, x, y;
- int sn1, sn2, rectx, *rectzofs, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- rectpofs= (zspan->rectp+rectx*my2);
- rectoofs= (zspan->recto+rectx*my2);
- rectmaskofs= (zspan->rectmask+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rp= rectpofs+sn1;
- ro= rectoofs+sn1;
- rm= rectmaskofs+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if ( intzverg > *rz || *rz==0x7FFFFFFF) { /* UNIQUE LINE: see comment above */
- if (!zspan->rectmask || intzverg > *rm) {
- *ro= obi; /* UNIQUE LINE: see comment above (order differs) */
- *rz= intzverg;
- *rp= zvlnr;
- }
- }
- zverg+= zxd;
- rz++;
- rp++;
- ro++;
- rm++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectpofs-= rectx;
- rectoofs-= rectx;
- rectmaskofs-= rectx;
- }
-}
-
-/* uses spanbuffers */
-
-/* WATCH IT: zbuffillGLinv4 and zbuffillGL4 are identical except for a 2 lines,
- * commented below */
-static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rectoofs, *ro;
- int *rectpofs, *rp;
- const int *rectmaskofs, *rm;
- int *rz, x, y;
- int sn1, sn2, rectx, *rectzofs, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- rectpofs= (zspan->rectp+rectx*my2);
- rectoofs= (zspan->recto+rectx*my2);
- rectmaskofs= (zspan->rectmask+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rp= rectpofs+sn1;
- ro= rectoofs+sn1;
- rm= rectmaskofs+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if (intzverg < *rz) { /* ONLY UNIQUE LINE: see comment above */
- if (!zspan->rectmask || intzverg > *rm) {
- *rz= intzverg;
- *rp= zvlnr;
- *ro= obi; /* UNIQUE LINE: see comment above (order differs) */
- }
- }
- zverg+= zxd;
- rz++;
- rp++;
- ro++;
- rm++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectpofs-= rectx;
- rectoofs-= rectx;
- rectmaskofs-= rectx;
- }
-}
-
-/**
- * Fill the z buffer. The face buffer is not operated on!
- *
- * This is one of the z buffer fill functions called in zbufclip() and
- * zbufwireclip().
- *
- * \param v1 [4 floats, world coordinates] first vertex
- * \param v2 [4 floats, world coordinates] second vertex
- * \param v3 [4 floats, world coordinates] third vertex
- */
-
-/* now: filling two Z values, the closest and 2nd closest */
-static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr),
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rz, *rz1, x, y;
- int sn1, sn2, rectx, *rectzofs, *rectzofs1= NULL, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- if (zspan->rectz1)
- rectzofs1= (zspan->rectz1+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rz1= rectzofs1+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- int zvergi = round_db_to_int_clamp(zverg);
-
- /* option: maintain two depth values, closest and 2nd closest */
- if (zvergi < *rz) {
- if (rectzofs1) *rz1= *rz;
- *rz= zvergi;
- }
- else if (rectzofs1 && zvergi < *rz1)
- *rz1= zvergi;
-
- zverg+= zxd;
-
- rz++;
- rz1++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- if (rectzofs1) rectzofs1-= rectx;
- }
-}
-
-/* 2d scanconvert for tria, calls func for each x, y coordinate and gives UV barycentrics */
-void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) )
-{
- float x0, y0, x1, y1, x2, y2, z0, z1, z2, z;
- float u, v, uxd, uyd, vxd, vyd, uy0, vy0, zxd, zyd, zy0, xx1;
- const float *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- z1= 1.0f; /* (u1 - u2) */
- z2= 0.0f; /* (u2 - u3) */
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + 1.0f;
- uxd= -(double)x0/(double)z0;
- uyd= -(double)y0/(double)z0;
- uy0= ((double)my2)*uyd + (double)xx1;
-
- z1= -1.0f; /* (v1 - v2) */
- z2= 1.0f; /* (v2 - v3) */
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0;
- vxd= -(double)x0/(double)z0;
- vyd= -(double)y0/(double)z0;
- vy0= ((double)my2)*vyd + (double)xx1;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- u= (double)sn1*uxd + uy0;
- v= (double)sn1*vxd + vy0;
- z= (double)sn1*zxd + zy0;
-
- for (x= sn1; x<=sn2; x++, u+=uxd, v+=vxd, z+=zxd)
- func(handle, x, y, u, v, z);
-
- uy0 -= uyd;
- vy0 -= vyd;
- zy0 -= zyd;
- }
-}
-
/* scanconvert for strand triangles, calls func for each x, y coordinate and gives UV barycentrics and z */
void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) )
@@ -1585,2154 +241,4 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
}
}
-
-
-/**
- * (clip pyramid)
- * Sets lambda: flag, and parametrize the clipping of vertices in
- * viewspace coordinates. lambda = -1 means no clipping, lambda in [0, 1] means a clipping.
- * Note: uses globals.
- * \param v1 start coordinate s
- * \param v2 target coordinate t
- * \param b2
- * \param b3
- * \param a index for coordinate (x, y, or z)
- */
-
-static void clippyra(float *lambda, float *v1, float *v2, int *b2, int *b3, int a, float clipcrop)
-{
- float da, dw, u1=0.0, u2=1.0;
- float v13;
-
- lambda[0]= -1.0;
- lambda[1]= -1.0;
-
- da= v2[a]-v1[a];
- /* prob; we clip slightly larger, osa renders add 2 pixels on edges, should become variable? */
- /* or better; increase r.winx/y size, but thats quite a complex one. do it later */
- if (a==2) {
- dw= (v2[3]-v1[3]);
- v13= v1[3];
- }
- else {
- dw= clipcrop*(v2[3]-v1[3]);
- v13= clipcrop*v1[3];
- }
- /* according the original article by Liang&Barsky, for clipping of
- * homogeneous coordinates with viewplane, the value of "0" is used instead of "-w" .
- * This differs from the other clipping cases (like left or top) and I considered
- * it to be not so 'homogenic'. But later it has proven to be an error,
- * who would have thought that of L&B!
- */
-
- if (cliptestf(-da, -dw, v13, v1[a], &u1, &u2)) {
- if (cliptestf(da, -dw, v13, -v1[a], &u1, &u2)) {
- *b3=1;
- if (u2<1.0f) {
- lambda[1]= u2;
- *b2=1;
- }
- else lambda[1]=1.0; /* u2 */
- if (u1>0.0f) {
- lambda[0] = u1;
- *b2 = 1;
- }
- else {
- lambda[0] = 0.0;
- }
- }
- }
-}
-
-/**
- * (make vertex pyramide clip)
- * Checks lambda and uses this to make decision about clipping the line
- * segment from v1 to v2. lambda is the factor by which the vector is
- * cut. ( calculate s + l * ( t - s )). The result is appended to the
- * vertex list of this face.
- *
- *
- * \param v1 start coordinate s
- * \param v2 target coordinate t
- * \param b1
- * \param b2
- * \param clve vertex vector.
- */
-
-static void makevertpyra(float *vez, float *lambda, float **trias, float *v1, float *v2, int *b1, int *clve)
-{
- float l1, l2, *adr;
-
- l1= lambda[0];
- l2= lambda[1];
-
- if (l1!= -1.0f) {
- if (l1!= 0.0f) {
- adr= vez+4*(*clve);
- trias[*b1]=adr;
- (*clve)++;
- adr[0]= v1[0]+l1*(v2[0]-v1[0]);
- adr[1]= v1[1]+l1*(v2[1]-v1[1]);
- adr[2]= v1[2]+l1*(v2[2]-v1[2]);
- adr[3]= v1[3]+l1*(v2[3]-v1[3]);
- }
- else trias[*b1]= v1;
-
- (*b1)++;
- }
- if (l2!= -1.0f) {
- if (l2!= 1.0f) {
- adr= vez+4*(*clve);
- trias[*b1]=adr;
- (*clve)++;
- adr[0]= v1[0]+l2*(v2[0]-v1[0]);
- adr[1]= v1[1]+l2*(v2[1]-v1[1]);
- adr[2]= v1[2]+l2*(v2[2]-v1[2]);
- adr[3]= v1[3]+l2*(v2[3]-v1[3]);
- (*b1)++;
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void projectverto(const float v1[3], float winmat[4][4], float adr[4])
-{
- /* calcs homogenic coord of vertex v1 */
- float x, y, z;
-
- x = v1[0];
- y = v1[1];
- z = v1[2];
- adr[0] = x * winmat[0][0] + z * winmat[2][0] + winmat[3][0];
- adr[1] = y * winmat[1][1] + z * winmat[2][1] + winmat[3][1];
- adr[2] = z * winmat[2][2] + winmat[3][2];
- adr[3] = z * winmat[2][3] + winmat[3][3];
-
- //printf("hoco %f %f %f %f\n", adr[0], adr[1], adr[2], adr[3]);
-}
-
-/* ------------------------------------------------------------------------- */
-
-void projectvert(const float v1[3], float winmat[4][4], float adr[4])
-{
- /* calcs homogenic coord of vertex v1 */
- float x, y, z;
-
- x = v1[0];
- y = v1[1];
- z = v1[2];
- adr[0] = x * winmat[0][0] + y * winmat[1][0] + z * winmat[2][0] + winmat[3][0];
- adr[1] = x * winmat[0][1] + y * winmat[1][1] + z * winmat[2][1] + winmat[3][1];
- adr[2] = x * winmat[0][2] + y * winmat[1][2] + z * winmat[2][2] + winmat[3][2];
- adr[3] = x * winmat[0][3] + y * winmat[1][3] + z * winmat[2][3] + winmat[3][3];
-}
-
-/* ------------------------------------------------------------------------- */
-
-#define ZBUF_PROJECT_CACHE_SIZE 256
-
-typedef struct ZbufProjectCache {
- int index, clip;
- float ho[4];
-} ZbufProjectCache;
-
-static void zbuf_project_cache_clear(ZbufProjectCache *cache, int size)
-{
- int i;
-
- if (size > ZBUF_PROJECT_CACHE_SIZE)
- size= ZBUF_PROJECT_CACHE_SIZE;
-
- memset(cache, 0, sizeof(ZbufProjectCache)*size);
- for (i=0; i<size; i++)
- cache[i].index= -1;
-}
-
-static int zbuf_shadow_project(ZbufProjectCache *cache, int index, float winmat[4][4], float *co, float *ho)
-{
- int cindex= index & 255;
-
- if (cache[cindex].index == index) {
- copy_v4_v4(ho, cache[cindex].ho);
- return cache[cindex].clip;
- }
- else {
- int clipflag;
- projectvert(co, winmat, ho);
- clipflag= testclip(ho);
-
- copy_v4_v4(cache[cindex].ho, ho);
- cache[cindex].clip= clipflag;
- cache[cindex].index= index;
-
- return clipflag;
- }
-}
-
-static void zbuffer_part_bounds(int winx, int winy, RenderPart *pa, float *bounds)
-{
- bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
- bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
- bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
- bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
-}
-
-static int zbuf_part_project(ZbufProjectCache *cache, int index, float winmat[4][4], float *bounds, float *co, float *ho)
-{
- float vec[3];
- int cindex= index & 255;
-
- if (cache[cindex].index == index) {
- copy_v4_v4(ho, cache[cindex].ho);
- return cache[cindex].clip;
- }
- else {
- float wco;
- int clipflag= 0;
- copy_v3_v3(vec, co);
- projectvert(co, winmat, ho);
-
- wco= ho[3];
- if (ho[0] < bounds[0]*wco) clipflag |= 1;
- else if (ho[0] > bounds[1]*wco) clipflag |= 2;
- if (ho[1] > bounds[3]*wco) clipflag |= 4;
- else if (ho[1] < bounds[2]*wco) clipflag |= 8;
-
- copy_v4_v4(cache[cindex].ho, ho);
- cache[cindex].clip= clipflag;
- cache[cindex].index= index;
-
- return clipflag;
- }
-}
-
-void zbuf_render_project(float winmat[4][4], const float co[3], float ho[4])
-{
- float vec[3];
-
- copy_v3_v3(vec, co);
- projectvert(vec, winmat, ho);
-}
-
-void zbuf_make_winmat(Render *re, float winmat[4][4])
-{
- if (re->r.mode & R_PANORAMA) {
- float panomat[4][4];
-
- unit_m4(panomat);
-
- panomat[0][0]= re->panoco;
- panomat[0][2]= re->panosi;
- panomat[2][0]= -re->panosi;
- panomat[2][2]= re->panoco;
-
- mul_m4_m4m4(winmat, re->winmat, panomat);
- }
- else
- copy_m4_m4(winmat, re->winmat);
-}
-
-/* do zbuffering and clip, f1 f2 f3 are hocos, c1 c2 c3 are clipping flags */
-
-void zbufclip(ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4],
- const int c1, const int c2, const int c3)
-{
- float *vlzp[32][3], lambda[3][2];
- float vez[400], *trias[40];
-
- if (c1 | c2 | c3) { /* not in middle */
- if (c1 & c2 & c3) { /* completely out */
- return;
- }
- else { /* clipping */
- int arg, v, b, clipflag[3], b1, b2, b3, c4, clve=3, clvlo, clvl=1;
- float *fp;
-
- vez[0]= f1[0]; vez[1]= f1[1]; vez[2]= f1[2]; vez[3]= f1[3];
- vez[4]= f2[0]; vez[5]= f2[1]; vez[6]= f2[2]; vez[7]= f2[3];
- vez[8]= f3[0]; vez[9]= f3[1]; vez[10]= f3[2];vez[11]= f3[3];
-
- vlzp[0][0]= vez;
- vlzp[0][1]= vez+4;
- vlzp[0][2]= vez+8;
-
- clipflag[0]= ( (c1 & 48) | (c2 & 48) | (c3 & 48) );
- if (clipflag[0]==0) { /* othwerwise it needs to be calculated again, after the first (z) clip */
- clipflag[1]= ( (c1 & 3) | (c2 & 3) | (c3 & 3) );
- clipflag[2]= ( (c1 & 12) | (c2 & 12) | (c3 & 12) );
- }
- else clipflag[1]=clipflag[2]= 0;
-
- for (b=0;b<3;b++) {
-
- if (clipflag[b]) {
-
- clvlo= clvl;
-
- for (v=0; v<clvlo; v++) {
-
- if (vlzp[v][0]!=NULL) { /* face is still there */
- b2= b3 =0; /* clip flags */
-
- if (b==0) arg= 2;
- else if (b==1) arg= 0;
- else arg= 1;
-
- clippyra(lambda[0], vlzp[v][0], vlzp[v][1], &b2, &b3, arg, zspan->clipcrop);
- clippyra(lambda[1], vlzp[v][1], vlzp[v][2], &b2, &b3, arg, zspan->clipcrop);
- clippyra(lambda[2], vlzp[v][2], vlzp[v][0], &b2, &b3, arg, zspan->clipcrop);
-
- if (b2==0 && b3==1) {
- /* completely 'in', but we copy because of last for () loop in this section */;
- vlzp[clvl][0]= vlzp[v][0];
- vlzp[clvl][1]= vlzp[v][1];
- vlzp[clvl][2]= vlzp[v][2];
- vlzp[v][0]= NULL;
- clvl++;
- }
- else if (b3==0) {
- vlzp[v][0]= NULL;
- /* completely 'out' */;
- }
- else {
- b1=0;
- makevertpyra(vez, lambda[0], trias, vlzp[v][0], vlzp[v][1], &b1, &clve);
- makevertpyra(vez, lambda[1], trias, vlzp[v][1], vlzp[v][2], &b1, &clve);
- makevertpyra(vez, lambda[2], trias, vlzp[v][2], vlzp[v][0], &b1, &clve);
-
- /* after front clip done: now set clip flags */
- if (b==0) {
- clipflag[1]= clipflag[2]= 0;
- f1= vez;
- for (b3=0; b3<clve; b3++) {
- c4= testclip(f1);
- clipflag[1] |= (c4 & 3);
- clipflag[2] |= (c4 & 12);
- f1+= 4;
- }
- }
-
- vlzp[v][0]= NULL;
- if (b1>2) {
- for (b3=3; b3<=b1; b3++) {
- vlzp[clvl][0]= trias[0];
- vlzp[clvl][1]= trias[b3-2];
- vlzp[clvl][2]= trias[b3-1];
- clvl++;
- }
- }
- }
- }
- }
- }
- }
-
- /* warning, clip overflow, this should never happen! */
- BLI_assert(!(clve > 38 || clvl > 31));
-
- /* perspective division */
- fp = vez;
- for (b = 0; b < clve; b++) {
- hoco_to_zco(zspan, fp, fp);
- fp += 4;
- }
- for (b = 1; b < clvl; b++) {
- if (vlzp[b][0]) {
- zspan->zbuffunc(zspan, obi, zvlnr, vlzp[b][0], vlzp[b][1], vlzp[b][2], NULL);
- }
- }
- return;
- }
- }
-
- /* perspective division: HCS to ZCS */
- hoco_to_zco(zspan, vez, f1);
- hoco_to_zco(zspan, vez+4, f2);
- hoco_to_zco(zspan, vez+8, f3);
- zspan->zbuffunc(zspan, obi, zvlnr, vez, vez+4, vez+8, NULL);
-}
-
-void zbufclip4(ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4], const float f4[4],
- const int c1, const int c2, const int c3, const int c4)
-{
- float vez[16];
-
- if (c1 | c2 | c3 | c4) { /* not in middle */
- if (c1 & c2 & c3 & c4) { /* completely out */
- return;
- }
- else { /* clipping */
- zbufclip(zspan, obi, zvlnr, f1, f2, f3, c1, c2, c3);
- zbufclip(zspan, obi, zvlnr, f1, f3, f4, c1, c3, c4);
- }
- return;
- }
-
- /* perspective division: HCS to ZCS */
- hoco_to_zco(zspan, vez, f1);
- hoco_to_zco(zspan, vez+4, f2);
- hoco_to_zco(zspan, vez+8, f3);
- hoco_to_zco(zspan, vez+12, f4);
-
- zspan->zbuffunc(zspan, obi, zvlnr, vez, vez+4, vez+8, vez+12);
-}
-
-/* ************** ZMASK ******************************** */
-
-#define EXTEND_PIXEL(a) if (temprectp[a]) { z += rectz[a]; tot++; } (void)0
-
-/* changes the zbuffer to be ready for z-masking: applies an extend-filter, and then clears */
-static void zmask_rect(int *rectz, int *rectp, int xs, int ys, int neg)
-{
- int len=0, x, y;
- int *temprectp;
- int row1, row2, row3, *curp, *curz;
-
- temprectp= MEM_dupallocN(rectp);
-
- /* extend: if pixel is not filled in, we check surrounding pixels and average z value */
-
- for (y=1; y<=ys; y++) {
- /* setup row indices */
- row1= (y-2)*xs;
- row2= row1 + xs;
- row3= row2 + xs;
- if (y==1)
- row1= row2;
- else if (y==ys)
- row3= row2;
-
- curp= rectp + (y-1)*xs;
- curz= rectz + (y-1)*xs;
-
- for (x=0; x<xs; x++, curp++, curz++) {
- if (curp[0]==0) {
- int tot= 0;
- float z= 0.0f;
-
- EXTEND_PIXEL(row1);
- EXTEND_PIXEL(row2);
- EXTEND_PIXEL(row3);
- EXTEND_PIXEL(row1 + 1);
- EXTEND_PIXEL(row3 + 1);
- if (x!=xs-1) {
- EXTEND_PIXEL(row1 + 2);
- EXTEND_PIXEL(row2 + 2);
- EXTEND_PIXEL(row3 + 2);
- }
- if (tot) {
- len++;
- curz[0]= (int)(z/(float)tot);
- curp[0]= -1; /* env */
- }
- }
-
- if (x!=0) {
- row1++; row2++; row3++;
- }
- }
- }
-
- MEM_freeN(temprectp);
-
- if (neg) {
- /* z values for negative are already correct */
- }
- else {
- /* clear not filled z values */
- for (len= xs*ys -1; len>=0; len--) {
- if (rectp[len]==0) {
- rectz[len] = -0x7FFFFFFF;
- rectp[len]= -1; /* env code */
- }
- }
- }
-}
-
-
-/* ***************** ZBUFFER MAIN ROUTINES **************** */
-
-void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart *, ZSpan *, int, void *), void *data)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspans[16], *zspan; /* 16 = RE_MAX_OSA */
- VlakRen *vlr= NULL;
- VertRen *v1, *v2, *v3, *v4;
- Material *ma = NULL;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- float obwinmat[4][4], winmat[4][4], bounds[4];
- float ho1[4], ho2[4], ho3[4], ho4[4]={0};
- unsigned int lay= (1 << 20) - 1, lay_zmask= 0;
- int i, v, zvlnr, zsample, samples, c1, c2, c3, c4=0;
- short nofill=0, env=0, wire=0, zmaskpass=0;
- const bool all_z = (rl->layflag & SCE_LAY_ALL_Z) && !(rl->layflag & SCE_LAY_ZMASK);
- const bool neg_zmask = (rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK);
-
- zbuf_make_winmat(&R, winmat);
-
- samples= (R.osa? R.osa: 1);
- samples= MIN2(4, samples-pa->sample);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- zbuffer_part_bounds(R.winx, R.winy, pa, bounds);
- zbuf_alloc_span(zspan, pa->rectx, pa->recty, R.clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan->zmulx= ((float)R.winx)/2.0f;
- zspan->zmuly= ((float)R.winy)/2.0f;
-
- if (R.osa) {
- zspan->zofsx= -pa->disprect.xmin - R.jit[pa->sample+zsample][0];
- zspan->zofsy= -pa->disprect.ymin - R.jit[pa->sample+zsample][1];
- }
- else if (R.i.curblur) {
- zspan->zofsx= -pa->disprect.xmin - R.mblur_jit[R.i.curblur-1][0];
- zspan->zofsy= -pa->disprect.ymin - R.mblur_jit[R.i.curblur-1][1];
- }
- else {
- zspan->zofsx= -pa->disprect.xmin;
- zspan->zofsy= -pa->disprect.ymin;
- }
- /* to center the sample position */
- zspan->zofsx -= 0.5f;
- zspan->zofsy -= 0.5f;
-
- /* the buffers */
- if (zsample == samples-1) {
- zspan->rectp= pa->rectp;
- zspan->recto= pa->recto;
-
- if (neg_zmask)
- zspan->rectz= pa->rectmask;
- else
- zspan->rectz= pa->rectz;
- }
- else {
- zspan->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- zspan->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- zspan->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- }
-
- fillrect(zspan->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
- fillrect(zspan->rectp, pa->rectx, pa->recty, 0);
- fillrect(zspan->recto, pa->rectx, pa->recty, 0);
- }
-
- /* in case zmask we fill Z for objects in lay_zmask first, then clear Z, and then do normal zbuffering */
- if (rl->layflag & SCE_LAY_ZMASK)
- zmaskpass= 1;
-
- for (; zmaskpass >=0; zmaskpass--) {
- ma= NULL;
-
- /* filling methods */
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (zmaskpass && neg_zmask)
- zspan->zbuffunc= zbuffillGLinv4;
- else
- zspan->zbuffunc= zbuffillGL4;
- zspan->zbuflinefunc= zbufline;
- }
-
- /* regular zbuffering loop, does all sample buffers */
- for (i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- /* continue happens in 2 different ways... zmaskpass only does lay_zmask stuff */
- if (zmaskpass) {
- if ((obi->lay & lay_zmask)==0)
- continue;
- }
- else if (!all_z && !(obi->lay & (lay|lay_zmask)))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- /* the cases: visible for render, only z values, zmask, nothing */
- if (obi->lay & lay) {
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- nofill= (ma->mode & MA_ONLYCAST) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP));
- env= (ma->mode & MA_ENV);
- wire= (ma->material_type == MA_TYPE_WIRE);
-
- for (zsample=0; zsample<samples; zsample++) {
- if (ma->mode & MA_ZINV || (zmaskpass && neg_zmask))
- zspans[zsample].zbuffunc= zbuffillGLinv4;
- else
- zspans[zsample].zbuffunc= zbuffillGL4;
- }
- }
- }
- else if (all_z || (obi->lay & lay_zmask)) {
- env= 1;
- nofill= 0;
- ma= NULL;
- }
- else {
- nofill= 1;
- ma= NULL; /* otherwise nofill can hang */
- }
-
- if (!(vlr->flag & R_HIDDEN) && nofill==0) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
-
- if (env) zvlnr= -1;
- else zvlnr= v+1;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
- if (v4)
- c4= testclip(ho4);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (wire) {
- if (v4)
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- else
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- /* strands allow to be filled in as quad */
- if (v4 && (vlr->flag & R_STRAND)) {
- zbufclip4(zspan, i, zvlnr, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else {
- zbufclip(zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4)
- zbufclip(zspan, i, (env)? zvlnr: zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- }
- }
- }
-
- /* clear all z to close value, so it works as mask for next passes (ztra+strand) */
- if (zmaskpass) {
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (neg_zmask) {
- zspan->rectmask= zspan->rectz;
- if (zsample == samples-1)
- zspan->rectz= pa->rectz;
- else
- zspan->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- fillrect(zspan->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
-
- zmask_rect(zspan->rectmask, zspan->rectp, pa->rectx, pa->recty, 1);
- }
- else
- zmask_rect(zspan->rectz, zspan->rectp, pa->rectx, pa->recty, 0);
- }
- }
- }
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (fillfunc)
- fillfunc(pa, zspan, pa->sample+zsample, data);
-
- if (zsample != samples-1) {
- MEM_freeN(zspan->rectz);
- MEM_freeN(zspan->rectp);
- MEM_freeN(zspan->recto);
- if (zspan->rectmask)
- MEM_freeN(zspan->rectmask);
- }
-
- zbuf_free_span(zspan);
- }
-}
-
-void zbuffer_shadow(Render *re, float winmat[4][4], LampRen *lar, int *rectz, int size, float jitx, float jity)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspan;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- Material *ma= NULL;
- StrandSegment sseg;
- StrandRen *strand= NULL;
- StrandVert *svert;
- StrandBound *sbound;
- float obwinmat[4][4], ho1[4], ho2[4], ho3[4], ho4[4];
- int a, b, c, i, c1, c2, c3, c4, ok=1, lay= -1;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- /* 1.0f for clipping in clippyra()... bad stuff actually */
- zbuf_alloc_span(&zspan, size, size, 1.0f);
- zspan.zmulx= ((float)size)/2.0f;
- zspan.zmuly= ((float)size)/2.0f;
- /* -0.5f to center the sample position */
- zspan.zofsx= jitx - 0.5f;
- zspan.zofsy= jity - 0.5f;
-
- /* the buffers */
- zspan.rectz= rectz;
- fillrect(rectz, size, size, 0x7FFFFFFE);
- if (lar->buftype==LA_SHADBUF_HALFWAY) {
- zspan.rectz1= MEM_mallocN(size*size*sizeof(int), "seconday z buffer");
- fillrect(zspan.rectz1, size, size, 0x7FFFFFFE);
- }
-
- /* filling methods */
- zspan.zbuflinefunc= zbufline_onlyZ;
- zspan.zbuffunc= zbuffillGL_onlyZ;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obr->ob==re->excludeob)
- continue;
- else if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, NULL, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- /* faces */
- for (a=0; a<obr->totvlak; a++) {
-
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (obi->lay & lay) && !(vlr->flag & R_HIDDEN)) {
- c1= zbuf_shadow_project(cache, vlr->v1->index, obwinmat, vlr->v1->co, ho1);
- c2= zbuf_shadow_project(cache, vlr->v2->index, obwinmat, vlr->v2->co, ho2);
- c3= zbuf_shadow_project(cache, vlr->v3->index, obwinmat, vlr->v3->co, ho3);
-
- if ((ma->material_type == MA_TYPE_WIRE) || (vlr->flag & R_STRAND)) {
- if (vlr->v4) {
- c4= zbuf_shadow_project(cache, vlr->v4->index, obwinmat, vlr->v4->co, ho4);
- zbufclipwire(&zspan, 0, a+1, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else
- zbufclipwire(&zspan, 0, a+1, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- if (vlr->v4) {
- c4= zbuf_shadow_project(cache, vlr->v4->index, obwinmat, vlr->v4->co, ho4);
- zbufclip4(&zspan, 0, 0, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else
- zbufclip(&zspan, 0, 0, ho1, ho2, ho3, c1, c2, c3);
- }
- }
-
- if ((a & 255)==255 && re->test_break(re->tbh))
- break;
- }
-
- /* strands */
- if (obr->strandbuf) {
- /* for each bounding box containing a number of strands */
- sbound= obr->strandbuf->bound;
- for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
- if (clip_render_object(sbound->boundbox, NULL, obwinmat))
- continue;
-
- /* for each strand in this bounding box */
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
-
- sseg.obi= obi;
- sseg.buffer= strand->buffer;
- sseg.sqadaptcos= sseg.buffer->adaptcos;
- sseg.sqadaptcos *= sseg.sqadaptcos;
- sseg.strand= strand;
- svert= strand->vert;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (sseg.buffer->ma!= ma) {
- ma= sseg.buffer->ma;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (sseg.buffer->lay & lay)) {
- zbuf_project_cache_clear(cache, strand->totvert);
-
- for (b=0; b<strand->totvert-1; b++, svert++) {
- sseg.v[0]= (b > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1;
-
- c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1);
- c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2);
- c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3);
- c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4);
-
- if (!(c1 & c2 & c3 & c4))
- render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg);
- }
- }
-
- if ((a & 255)==255 && re->test_break(re->tbh))
- break;
- }
- }
- }
-
- if (re->test_break(re->tbh))
- break;
- }
-
- /* merge buffers */
- if (lar->buftype==LA_SHADBUF_HALFWAY) {
- for (a=size*size -1; a>=0; a--)
- rectz[a]= (rectz[a]>>1) + (zspan.rectz1[a]>>1);
-
- MEM_freeN(zspan.rectz1);
- }
-
- zbuf_free_span(&zspan);
-}
-
-static void zbuffill_sss(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, z;
- float x0, y0, x1, y1, x2, y2, z0, z1, z2, xx1, *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- z= (double)sn1*zxd + zy0;
-
- for (x= sn1; x<=sn2; x++, z+=zxd)
- zspan->sss_func(zspan->sss_handle, obi, zvlnr, x, y, z);
-
- zy0 -= zyd;
- }
-}
-
-void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int, int))
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspan;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- VertRen *v1, *v2, *v3, *v4;
- Material *ma = NULL, *sss_ma = R.sss_mat;
- float obwinmat[4][4], winmat[4][4], bounds[4];
- float ho1[4], ho2[4], ho3[4], ho4[4]={0};
- int i, v, zvlnr, c1, c2, c3, c4=0;
- short nofill=0, env=0, wire=0;
-
- zbuf_make_winmat(&R, winmat);
- zbuffer_part_bounds(R.winx, R.winy, pa, bounds);
- zbuf_alloc_span(&zspan, pa->rectx, pa->recty, R.clipcrop);
-
- zspan.sss_handle= handle;
- zspan.sss_func= func;
-
- /* needed for transform from hoco to zbuffer co */
- zspan.zmulx= ((float)R.winx)/2.0f;
- zspan.zmuly= ((float)R.winy)/2.0f;
-
- /* -0.5f to center the sample position */
- zspan.zofsx= -pa->disprect.xmin - 0.5f;
- zspan.zofsy= -pa->disprect.ymin - 0.5f;
-
- /* filling methods */
- zspan.zbuffunc= zbuffill_sss;
-
- /* fill front and back zbuffer */
- if (pa->rectz) {
- fillrect(pa->recto, pa->rectx, pa->recty, 0);
- fillrect(pa->rectp, pa->rectx, pa->recty, 0);
- fillrect(pa->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
- }
- if (pa->rectbackz) {
- fillrect(pa->rectbacko, pa->rectx, pa->recty, 0);
- fillrect(pa->rectbackp, pa->rectx, pa->recty, 0);
- fillrect(pa->rectbackz, pa->rectx, pa->recty, -0x7FFFFFFF);
- }
-
- for (i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- if (material_in_material(vlr->mat, sss_ma)) {
- /* three cases, visible for render, only z values and nothing */
- if (obi->lay & lay) {
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- nofill= ma->mode & MA_ONLYCAST;
- env= (ma->mode & MA_ENV);
- wire= (ma->material_type == MA_TYPE_WIRE);
- }
- }
- else {
- nofill= 1;
- ma= NULL; /* otherwise nofill can hang */
- }
-
- if (nofill==0 && wire==0 && env==0) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
-
- zvlnr= v+1;
- zbufclip(&zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4) {
- c4= testclip(ho4);
- zbufclip(&zspan, i, zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- }
- }
-
- zbuf_free_span(&zspan);
-}
-
-/* ******************** ABUF ************************* */
-
-/**
- * Copy results from the solid face z buffering to the transparent
- * buffer.
- */
-static void copyto_abufz(RenderPart *pa, int *arectz, int *rectmask, int sample)
-{
- PixStr *ps;
- int x, y, *rza, *rma;
- intptr_t *rd;
-
- if (R.osa==0) {
- if (!pa->rectz)
- fillrect(arectz, pa->rectx, pa->recty, 0x7FFFFFFE);
- else
- memcpy(arectz, pa->rectz, sizeof(int)*pa->rectx*pa->recty);
-
- if (rectmask && pa->rectmask)
- memcpy(rectmask, pa->rectmask, sizeof(int)*pa->rectx*pa->recty);
-
- return;
- }
- else if (!pa->rectdaps) {
- fillrect(arectz, pa->rectx, pa->recty, 0x7FFFFFFE);
- return;
- }
-
- rza= arectz;
- rma= rectmask;
- rd= pa->rectdaps;
-
- sample= (1<<sample);
-
- for (y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++) {
-
- *rza= 0x7FFFFFFF;
- if (rectmask) *rma= 0x7FFFFFFF;
- if (*rd) {
- /* when there's a sky pixstruct, fill in sky-Z, otherwise solid Z */
- for (ps= (PixStr *)(*rd); ps; ps= ps->next) {
- if (sample & ps->mask) {
- *rza= ps->z;
- if (rectmask) *rma= ps->maskz;
- break;
- }
- }
- }
-
- rza++;
- rma++;
- rd++;
- }
- }
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/**
- * Do accumulation z buffering.
- */
-
-static int zbuffer_abuf(Render *re, RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay, int negzmask, float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float UNUSED(clipcrop), int shadow)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspans[16], *zspan; /* MAX_OSA */
- Material *ma=NULL;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr=NULL;
- VertRen *v1, *v2, *v3, *v4;
- float vec[3], hoco[4], mul, zval, fval;
- float obwinmat[4][4], bounds[4], ho1[4], ho2[4], ho3[4], ho4[4]={0};
- int i, v, zvlnr, c1, c2, c3, c4=0, dofill= 0;
- int zsample, polygon_offset;
-
- zbuffer_part_bounds(winx, winy, pa, bounds);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- zbuf_alloc_span(zspan, pa->rectx, pa->recty, re->clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan->zmulx= ((float)winx)/2.0f;
- zspan->zmuly= ((float)winy)/2.0f;
-
- /* the buffers */
- zspan->arectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectz");
- zspan->apixbuf= APixbuf;
- zspan->apsmbase= apsmbase;
-
- if (negzmask)
- zspan->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectmask");
-
- /* filling methods */
- zspan->zbuffunc= zbuffillAc4;
- zspan->zbuflinefunc= zbuflineAc;
-
- copyto_abufz(pa, zspan->arectz, zspan->rectmask, zsample); /* init zbuffer */
- zspan->mask= 1<<zsample;
-
- if (jit) {
- zspan->zofsx= -pa->disprect.xmin - jit[zsample][0];
- zspan->zofsy= -pa->disprect.ymin - jit[zsample][1];
- }
- else {
- zspan->zofsx= -pa->disprect.xmin;
- zspan->zofsy= -pa->disprect.ymin;
- }
-
- /* to center the sample position */
- zspan->zofsx -= 0.5f;
- zspan->zofsy -= 0.5f;
- }
-
- /* we use this to test if nothing was filled in */
- zvlnr= 0;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0)
- vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- if (shadow)
- dofill= (ma->mode2 & MA_CASTSHADOW) && (ma->mode & MA_SHADBUF);
- else
- dofill= (((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP)) && !(ma->mode & MA_ONLYCAST));
- }
-
- if (dofill) {
- if (!(vlr->flag & R_HIDDEN) && (obi->lay & lay)) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
- /* a little advantage for transp rendering (a z offset) */
- if (!shadow && ma->zoffs != 0.0f) {
- mul= 0x7FFFFFFF;
- zval= mul*(1.0f+ho1[2]/ho1[3]);
-
- copy_v3_v3(vec, v1->co);
- /* z is negative, otherwise its being clipped */
- vec[2]-= ma->zoffs;
- projectverto(vec, obwinmat, hoco);
- fval= mul*(1.0f+hoco[2]/hoco[3]);
-
- polygon_offset= (int)fabsf(zval - fval);
- }
- else polygon_offset= 0;
-
- zvlnr= v+1;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
- if (v4)
- c4= testclip(ho4);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
- zspan->polygon_offset= polygon_offset;
-
- if (ma->material_type == MA_TYPE_WIRE) {
- if (v4)
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- else
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- if (v4 && (vlr->flag & R_STRAND)) {
- zbufclip4(zspan, i, zvlnr, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else {
- zbufclip(zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4)
- zbufclip(zspan, i, zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- if ((v & 255)==255)
- if (re->test_break(re->tbh))
- break;
- }
- }
- }
-
- if (re->test_break(re->tbh)) break;
- }
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
- MEM_freeN(zspan->arectz);
- if (zspan->rectmask)
- MEM_freeN(zspan->rectmask);
- zbuf_free_span(zspan);
- }
-
- return zvlnr;
-}
-
-static int zbuffer_abuf_render(RenderPart *pa, APixstr *APixbuf, APixstrand *APixbufstrand, ListBase *apsmbase, RenderLayer *rl, StrandShadeCache *sscache)
-{
- float winmat[4][4], (*jit)[2];
- int samples, negzmask, doztra= 0;
-
- samples= (R.osa)? R.osa: 1;
- negzmask= ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK));
-
- if (R.osa)
- jit= R.jit;
- else if (R.i.curblur)
- jit= &R.mblur_jit[R.i.curblur-1];
- else
- jit= NULL;
-
- zbuf_make_winmat(&R, winmat);
-
- if (rl->layflag & SCE_LAY_ZTRA)
- doztra+= zbuffer_abuf(&R, pa, APixbuf, apsmbase, (1 << 20) - 1, negzmask, winmat, R.winx, R.winy, samples, jit, R.clipcrop, 0);
- if ((rl->layflag & SCE_LAY_STRAND) && APixbufstrand)
- doztra+= zbuffer_strands_abuf(&R, pa, APixbufstrand, apsmbase, (1 << 20) - 1, negzmask, winmat, R.winx, R.winy, samples, jit, R.clipcrop, 0, sscache);
-
- return doztra;
-}
-
-void zbuffer_abuf_shadow(Render *re, LampRen *lar, float winmat[4][4], APixstr *APixbuf, APixstrand *APixbufstrand, ListBase *apsmbase, int size, int samples, float (*jit)[2])
-{
- RenderPart pa;
- int lay= -1;
-
- if (lar->mode & LA_LAYER) lay= lar->lay;
-
- memset(&pa, 0, sizeof(RenderPart));
- pa.rectx= size;
- pa.recty= size;
- pa.disprect.xmin = 0;
- pa.disprect.ymin = 0;
- pa.disprect.xmax = size;
- pa.disprect.ymax = size;
-
- zbuffer_abuf(re, &pa, APixbuf, apsmbase, lay, 0, winmat, size, size, samples, jit, 1.0f, 1);
- if (APixbufstrand)
- zbuffer_strands_abuf(re, &pa, APixbufstrand, apsmbase, lay, 0, winmat, size, size, samples, jit, 1.0f, 1, NULL);
-}
-
-/* different rules for speed in transparent pass... */
-/* speed pointer NULL = sky, we clear */
-/* else if either alpha is full or no solid was filled in: copy speed */
-/* else fill in minimum speed */
-static void add_transp_speed(RenderLayer *rl, int offset, float speed[4], float alpha, intptr_t *rdrect)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- float *fp= rpass->rect + 4*offset;
-
- if (speed==NULL) {
- /* clear */
- if (fp[0]==PASS_VECTOR_MAX) fp[0]= 0.0f;
- if (fp[1]==PASS_VECTOR_MAX) fp[1]= 0.0f;
- if (fp[2]==PASS_VECTOR_MAX) fp[2]= 0.0f;
- if (fp[3]==PASS_VECTOR_MAX) fp[3]= 0.0f;
- }
- else if (rdrect==NULL || rdrect[offset]==0 || alpha>0.95f) {
- copy_v4_v4(fp, speed);
- }
- else {
- /* add minimum speed in pixel */
- if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0]= speed[0];
- fp[1]= speed[1];
- }
- if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2]= speed[2];
- fp[3]= speed[3];
- }
- }
- break;
- }
- }
-}
-
-static void add_transp_obindex(RenderLayer *rl, int offset, Object *ob)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- float *fp= rpass->rect + offset;
- *fp= (float)ob->index;
- break;
- }
- }
-}
-
-static void add_transp_material_index(RenderLayer *rl, int offset, Material *mat)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- float *fp= rpass->rect + offset;
- *fp= (float)mat->index;
- break;
- }
- }
-}
-
-/* ONLY OSA! merge all shaderesult samples to one */
-/* target should have been cleared */
-static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
-{
- RenderPass *rpass;
- float weight= 1.0f/((float)R.osa);
- int delta= sizeof(ShadeResult)/4;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col = NULL;
- int pixsize = 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- col = &shr->mist;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- col = &shr->z;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- ShadeResult *shr_t = shr+1;
- float *fp = shr->winspeed; /* was initialized */
- int samp;
-
- /* add minimum speed in pixel */
- for (samp = 1; samp<R.osa; samp++, shr_t++) {
-
- if (shr_t->combined[3] > 0.0f) {
- const float *speed = shr_t->winspeed;
-
- if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0] = speed[0];
- fp[1] = speed[1];
- }
- if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2] = speed[2];
- fp[3] = speed[3];
- }
- }
- }
- }
-
- if (col) {
- const float *fp= col+delta;
- int samp;
-
- for (samp= 1; samp<R.osa; samp++, fp+=delta) {
- col[0]+= fp[0];
- if (pixsize>1) {
- col[1]+= fp[1];
- col[2]+= fp[2];
- if (pixsize==4) col[3]+= fp[3];
- }
- }
- col[0]*= weight;
- if (pixsize>1) {
- col[1]*= weight;
- col[2]*= weight;
- if (pixsize==4) col[3]*= weight;
- }
- }
- }
-
-}
-
-static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *fp, *col= NULL;
- int pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- if (shr->z < *fp)
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- fp = rpass->rect + 4*offset;
- addAlphaOverFloat(fp, shr->col);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- col = &shr->mist;
- pixsize = 1;
- }
-
- if (col) {
- fp= rpass->rect + pixsize*offset;
- fp[0]= col[0] + (1.0f-alpha)*fp[0];
- if (pixsize==3) {
- fp[1]= col[1] + (1.0f-alpha)*fp[1];
- fp[2]= col[2] + (1.0f-alpha)*fp[2];
- }
- }
- }
-}
-
-typedef struct ZTranspRow {
- int obi;
- int z;
- int p;
- int mask;
- int segment;
- float u, v;
-} ZTranspRow;
-
-static int vergzvlak(const void *a1, const void *a2)
-{
- const ZTranspRow *r1 = a1, *r2 = a2;
-
- if (r1->z < r2->z) return 1;
- else if (r1->z > r2->z) return -1;
- return 0;
-}
-
-static void shade_strand_samples(StrandShadeCache *cache, ShadeSample *ssamp, int UNUSED(x), int UNUSED(y), ZTranspRow *row, int addpassflag)
-{
- StrandSegment sseg;
- StrandVert *svert;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
-
- obi= R.objectinstance + row->obi;
- obr= obi->obr;
-
- sseg.obi= obi;
- sseg.strand= RE_findOrAddStrand(obr, row->p-1);
- sseg.buffer= sseg.strand->buffer;
-
- svert= sseg.strand->vert + row->segment;
- sseg.v[0]= (row->segment > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (row->segment < sseg.strand->totvert-2)? svert+2: svert+1;
-
- ssamp->tot= 1;
- strand_shade_segment(&R, cache, &sseg, ssamp, row->v, row->u, addpassflag);
- ssamp->shi[0].mask= row->mask;
-}
-
-static void unref_strand_samples(StrandShadeCache *cache, ZTranspRow *row, int totface)
-{
- StrandVert *svert;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- StrandRen *strand;
-
- /* remove references to samples that are not being rendered, but we still
- * need to remove them so that the reference count of strand vertex shade
- * samples correctly drops to zero */
- while (totface > 0) {
- totface--;
-
- if (row[totface].segment != -1) {
- obi= R.objectinstance + row[totface].obi;
- obr= obi->obr;
- strand= RE_findOrAddStrand(obr, row[totface].p-1);
- svert= strand->vert + row[totface].segment;
-
- strand_shade_unref(cache, obi, svert);
- strand_shade_unref(cache, obi, svert+1);
- }
- }
-}
-
-static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int obi, int facenr, int curmask)
-{
- ShadeInput *shi= ssamp->shi;
- float xs, ys;
-
- ssamp->tot= 0;
-
- shade_input_set_triangle(shi, obi, facenr, 1);
-
- /* officially should always be true... we have no sky info */
- if (shi->vlr) {
-
- /* full osa is only set for OSA renders */
- if (shi->vlr->flag & R_FULL_OSA) {
- short shi_inc= 0, samp;
-
- for (samp=0; samp<R.osa; samp++) {
- if (curmask & (1<<samp)) {
- xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures (xs, ys) are inside pixel */
- ys= (float)y + R.jit[samp][1] + 0.5f;
-
- if (shi_inc) {
- shade_input_copy_triangle(shi+1, shi);
- shi++;
- }
- shi->mask= (1<<samp);
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)z);
- shade_input_set_uv(shi);
- if (shi_inc==0)
- shade_input_set_normals(shi);
- else /* XXX shi->flippednor messes up otherwise */
- shade_input_set_vertex_normals(shi);
-
- shi_inc= 1;
- }
- }
- }
- else {
- if (R.osa) {
- short b= R.samples->centmask[curmask];
- xs= (float)x + R.samples->centLut[b & 15] + 0.5f;
- ys= (float)y + R.samples->centLut[b>>4] + 0.5f;
- }
- else if (R.i.curblur) {
- xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f;
- ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f;
- }
- else {
- xs= (float)x + 0.5f;
- ys= (float)y + 0.5f;
- }
- shi->mask= curmask;
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)z);
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
- }
-
- /* total sample amount, shi->sample is static set in initialize */
- ssamp->tot= shi->sample+1;
- }
-}
-
-static int shade_tra_samples(ShadeSample *ssamp, StrandShadeCache *cache, int x, int y, ZTranspRow *row, int addpassflag)
-{
- if (row->segment != -1) {
- shade_strand_samples(cache, ssamp, x, y, row, addpassflag);
- return 1;
- }
-
- shade_tra_samples_fill(ssamp, x, y, row->z, row->obi, row->p, row->mask);
-
- if (ssamp->tot) {
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
- int samp;
-
- /* if AO? */
- shade_samples_do_AO(ssamp);
-
- /* if shade (all shadepinputs have same passflag) */
- if (shi->passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB|SCE_PASS_INDEXMA)) {
- for (samp=0; samp<ssamp->tot; samp++, shi++, shr++) {
- shade_input_set_shade_texco(shi);
- shade_input_do_shade(shi, shr);
-
- /* include lamphalos for ztra, since halo layer was added already */
- if (R.flag & R_LAMPHALO)
- if (shi->layflag & SCE_LAY_HALO)
- renderspothalo(shi, shr->combined, shr->combined[3]);
- }
- }
- else if (shi->passflag & SCE_PASS_Z) {
- for (samp=0; samp<ssamp->tot; samp++, shi++, shr++)
- shr->z= -shi->co[2];
- }
-
- return 1;
- }
- return 0;
-}
-
-static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
-{
- int a, sample, osa = (R.osa? R.osa: 1), retval = osa;
-
- for (a=0; a < osa; a++, samp_shr++) {
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
-
- for (sample=0; sample<ssamp->tot; sample++, shi++, shr++) {
-
- if (shi->mask & (1<<a)) {
- float fac= (1.0f - samp_shr->combined[3])*shr->combined[3];
-
- addAlphaUnderFloat(samp_shr->combined, shr->combined);
-
- samp_shr->z = min_ff(samp_shr->z, shr->z);
-
- if (addpassflag & SCE_PASS_VECTOR) {
- copy_v4_v4(samp_shr->winspeed, shr->winspeed);
- }
- /* optim... */
- if (addpassflag & ~(SCE_PASS_VECTOR)) {
-
- if (addpassflag & SCE_PASS_RGBA)
- addAlphaUnderFloat(samp_shr->col, shr->col);
-
- if (addpassflag & SCE_PASS_NORMAL)
- madd_v3_v3fl(samp_shr->nor, shr->nor, fac);
-
- if (addpassflag & SCE_PASS_EMIT)
- madd_v3_v3fl(samp_shr->emit, shr->emit, fac);
-
- if (addpassflag & SCE_PASS_DIFFUSE)
- madd_v3_v3fl(samp_shr->diff, shr->diff, fac);
-
- if (addpassflag & SCE_PASS_SPEC)
- madd_v3_v3fl(samp_shr->spec, shr->spec, fac);
-
- if (addpassflag & SCE_PASS_SHADOW)
- madd_v3_v3fl(samp_shr->shad, shr->shad, fac);
-
- if (addpassflag & SCE_PASS_AO)
- madd_v3_v3fl(samp_shr->ao, shr->ao, fac);
-
- if (addpassflag & SCE_PASS_ENVIRONMENT)
- madd_v3_v3fl(samp_shr->env, shr->env, fac);
-
- if (addpassflag & SCE_PASS_INDIRECT)
- madd_v3_v3fl(samp_shr->indirect, shr->indirect, fac);
-
- if (addpassflag & SCE_PASS_REFLECT)
- madd_v3_v3fl(samp_shr->refl, shr->refl, fac);
-
- if (addpassflag & SCE_PASS_REFRACT)
- madd_v3_v3fl(samp_shr->refr, shr->refr, fac);
-
- if (addpassflag & SCE_PASS_MIST)
- samp_shr->mist= samp_shr->mist+fac*shr->mist;
-
- }
- }
- }
-
- if (samp_shr->combined[3]>0.999f) retval--;
- }
- return retval;
-}
-
-static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf)
-{
- /* speed vector exception... if solid render was done, sky pixels are set to zero already */
- /* for all pixels with alpha zero, we re-initialize speed again then */
- float *fp, *col;
- int a;
-
- fp = RE_RenderLayerGetPass(rl, RE_PASSNAME_VECTOR, R.viewname);
- if (fp==NULL) return;
- col= rectf+3;
-
- for (a= 4*pa->rectx*pa->recty -4; a>=0; a-=4) {
- if (col[a]==0.0f) {
- fp[a]= PASS_VECTOR_MAX;
- fp[a+1]= PASS_VECTOR_MAX;
- fp[a+2]= PASS_VECTOR_MAX;
- fp[a+3]= PASS_VECTOR_MAX;
- }
- }
-}
-
-#define MAX_ZROW 2000
-
-/* main render call to do the z-transparent layer */
-/* returns a mask, only if a) transp rendered and b) solid was rendered */
-unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass, ListBase *UNUSED(psmlist))
-{
- RenderResult *rr= pa->result;
- ShadeSample ssamp;
- APixstr *APixbuf; /* Zbuffer: linked list of face samples */
- APixstrand *APixbufstrand = NULL;
- APixstr *ap, *aprect, *apn;
- APixstrand *apstrand, *aprectstrand, *apnstrand;
- ListBase apsmbase={NULL, NULL};
- ShadeResult samp_shr[16]; /* MAX_OSA */
- ZTranspRow zrow[MAX_ZROW];
- StrandShadeCache *sscache= NULL;
- RenderLayer *rlpp[RE_MAX_OSA];
- float sampalpha, alpha, *passrect= pass;
- intptr_t *rdrect;
- int x, y, crop=0, a, b, totface, totfullsample, totsample, doztra;
- int addpassflag, offs= 0, od, osa = (R.osa? R.osa: 1);
- unsigned short *ztramask= NULL, filled;
-
- /* looks nicer for calling code */
- if (R.test_break(R.tbh))
- return NULL;
-
- if (R.osa > 16) { /* MAX_OSA */
- printf("zbuffer_transp_shade: osa too large\n");
- G.is_break = true;
- return NULL;
- }
-
- APixbuf= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf");
- if (R.totstrand && (rl->layflag & SCE_LAY_STRAND)) {
- APixbufstrand= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstrand), "APixbufstrand");
- sscache= strand_shade_cache_create();
- }
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
- addpassflag= rl->passflag & ~(SCE_PASS_COMBINED);
-
- if (R.osa)
- sampalpha= 1.0f/(float)R.osa;
- else
- sampalpha= 1.0f;
-
- /* fill the Apixbuf */
- doztra= zbuffer_abuf_render(pa, APixbuf, APixbufstrand, &apsmbase, rl, sscache);
-
- if (doztra == 0) {
- /* nothing filled in */
- MEM_freeN(APixbuf);
- if (APixbufstrand)
- MEM_freeN(APixbufstrand);
- if (sscache)
- strand_shade_cache_free(sscache);
- freepsA(&apsmbase);
- return NULL;
- }
-
- aprect= APixbuf;
- aprectstrand= APixbufstrand;
- rdrect= pa->rectdaps;
-
- /* needed for correct zbuf/index pass */
- totfullsample= get_sample_layers(pa, rl, rlpp);
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, APixbuf);
-
- /* masks, to have correct alpha combine */
- if (R.osa && (rl->layflag & SCE_LAY_SOLID) && pa->fullresult.first==NULL)
- ztramask= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "ztramask");
-
- /* zero alpha pixels get speed vector max again */
- if (addpassflag & SCE_PASS_VECTOR)
- if (rl->layflag & SCE_LAY_SOLID) {
- float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */
- }
- /* filtered render, for now we assume only 1 filter size */
- if (pa->crop) {
- crop= 1;
- offs= pa->rectx + 1;
- passrect+= 4*offs;
- aprect+= offs;
- aprectstrand+= offs;
- }
-
- /* init scanline updates */
- rr->renrect.ymin = 0;
- rr->renrect.ymax = -pa->crop;
- rr->renlay= rl;
-
- /* render the tile */
- for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- pass= passrect;
- ap= aprect;
- apstrand= aprectstrand;
- od= offs;
-
- if (R.test_break(R.tbh))
- break;
-
- for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, apstrand++, pass+=4, od++) {
-
- if (ap->p[0]==0 && (!APixbufstrand || apstrand->p[0]==0)) {
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, NULL, 0.0f, rdrect);
- }
- else {
- /* sort in z */
- totface= 0;
- apn= ap;
- while (apn) {
- for (a=0; a<4; a++) {
- if (apn->p[a]) {
- zrow[totface].obi= apn->obi[a];
- zrow[totface].z= apn->z[a];
- zrow[totface].p= apn->p[a];
- zrow[totface].mask= apn->mask[a];
- zrow[totface].segment= -1;
- totface++;
- if (totface>=MAX_ZROW) totface= MAX_ZROW-1;
- }
- else break;
- }
- apn= apn->next;
- }
-
- apnstrand= (APixbufstrand)? apstrand: NULL;
- while (apnstrand) {
- for (a=0; a<4; a++) {
- if (apnstrand->p[a]) {
- zrow[totface].obi= apnstrand->obi[a];
- zrow[totface].z= apnstrand->z[a];
- zrow[totface].p= apnstrand->p[a];
- zrow[totface].mask= apnstrand->mask[a];
- zrow[totface].segment= apnstrand->seg[a];
-
- if (R.osa) {
- totsample= 0;
- for (b=0; b<R.osa; b++)
- if (zrow[totface].mask & (1<<b))
- totsample++;
- }
- else
- totsample= 1;
-
- zrow[totface].u= apnstrand->u[a]/totsample;
- zrow[totface].v= apnstrand->v[a]/totsample;
- totface++;
- if (totface>=MAX_ZROW) totface= MAX_ZROW-1;
- }
- }
- apnstrand= apnstrand->next;
- }
-
- if (totface==2) {
- if (zrow[0].z < zrow[1].z) {
- SWAP(ZTranspRow, zrow[0], zrow[1]);
- }
-
- }
- else if (totface>2) {
- qsort(zrow, totface, sizeof(ZTranspRow), vergzvlak);
- }
-
- /* front face does index pass for transparent, no AA or filters, but yes FSA */
- if (addpassflag & SCE_PASS_INDEXOB) {
- ObjectRen *obr= R.objectinstance[zrow[totface-1].obi].obr;
- if (obr->ob) {
- for (a= 0; a<totfullsample; a++)
- add_transp_obindex(rlpp[a], od, obr->ob);
- }
- }
- if (addpassflag & SCE_PASS_INDEXMA) {
- ObjectRen *obr = R.objectinstance[zrow[totface-1].obi].obr;
- int p = zrow[totface-1].p;
- Material *mat = NULL;
-
- if (zrow[totface-1].segment == -1) {
- int facenr = (p - 1) & RE_QUAD_MASK;
- VlakRen *vlr = NULL;
-
- if (facenr >= 0 && facenr < obr->totvlak)
- vlr = RE_findOrAddVlak(obr, facenr);
-
- if (vlr)
- mat = vlr->mat;
- }
- else {
- StrandRen *strand = RE_findOrAddStrand(obr, p - 1);
-
- if (strand)
- mat = strand->buffer->ma;
- }
-
- if (mat) {
- for (a= 0; a<totfullsample; a++)
- add_transp_material_index(rlpp[a], od, mat);
- }
- }
-
- /* for each mask-sample we alpha-under colors. then in end it's added using filter */
- memset(samp_shr, 0, sizeof(ShadeResult)*osa);
- for (a=0; a<osa; a++) {
- samp_shr[a].z= 10e10f;
- if (addpassflag & SCE_PASS_VECTOR) {
- samp_shr[a].winspeed[0]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[1]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[2]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[3]= PASS_VECTOR_MAX;
- }
- }
-
- if (R.osa==0) {
- while (totface>0) {
- totface--;
-
- if (shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) {
- filled= addtosamp_shr(samp_shr, &ssamp, addpassflag);
- addAlphaUnderFloat(pass, ssamp.shr[0].combined);
-
- if (filled == 0) {
- if (sscache)
- unref_strand_samples(sscache, zrow, totface);
- break;
- }
- }
- }
-
- alpha= samp_shr->combined[3];
- if (alpha!=0.0f) {
- add_transp_passes(rl, od, samp_shr, alpha);
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr->winspeed, alpha, rdrect);
- }
- }
- else {
- short *sp= (short *)(ztramask+od);
-
- while (totface>0) {
- totface--;
-
- if (shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) {
- filled= addtosamp_shr(samp_shr, &ssamp, addpassflag);
-
- if (ztramask)
- *sp |= zrow[totface].mask;
- if (filled==0) {
- if (sscache)
- unref_strand_samples(sscache, zrow, totface);
- break;
- }
- }
- }
-
- /* multisample buffers or filtered mask filling? */
- if (pa->fullresult.first) {
- for (a=0; a<R.osa; a++) {
- alpha= samp_shr[a].combined[3];
- if (alpha != 0.0f) {
- RenderLayer *rl_other = ssamp.rlpp[a];
-
- float *rect = RE_RenderLayerGetPass(rl_other , RE_PASSNAME_COMBINED, R.viewname);
- addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
-
- add_transp_passes(rl_other , od, &samp_shr[a], alpha);
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl_other , od, samp_shr[a].winspeed, alpha, rdrect);
- }
- }
- }
- else {
- alpha= 0.0f;
-
- /* note; cannot use pass[3] for alpha due to filtermask */
- for (a=0; a<R.osa; a++) {
- add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx);
- alpha+= samp_shr[a].combined[3];
- }
-
- if (addpassflag) {
- alpha*= sampalpha;
-
- /* merge all in one, and then add */
- merge_transp_passes(rl, samp_shr);
- add_transp_passes(rl, od, samp_shr, alpha);
-
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr[0].winspeed, alpha, rdrect);
- }
- }
- }
- }
- }
-
- aprect+= pa->rectx;
- aprectstrand+= pa->rectx;
- passrect+= 4*pa->rectx;
- offs+= pa->rectx;
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
-
- MEM_freeN(APixbuf);
- if (APixbufstrand)
- MEM_freeN(APixbufstrand);
- if (sscache)
- strand_shade_cache_free(sscache);
- freepsA(&apsmbase);
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
-
- return ztramask;
-}
-
-
/* end of zbuf.c */